1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * SBI initialilization and all extension implementation. 4 * 5 * Copyright (c) 2020 Western Digital Corporation or its affiliates. 6 */ 7 8 #include <linux/bits.h> 9 #include <linux/init.h> 10 #include <linux/mm.h> 11 #include <linux/pm.h> 12 #include <linux/reboot.h> 13 #include <asm/sbi.h> 14 #include <asm/smp.h> 15 #include <asm/tlbflush.h> 16 17 /* default SBI version is 0.1 */ 18 unsigned long sbi_spec_version __ro_after_init = SBI_SPEC_VERSION_DEFAULT; 19 EXPORT_SYMBOL(sbi_spec_version); 20 21 static void (*__sbi_set_timer)(uint64_t stime) __ro_after_init; 22 static void (*__sbi_send_ipi)(unsigned int cpu) __ro_after_init; 23 static int (*__sbi_rfence)(int fid, const struct cpumask *cpu_mask, 24 unsigned long start, unsigned long size, 25 unsigned long arg4, unsigned long arg5) __ro_after_init; 26 27 #ifdef CONFIG_RISCV_SBI_V01 28 static unsigned long __sbi_v01_cpumask_to_hartmask(const struct cpumask *cpu_mask) 29 { 30 unsigned long cpuid, hartid; 31 unsigned long hmask = 0; 32 33 /* 34 * There is no maximum hartid concept in RISC-V and NR_CPUS must not be 35 * associated with hartid. As SBI v0.1 is only kept for backward compatibility 36 * and will be removed in the future, there is no point in supporting hartid 37 * greater than BITS_PER_LONG (32 for RV32 and 64 for RV64). Ideally, SBI v0.2 38 * should be used for platforms with hartid greater than BITS_PER_LONG. 39 */ 40 for_each_cpu(cpuid, cpu_mask) { 41 hartid = cpuid_to_hartid_map(cpuid); 42 if (hartid >= BITS_PER_LONG) { 43 pr_warn("Unable to send any request to hartid > BITS_PER_LONG for SBI v0.1\n"); 44 break; 45 } 46 hmask |= BIT(hartid); 47 } 48 49 return hmask; 50 } 51 52 /** 53 * sbi_console_putchar() - Writes given character to the console device. 54 * @ch: The data to be written to the console. 55 * 56 * Return: None 57 */ 58 void sbi_console_putchar(int ch) 59 { 60 sbi_ecall(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, ch, 0, 0, 0, 0, 0); 61 } 62 EXPORT_SYMBOL(sbi_console_putchar); 63 64 /** 65 * sbi_console_getchar() - Reads a byte from console device. 66 * 67 * Returns the value read from console. 68 */ 69 int sbi_console_getchar(void) 70 { 71 struct sbiret ret; 72 73 ret = sbi_ecall(SBI_EXT_0_1_CONSOLE_GETCHAR, 0, 0, 0, 0, 0, 0, 0); 74 75 return ret.error; 76 } 77 EXPORT_SYMBOL(sbi_console_getchar); 78 79 /** 80 * sbi_shutdown() - Remove all the harts from executing supervisor code. 81 * 82 * Return: None 83 */ 84 void sbi_shutdown(void) 85 { 86 sbi_ecall(SBI_EXT_0_1_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0); 87 } 88 EXPORT_SYMBOL(sbi_shutdown); 89 90 /** 91 * __sbi_set_timer_v01() - Program the timer for next timer event. 92 * @stime_value: The value after which next timer event should fire. 93 * 94 * Return: None 95 */ 96 static void __sbi_set_timer_v01(uint64_t stime_value) 97 { 98 #if __riscv_xlen == 32 99 sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value, 100 stime_value >> 32, 0, 0, 0, 0); 101 #else 102 sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value, 0, 0, 0, 0, 0); 103 #endif 104 } 105 106 static void __sbi_send_ipi_v01(unsigned int cpu) 107 { 108 unsigned long hart_mask = 109 __sbi_v01_cpumask_to_hartmask(cpumask_of(cpu)); 110 sbi_ecall(SBI_EXT_0_1_SEND_IPI, 0, (unsigned long)(&hart_mask), 111 0, 0, 0, 0, 0); 112 } 113 114 static int __sbi_rfence_v01(int fid, const struct cpumask *cpu_mask, 115 unsigned long start, unsigned long size, 116 unsigned long arg4, unsigned long arg5) 117 { 118 int result = 0; 119 unsigned long hart_mask; 120 121 if (!cpu_mask || cpumask_empty(cpu_mask)) 122 cpu_mask = cpu_online_mask; 123 hart_mask = __sbi_v01_cpumask_to_hartmask(cpu_mask); 124 125 /* v0.2 function IDs are equivalent to v0.1 extension IDs */ 126 switch (fid) { 127 case SBI_EXT_RFENCE_REMOTE_FENCE_I: 128 sbi_ecall(SBI_EXT_0_1_REMOTE_FENCE_I, 0, 129 (unsigned long)&hart_mask, 0, 0, 0, 0, 0); 130 break; 131 case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA: 132 sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA, 0, 133 (unsigned long)&hart_mask, start, size, 134 0, 0, 0); 135 break; 136 case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID: 137 sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID, 0, 138 (unsigned long)&hart_mask, start, size, 139 arg4, 0, 0); 140 break; 141 default: 142 pr_err("SBI call [%d]not supported in SBI v0.1\n", fid); 143 result = -EINVAL; 144 } 145 146 return result; 147 } 148 149 static void sbi_set_power_off(void) 150 { 151 pm_power_off = sbi_shutdown; 152 } 153 #else 154 static void __sbi_set_timer_v01(uint64_t stime_value) 155 { 156 pr_warn("Timer extension is not available in SBI v%lu.%lu\n", 157 sbi_major_version(), sbi_minor_version()); 158 } 159 160 static void __sbi_send_ipi_v01(unsigned int cpu) 161 { 162 pr_warn("IPI extension is not available in SBI v%lu.%lu\n", 163 sbi_major_version(), sbi_minor_version()); 164 } 165 166 static int __sbi_rfence_v01(int fid, const struct cpumask *cpu_mask, 167 unsigned long start, unsigned long size, 168 unsigned long arg4, unsigned long arg5) 169 { 170 pr_warn("remote fence extension is not available in SBI v%lu.%lu\n", 171 sbi_major_version(), sbi_minor_version()); 172 173 return 0; 174 } 175 176 static void sbi_set_power_off(void) {} 177 #endif /* CONFIG_RISCV_SBI_V01 */ 178 179 static void __sbi_set_timer_v02(uint64_t stime_value) 180 { 181 #if __riscv_xlen == 32 182 sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 183 stime_value >> 32, 0, 0, 0, 0); 184 #else 185 sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 186 0, 0, 0, 0); 187 #endif 188 } 189 190 static void __sbi_send_ipi_v02(unsigned int cpu) 191 { 192 int result; 193 struct sbiret ret = {0}; 194 195 ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI, 196 1UL, cpuid_to_hartid_map(cpu), 0, 0, 0, 0); 197 if (ret.error) { 198 result = sbi_err_map_linux_errno(ret.error); 199 pr_err("%s: hbase = [%lu] failed (error [%d])\n", 200 __func__, cpuid_to_hartid_map(cpu), result); 201 } 202 } 203 204 static int __sbi_rfence_v02_call(unsigned long fid, unsigned long hmask, 205 unsigned long hbase, unsigned long start, 206 unsigned long size, unsigned long arg4, 207 unsigned long arg5) 208 { 209 struct sbiret ret = {0}; 210 int ext = SBI_EXT_RFENCE; 211 int result = 0; 212 213 switch (fid) { 214 case SBI_EXT_RFENCE_REMOTE_FENCE_I: 215 ret = sbi_ecall(ext, fid, hmask, hbase, 0, 0, 0, 0); 216 break; 217 case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA: 218 ret = sbi_ecall(ext, fid, hmask, hbase, start, 219 size, 0, 0); 220 break; 221 case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID: 222 ret = sbi_ecall(ext, fid, hmask, hbase, start, 223 size, arg4, 0); 224 break; 225 226 case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA: 227 ret = sbi_ecall(ext, fid, hmask, hbase, start, 228 size, 0, 0); 229 break; 230 case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID: 231 ret = sbi_ecall(ext, fid, hmask, hbase, start, 232 size, arg4, 0); 233 break; 234 case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA: 235 ret = sbi_ecall(ext, fid, hmask, hbase, start, 236 size, 0, 0); 237 break; 238 case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID: 239 ret = sbi_ecall(ext, fid, hmask, hbase, start, 240 size, arg4, 0); 241 break; 242 default: 243 pr_err("unknown function ID [%lu] for SBI extension [%d]\n", 244 fid, ext); 245 result = -EINVAL; 246 } 247 248 if (ret.error) { 249 result = sbi_err_map_linux_errno(ret.error); 250 pr_err("%s: hbase = [%lu] hmask = [0x%lx] failed (error [%d])\n", 251 __func__, hbase, hmask, result); 252 } 253 254 return result; 255 } 256 257 static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask, 258 unsigned long start, unsigned long size, 259 unsigned long arg4, unsigned long arg5) 260 { 261 unsigned long hartid, cpuid, hmask = 0, hbase = 0, htop = 0; 262 int result; 263 264 if (!cpu_mask || cpumask_empty(cpu_mask)) 265 cpu_mask = cpu_online_mask; 266 267 for_each_cpu(cpuid, cpu_mask) { 268 hartid = cpuid_to_hartid_map(cpuid); 269 if (hmask) { 270 if (hartid + BITS_PER_LONG <= htop || 271 hbase + BITS_PER_LONG <= hartid) { 272 result = __sbi_rfence_v02_call(fid, hmask, 273 hbase, start, size, arg4, arg5); 274 if (result) 275 return result; 276 hmask = 0; 277 } else if (hartid < hbase) { 278 /* shift the mask to fit lower hartid */ 279 hmask <<= hbase - hartid; 280 hbase = hartid; 281 } 282 } 283 if (!hmask) { 284 hbase = hartid; 285 htop = hartid; 286 } else if (hartid > htop) { 287 htop = hartid; 288 } 289 hmask |= BIT(hartid - hbase); 290 } 291 292 if (hmask) { 293 result = __sbi_rfence_v02_call(fid, hmask, hbase, 294 start, size, arg4, arg5); 295 if (result) 296 return result; 297 } 298 299 return 0; 300 } 301 302 static bool sbi_fwft_supported; 303 304 struct fwft_set_req { 305 u32 feature; 306 unsigned long value; 307 unsigned long flags; 308 atomic_t error; 309 }; 310 311 static void cpu_sbi_fwft_set(void *arg) 312 { 313 struct fwft_set_req *req = arg; 314 int ret; 315 316 ret = sbi_fwft_set(req->feature, req->value, req->flags); 317 if (ret) 318 atomic_set(&req->error, ret); 319 } 320 321 /** 322 * sbi_fwft_set() - Set a feature on the local hart 323 * @feature: The feature ID to be set 324 * @value: The feature value to be set 325 * @flags: FWFT feature set flags 326 * 327 * Return: 0 on success, appropriate linux error code otherwise. 328 */ 329 int sbi_fwft_set(u32 feature, unsigned long value, unsigned long flags) 330 { 331 struct sbiret ret; 332 333 if (!sbi_fwft_supported) 334 return -EOPNOTSUPP; 335 336 ret = sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_SET, 337 feature, value, flags, 0, 0, 0); 338 339 return sbi_err_map_linux_errno(ret.error); 340 } 341 342 /** 343 * sbi_fwft_set_cpumask() - Set a feature for the specified cpumask 344 * @mask: CPU mask of cpus that need the feature to be set 345 * @feature: The feature ID to be set 346 * @value: The feature value to be set 347 * @flags: FWFT feature set flags 348 * 349 * Return: 0 on success, appropriate linux error code otherwise. 350 */ 351 int sbi_fwft_set_cpumask(const cpumask_t *mask, u32 feature, 352 unsigned long value, unsigned long flags) 353 { 354 struct fwft_set_req req = { 355 .feature = feature, 356 .value = value, 357 .flags = flags, 358 .error = ATOMIC_INIT(0), 359 }; 360 361 if (!sbi_fwft_supported) 362 return -EOPNOTSUPP; 363 364 if (feature & SBI_FWFT_GLOBAL_FEATURE_BIT) 365 return -EINVAL; 366 367 on_each_cpu_mask(mask, cpu_sbi_fwft_set, &req, 1); 368 369 return atomic_read(&req.error); 370 } 371 372 /** 373 * sbi_set_timer() - Program the timer for next timer event. 374 * @stime_value: The value after which next timer event should fire. 375 * 376 * Return: None. 377 */ 378 void sbi_set_timer(uint64_t stime_value) 379 { 380 __sbi_set_timer(stime_value); 381 } 382 383 /** 384 * sbi_send_ipi() - Send an IPI to any hart. 385 * @cpu: Logical id of the target CPU. 386 */ 387 void sbi_send_ipi(unsigned int cpu) 388 { 389 __sbi_send_ipi(cpu); 390 } 391 EXPORT_SYMBOL(sbi_send_ipi); 392 393 /** 394 * sbi_remote_fence_i() - Execute FENCE.I instruction on given remote harts. 395 * @cpu_mask: A cpu mask containing all the target harts. 396 * 397 * Return: 0 on success, appropriate linux error code otherwise. 398 */ 399 int sbi_remote_fence_i(const struct cpumask *cpu_mask) 400 { 401 return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_FENCE_I, 402 cpu_mask, 0, 0, 0, 0); 403 } 404 EXPORT_SYMBOL(sbi_remote_fence_i); 405 406 /** 407 * sbi_remote_sfence_vma_asid() - Execute SFENCE.VMA instructions on given 408 * remote harts for a virtual address range belonging to a specific ASID or not. 409 * 410 * @cpu_mask: A cpu mask containing all the target harts. 411 * @start: Start of the virtual address 412 * @size: Total size of the virtual address range. 413 * @asid: The value of address space identifier (ASID), or FLUSH_TLB_NO_ASID 414 * for flushing all address spaces. 415 * 416 * Return: 0 on success, appropriate linux error code otherwise. 417 */ 418 int sbi_remote_sfence_vma_asid(const struct cpumask *cpu_mask, 419 unsigned long start, 420 unsigned long size, 421 unsigned long asid) 422 { 423 if (asid == FLUSH_TLB_NO_ASID) 424 return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA, 425 cpu_mask, start, size, 0, 0); 426 else 427 return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID, 428 cpu_mask, start, size, asid, 0); 429 } 430 EXPORT_SYMBOL(sbi_remote_sfence_vma_asid); 431 432 /** 433 * sbi_remote_hfence_gvma() - Execute HFENCE.GVMA instructions on given remote 434 * harts for the specified guest physical address range. 435 * @cpu_mask: A cpu mask containing all the target harts. 436 * @start: Start of the guest physical address 437 * @size: Total size of the guest physical address range. 438 * 439 * Return: None 440 */ 441 int sbi_remote_hfence_gvma(const struct cpumask *cpu_mask, 442 unsigned long start, 443 unsigned long size) 444 { 445 return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA, 446 cpu_mask, start, size, 0, 0); 447 } 448 EXPORT_SYMBOL_GPL(sbi_remote_hfence_gvma); 449 450 /** 451 * sbi_remote_hfence_gvma_vmid() - Execute HFENCE.GVMA instructions on given 452 * remote harts for a guest physical address range belonging to a specific VMID. 453 * 454 * @cpu_mask: A cpu mask containing all the target harts. 455 * @start: Start of the guest physical address 456 * @size: Total size of the guest physical address range. 457 * @vmid: The value of guest ID (VMID). 458 * 459 * Return: 0 if success, Error otherwise. 460 */ 461 int sbi_remote_hfence_gvma_vmid(const struct cpumask *cpu_mask, 462 unsigned long start, 463 unsigned long size, 464 unsigned long vmid) 465 { 466 return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID, 467 cpu_mask, start, size, vmid, 0); 468 } 469 EXPORT_SYMBOL(sbi_remote_hfence_gvma_vmid); 470 471 /** 472 * sbi_remote_hfence_vvma() - Execute HFENCE.VVMA instructions on given remote 473 * harts for the current guest virtual address range. 474 * @cpu_mask: A cpu mask containing all the target harts. 475 * @start: Start of the current guest virtual address 476 * @size: Total size of the current guest virtual address range. 477 * 478 * Return: None 479 */ 480 int sbi_remote_hfence_vvma(const struct cpumask *cpu_mask, 481 unsigned long start, 482 unsigned long size) 483 { 484 return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA, 485 cpu_mask, start, size, 0, 0); 486 } 487 EXPORT_SYMBOL(sbi_remote_hfence_vvma); 488 489 /** 490 * sbi_remote_hfence_vvma_asid() - Execute HFENCE.VVMA instructions on given 491 * remote harts for current guest virtual address range belonging to a specific 492 * ASID. 493 * 494 * @cpu_mask: A cpu mask containing all the target harts. 495 * @start: Start of the current guest virtual address 496 * @size: Total size of the current guest virtual address range. 497 * @asid: The value of address space identifier (ASID). 498 * 499 * Return: None 500 */ 501 int sbi_remote_hfence_vvma_asid(const struct cpumask *cpu_mask, 502 unsigned long start, 503 unsigned long size, 504 unsigned long asid) 505 { 506 return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID, 507 cpu_mask, start, size, asid, 0); 508 } 509 EXPORT_SYMBOL(sbi_remote_hfence_vvma_asid); 510 511 static void sbi_srst_reset(unsigned long type, unsigned long reason) 512 { 513 sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET, type, reason, 514 0, 0, 0, 0); 515 pr_warn("%s: type=0x%lx reason=0x%lx failed\n", 516 __func__, type, reason); 517 } 518 519 static int sbi_srst_reboot(struct notifier_block *this, 520 unsigned long mode, void *cmd) 521 { 522 sbi_srst_reset((mode == REBOOT_WARM || mode == REBOOT_SOFT) ? 523 SBI_SRST_RESET_TYPE_WARM_REBOOT : 524 SBI_SRST_RESET_TYPE_COLD_REBOOT, 525 SBI_SRST_RESET_REASON_NONE); 526 return NOTIFY_DONE; 527 } 528 529 static struct notifier_block sbi_srst_reboot_nb; 530 531 static void sbi_srst_power_off(void) 532 { 533 sbi_srst_reset(SBI_SRST_RESET_TYPE_SHUTDOWN, 534 SBI_SRST_RESET_REASON_NONE); 535 } 536 537 /** 538 * sbi_probe_extension() - Check if an SBI extension ID is supported or not. 539 * @extid: The extension ID to be probed. 540 * 541 * Return: 1 or an extension specific nonzero value if yes, 0 otherwise. 542 */ 543 long sbi_probe_extension(int extid) 544 { 545 struct sbiret ret; 546 547 ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid, 548 0, 0, 0, 0, 0); 549 if (!ret.error) 550 return ret.value; 551 552 return 0; 553 } 554 EXPORT_SYMBOL(sbi_probe_extension); 555 556 static inline long sbi_get_spec_version(void) 557 { 558 return __sbi_base_ecall(SBI_EXT_BASE_GET_SPEC_VERSION); 559 } 560 561 static inline long sbi_get_firmware_id(void) 562 { 563 return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_ID); 564 } 565 566 static inline long sbi_get_firmware_version(void) 567 { 568 return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION); 569 } 570 571 long sbi_get_mvendorid(void) 572 { 573 return __sbi_base_ecall(SBI_EXT_BASE_GET_MVENDORID); 574 } 575 EXPORT_SYMBOL_GPL(sbi_get_mvendorid); 576 577 long sbi_get_marchid(void) 578 { 579 return __sbi_base_ecall(SBI_EXT_BASE_GET_MARCHID); 580 } 581 EXPORT_SYMBOL_GPL(sbi_get_marchid); 582 583 long sbi_get_mimpid(void) 584 { 585 return __sbi_base_ecall(SBI_EXT_BASE_GET_MIMPID); 586 } 587 EXPORT_SYMBOL_GPL(sbi_get_mimpid); 588 589 bool sbi_debug_console_available; 590 591 int sbi_debug_console_write(const char *bytes, unsigned int num_bytes) 592 { 593 phys_addr_t base_addr; 594 struct sbiret ret; 595 596 if (!sbi_debug_console_available) 597 return -EOPNOTSUPP; 598 599 if (is_vmalloc_addr(bytes)) 600 base_addr = page_to_phys(vmalloc_to_page(bytes)) + 601 offset_in_page(bytes); 602 else 603 base_addr = __pa(bytes); 604 if (PAGE_SIZE < (offset_in_page(bytes) + num_bytes)) 605 num_bytes = PAGE_SIZE - offset_in_page(bytes); 606 607 if (IS_ENABLED(CONFIG_32BIT)) 608 ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE, 609 num_bytes, lower_32_bits(base_addr), 610 upper_32_bits(base_addr), 0, 0, 0); 611 else 612 ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE, 613 num_bytes, base_addr, 0, 0, 0, 0); 614 615 if (ret.error == SBI_ERR_FAILURE) 616 return -EIO; 617 return ret.error ? sbi_err_map_linux_errno(ret.error) : ret.value; 618 } 619 620 int sbi_debug_console_read(char *bytes, unsigned int num_bytes) 621 { 622 phys_addr_t base_addr; 623 struct sbiret ret; 624 625 if (!sbi_debug_console_available) 626 return -EOPNOTSUPP; 627 628 if (is_vmalloc_addr(bytes)) 629 base_addr = page_to_phys(vmalloc_to_page(bytes)) + 630 offset_in_page(bytes); 631 else 632 base_addr = __pa(bytes); 633 if (PAGE_SIZE < (offset_in_page(bytes) + num_bytes)) 634 num_bytes = PAGE_SIZE - offset_in_page(bytes); 635 636 if (IS_ENABLED(CONFIG_32BIT)) 637 ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_READ, 638 num_bytes, lower_32_bits(base_addr), 639 upper_32_bits(base_addr), 0, 0, 0); 640 else 641 ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_READ, 642 num_bytes, base_addr, 0, 0, 0, 0); 643 644 if (ret.error == SBI_ERR_FAILURE) 645 return -EIO; 646 return ret.error ? sbi_err_map_linux_errno(ret.error) : ret.value; 647 } 648 649 void __init sbi_init(void) 650 { 651 int ret; 652 653 sbi_set_power_off(); 654 ret = sbi_get_spec_version(); 655 if (ret > 0) 656 sbi_spec_version = ret; 657 658 pr_info("SBI specification v%lu.%lu detected\n", 659 sbi_major_version(), sbi_minor_version()); 660 661 if (!sbi_spec_is_0_1()) { 662 pr_info("SBI implementation ID=0x%lx Version=0x%lx\n", 663 sbi_get_firmware_id(), sbi_get_firmware_version()); 664 if (sbi_probe_extension(SBI_EXT_TIME)) { 665 __sbi_set_timer = __sbi_set_timer_v02; 666 pr_info("SBI TIME extension detected\n"); 667 } else { 668 __sbi_set_timer = __sbi_set_timer_v01; 669 } 670 if (sbi_probe_extension(SBI_EXT_IPI)) { 671 __sbi_send_ipi = __sbi_send_ipi_v02; 672 pr_info("SBI IPI extension detected\n"); 673 } else { 674 __sbi_send_ipi = __sbi_send_ipi_v01; 675 } 676 if (sbi_probe_extension(SBI_EXT_RFENCE)) { 677 __sbi_rfence = __sbi_rfence_v02; 678 pr_info("SBI RFENCE extension detected\n"); 679 } else { 680 __sbi_rfence = __sbi_rfence_v01; 681 } 682 if (sbi_spec_version >= sbi_mk_version(0, 3) && 683 sbi_probe_extension(SBI_EXT_SRST)) { 684 pr_info("SBI SRST extension detected\n"); 685 pm_power_off = sbi_srst_power_off; 686 sbi_srst_reboot_nb.notifier_call = sbi_srst_reboot; 687 sbi_srst_reboot_nb.priority = 192; 688 register_restart_handler(&sbi_srst_reboot_nb); 689 } 690 if (sbi_spec_version >= sbi_mk_version(2, 0) && 691 sbi_probe_extension(SBI_EXT_DBCN) > 0) { 692 pr_info("SBI DBCN extension detected\n"); 693 sbi_debug_console_available = true; 694 } 695 if (sbi_spec_version >= sbi_mk_version(3, 0) && 696 sbi_probe_extension(SBI_EXT_FWFT)) { 697 pr_info("SBI FWFT extension detected\n"); 698 sbi_fwft_supported = true; 699 } 700 } else { 701 __sbi_set_timer = __sbi_set_timer_v01; 702 __sbi_send_ipi = __sbi_send_ipi_v01; 703 __sbi_rfence = __sbi_rfence_v01; 704 } 705 } 706