sbi.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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. #include <linux/init.h>
  8. #include <linux/pm.h>
  9. #include <asm/sbi.h>
  10. #include <asm/smp.h>
  11. /* default SBI version is 0.1 */
  12. unsigned long sbi_spec_version = SBI_SPEC_VERSION_DEFAULT;
  13. EXPORT_SYMBOL(sbi_spec_version);
  14. static void (*__sbi_set_timer)(uint64_t stime);
  15. static int (*__sbi_send_ipi)(const unsigned long *hart_mask);
  16. static int (*__sbi_rfence)(int fid, const unsigned long *hart_mask,
  17. unsigned long start, unsigned long size,
  18. unsigned long arg4, unsigned long arg5);
  19. struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
  20. unsigned long arg1, unsigned long arg2,
  21. unsigned long arg3, unsigned long arg4,
  22. unsigned long arg5)
  23. {
  24. struct sbiret ret;
  25. register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
  26. register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
  27. register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
  28. register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
  29. register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
  30. register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
  31. register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
  32. register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
  33. asm volatile ("ecall"
  34. : "+r" (a0), "+r" (a1)
  35. : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
  36. : "memory");
  37. ret.error = a0;
  38. ret.value = a1;
  39. return ret;
  40. }
  41. EXPORT_SYMBOL(sbi_ecall);
  42. int sbi_err_map_linux_errno(int err)
  43. {
  44. switch (err) {
  45. case SBI_SUCCESS:
  46. return 0;
  47. case SBI_ERR_DENIED:
  48. return -EPERM;
  49. case SBI_ERR_INVALID_PARAM:
  50. return -EINVAL;
  51. case SBI_ERR_INVALID_ADDRESS:
  52. return -EFAULT;
  53. case SBI_ERR_NOT_SUPPORTED:
  54. case SBI_ERR_FAILURE:
  55. default:
  56. return -ENOTSUPP;
  57. };
  58. }
  59. EXPORT_SYMBOL(sbi_err_map_linux_errno);
  60. #ifdef CONFIG_RISCV_SBI_V01
  61. /**
  62. * sbi_console_putchar() - Writes given character to the console device.
  63. * @ch: The data to be written to the console.
  64. *
  65. * Return: None
  66. */
  67. void sbi_console_putchar(int ch)
  68. {
  69. sbi_ecall(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, ch, 0, 0, 0, 0, 0);
  70. }
  71. EXPORT_SYMBOL(sbi_console_putchar);
  72. /**
  73. * sbi_console_getchar() - Reads a byte from console device.
  74. *
  75. * Returns the value read from console.
  76. */
  77. int sbi_console_getchar(void)
  78. {
  79. struct sbiret ret;
  80. ret = sbi_ecall(SBI_EXT_0_1_CONSOLE_GETCHAR, 0, 0, 0, 0, 0, 0, 0);
  81. return ret.error;
  82. }
  83. EXPORT_SYMBOL(sbi_console_getchar);
  84. /**
  85. * sbi_shutdown() - Remove all the harts from executing supervisor code.
  86. *
  87. * Return: None
  88. */
  89. extern void khv_shutdown(void);
  90. void sbi_shutdown(void)
  91. {
  92. #ifdef CONFIG_VIRTIO_KHV_MMIO
  93. khv_shutdown();
  94. #endif
  95. sbi_ecall(SBI_EXT_0_1_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0);
  96. }
  97. EXPORT_SYMBOL(sbi_shutdown);
  98. /**
  99. * sbi_clear_ipi() - Clear any pending IPIs for the calling hart.
  100. *
  101. * Return: None
  102. */
  103. void sbi_clear_ipi(void)
  104. {
  105. sbi_ecall(SBI_EXT_0_1_CLEAR_IPI, 0, 0, 0, 0, 0, 0, 0);
  106. }
  107. EXPORT_SYMBOL(sbi_clear_ipi);
  108. /**
  109. * sbi_set_timer_v01() - Program the timer for next timer event.
  110. * @stime_value: The value after which next timer event should fire.
  111. *
  112. * Return: None
  113. */
  114. static void __sbi_set_timer_v01(uint64_t stime_value)
  115. {
  116. #if __riscv_xlen == 32
  117. sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value,
  118. stime_value >> 32, 0, 0, 0, 0);
  119. #else
  120. sbi_ecall(SBI_EXT_0_1_SET_TIMER, 0, stime_value, 0, 0, 0, 0, 0);
  121. #endif
  122. }
  123. static int __sbi_send_ipi_v01(const unsigned long *hart_mask)
  124. {
  125. sbi_ecall(SBI_EXT_0_1_SEND_IPI, 0, (unsigned long)hart_mask,
  126. 0, 0, 0, 0, 0);
  127. return 0;
  128. }
  129. static int __sbi_rfence_v01(int fid, const unsigned long *hart_mask,
  130. unsigned long start, unsigned long size,
  131. unsigned long arg4, unsigned long arg5)
  132. {
  133. int result = 0;
  134. /* v0.2 function IDs are equivalent to v0.1 extension IDs */
  135. switch (fid) {
  136. case SBI_EXT_RFENCE_REMOTE_FENCE_I:
  137. sbi_ecall(SBI_EXT_0_1_REMOTE_FENCE_I, 0,
  138. (unsigned long)hart_mask, 0, 0, 0, 0, 0);
  139. break;
  140. case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
  141. sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA, 0,
  142. (unsigned long)hart_mask, start, size,
  143. 0, 0, 0);
  144. break;
  145. case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
  146. sbi_ecall(SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID, 0,
  147. (unsigned long)hart_mask, start, size,
  148. arg4, 0, 0);
  149. break;
  150. default:
  151. pr_err("SBI call [%d]not supported in SBI v0.1\n", fid);
  152. result = -EINVAL;
  153. }
  154. return result;
  155. }
  156. static void sbi_set_power_off(void)
  157. {
  158. pm_power_off = sbi_shutdown;
  159. }
  160. #else
  161. static void __sbi_set_timer_v01(uint64_t stime_value)
  162. {
  163. pr_warn("Timer extension is not available in SBI v%lu.%lu\n",
  164. sbi_major_version(), sbi_minor_version());
  165. }
  166. static int __sbi_send_ipi_v01(const unsigned long *hart_mask)
  167. {
  168. pr_warn("IPI extension is not available in SBI v%lu.%lu\n",
  169. sbi_major_version(), sbi_minor_version());
  170. return 0;
  171. }
  172. static int __sbi_rfence_v01(int fid, const unsigned long *hart_mask,
  173. unsigned long start, unsigned long size,
  174. unsigned long arg4, unsigned long arg5)
  175. {
  176. pr_warn("remote fence extension is not available in SBI v%lu.%lu\n",
  177. sbi_major_version(), sbi_minor_version());
  178. return 0;
  179. }
  180. static void sbi_set_power_off(void) {}
  181. #endif /* CONFIG_RISCV_SBI_V01 */
  182. static void __sbi_set_timer_v02(uint64_t stime_value)
  183. {
  184. #if __riscv_xlen == 32
  185. sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value,
  186. stime_value >> 32, 0, 0, 0, 0);
  187. #else
  188. sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0,
  189. 0, 0, 0, 0);
  190. #endif
  191. }
  192. static int __sbi_send_ipi_v02(const unsigned long *hart_mask)
  193. {
  194. unsigned long hartid, hmask_val, hbase;
  195. struct cpumask tmask;
  196. struct sbiret ret = {0};
  197. int result;
  198. if (!hart_mask || !(*hart_mask)) {
  199. riscv_cpuid_to_hartid_mask(cpu_online_mask, &tmask);
  200. hart_mask = cpumask_bits(&tmask);
  201. }
  202. hmask_val = 0;
  203. hbase = 0;
  204. for_each_set_bit(hartid, hart_mask, NR_CPUS) {
  205. if (hmask_val && ((hbase + BITS_PER_LONG) <= hartid)) {
  206. ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI,
  207. hmask_val, hbase, 0, 0, 0, 0);
  208. if (ret.error)
  209. goto ecall_failed;
  210. hmask_val = 0;
  211. hbase = 0;
  212. }
  213. if (!hmask_val)
  214. hbase = hartid;
  215. hmask_val |= 1UL << (hartid - hbase);
  216. }
  217. if (hmask_val) {
  218. ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI,
  219. hmask_val, hbase, 0, 0, 0, 0);
  220. if (ret.error)
  221. goto ecall_failed;
  222. }
  223. return 0;
  224. ecall_failed:
  225. result = sbi_err_map_linux_errno(ret.error);
  226. pr_err("%s: hbase = [%lu] hmask = [0x%lx] failed (error [%d])\n",
  227. __func__, hbase, hmask_val, result);
  228. return result;
  229. }
  230. static int __sbi_rfence_v02_call(unsigned long fid, unsigned long hmask_val,
  231. unsigned long hbase, unsigned long start,
  232. unsigned long size, unsigned long arg4,
  233. unsigned long arg5)
  234. {
  235. struct sbiret ret = {0};
  236. int ext = SBI_EXT_RFENCE;
  237. int result = 0;
  238. switch (fid) {
  239. case SBI_EXT_RFENCE_REMOTE_FENCE_I:
  240. ret = sbi_ecall(ext, fid, hmask_val, hbase, 0, 0, 0, 0);
  241. break;
  242. case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
  243. ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
  244. size, 0, 0);
  245. break;
  246. case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
  247. ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
  248. size, arg4, 0);
  249. break;
  250. case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
  251. ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
  252. size, 0, 0);
  253. break;
  254. case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
  255. ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
  256. size, arg4, 0);
  257. break;
  258. case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
  259. ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
  260. size, 0, 0);
  261. break;
  262. case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
  263. ret = sbi_ecall(ext, fid, hmask_val, hbase, start,
  264. size, arg4, 0);
  265. break;
  266. default:
  267. pr_err("unknown function ID [%lu] for SBI extension [%d]\n",
  268. fid, ext);
  269. result = -EINVAL;
  270. }
  271. if (ret.error) {
  272. result = sbi_err_map_linux_errno(ret.error);
  273. pr_err("%s: hbase = [%lu] hmask = [0x%lx] failed (error [%d])\n",
  274. __func__, hbase, hmask_val, result);
  275. }
  276. return result;
  277. }
  278. static int __sbi_rfence_v02(int fid, const unsigned long *hart_mask,
  279. unsigned long start, unsigned long size,
  280. unsigned long arg4, unsigned long arg5)
  281. {
  282. unsigned long hmask_val, hartid, hbase;
  283. struct cpumask tmask;
  284. int result;
  285. if (!hart_mask || !(*hart_mask)) {
  286. riscv_cpuid_to_hartid_mask(cpu_online_mask, &tmask);
  287. hart_mask = cpumask_bits(&tmask);
  288. }
  289. hmask_val = 0;
  290. hbase = 0;
  291. for_each_set_bit(hartid, hart_mask, NR_CPUS) {
  292. if (hmask_val && ((hbase + BITS_PER_LONG) <= hartid)) {
  293. result = __sbi_rfence_v02_call(fid, hmask_val, hbase,
  294. start, size, arg4, arg5);
  295. if (result)
  296. return result;
  297. hmask_val = 0;
  298. hbase = 0;
  299. }
  300. if (!hmask_val)
  301. hbase = hartid;
  302. hmask_val |= 1UL << (hartid - hbase);
  303. }
  304. if (hmask_val) {
  305. result = __sbi_rfence_v02_call(fid, hmask_val, hbase,
  306. start, size, arg4, arg5);
  307. if (result)
  308. return result;
  309. }
  310. return 0;
  311. }
  312. /**
  313. * sbi_set_timer() - Program the timer for next timer event.
  314. * @stime_value: The value after which next timer event should fire.
  315. *
  316. * Return: None
  317. */
  318. void sbi_set_timer(uint64_t stime_value)
  319. {
  320. __sbi_set_timer(stime_value);
  321. }
  322. /**
  323. * sbi_send_ipi() - Send an IPI to any hart.
  324. * @hart_mask: A cpu mask containing all the target harts.
  325. *
  326. * Return: None
  327. */
  328. void sbi_send_ipi(const unsigned long *hart_mask)
  329. {
  330. __sbi_send_ipi(hart_mask);
  331. }
  332. EXPORT_SYMBOL(sbi_send_ipi);
  333. /**
  334. * sbi_remote_fence_i() - Execute FENCE.I instruction on given remote harts.
  335. * @hart_mask: A cpu mask containing all the target harts.
  336. *
  337. * Return: None
  338. */
  339. void sbi_remote_fence_i(const unsigned long *hart_mask)
  340. {
  341. __sbi_rfence(SBI_EXT_RFENCE_REMOTE_FENCE_I,
  342. hart_mask, 0, 0, 0, 0);
  343. }
  344. EXPORT_SYMBOL(sbi_remote_fence_i);
  345. /**
  346. * sbi_remote_sfence_vma() - Execute SFENCE.VMA instructions on given remote
  347. * harts for the specified virtual address range.
  348. * @hart_mask: A cpu mask containing all the target harts.
  349. * @start: Start of the virtual address
  350. * @size: Total size of the virtual address range.
  351. *
  352. * Return: None
  353. */
  354. void sbi_remote_sfence_vma(const unsigned long *hart_mask,
  355. unsigned long start,
  356. unsigned long size)
  357. {
  358. __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
  359. hart_mask, start, size, 0, 0);
  360. }
  361. EXPORT_SYMBOL(sbi_remote_sfence_vma);
  362. /**
  363. * sbi_remote_sfence_vma_asid() - Execute SFENCE.VMA instructions on given
  364. * remote harts for a virtual address range belonging to a specific ASID.
  365. *
  366. * @hart_mask: A cpu mask containing all the target harts.
  367. * @start: Start of the virtual address
  368. * @size: Total size of the virtual address range.
  369. * @asid: The value of address space identifier (ASID).
  370. *
  371. * Return: None
  372. */
  373. void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
  374. unsigned long start,
  375. unsigned long size,
  376. unsigned long asid)
  377. {
  378. __sbi_rfence(SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
  379. hart_mask, start, size, asid, 0);
  380. }
  381. EXPORT_SYMBOL(sbi_remote_sfence_vma_asid);
  382. /**
  383. * sbi_remote_hfence_gvma() - Execute HFENCE.GVMA instructions on given remote
  384. * harts for the specified guest physical address range.
  385. * @hart_mask: A cpu mask containing all the target harts.
  386. * @start: Start of the guest physical address
  387. * @size: Total size of the guest physical address range.
  388. *
  389. * Return: None
  390. */
  391. int sbi_remote_hfence_gvma(const unsigned long *hart_mask,
  392. unsigned long start,
  393. unsigned long size)
  394. {
  395. return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA,
  396. hart_mask, start, size, 0, 0);
  397. }
  398. EXPORT_SYMBOL_GPL(sbi_remote_hfence_gvma);
  399. /**
  400. * sbi_remote_hfence_gvma_vmid() - Execute HFENCE.GVMA instructions on given
  401. * remote harts for a guest physical address range belonging to a specific VMID.
  402. *
  403. * @hart_mask: A cpu mask containing all the target harts.
  404. * @start: Start of the guest physical address
  405. * @size: Total size of the guest physical address range.
  406. * @vmid: The value of guest ID (VMID).
  407. *
  408. * Return: 0 if success, Error otherwise.
  409. */
  410. int sbi_remote_hfence_gvma_vmid(const unsigned long *hart_mask,
  411. unsigned long start,
  412. unsigned long size,
  413. unsigned long vmid)
  414. {
  415. return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID,
  416. hart_mask, start, size, vmid, 0);
  417. }
  418. EXPORT_SYMBOL(sbi_remote_hfence_gvma_vmid);
  419. /**
  420. * sbi_remote_hfence_vvma() - Execute HFENCE.VVMA instructions on given remote
  421. * harts for the current guest virtual address range.
  422. * @hart_mask: A cpu mask containing all the target harts.
  423. * @start: Start of the current guest virtual address
  424. * @size: Total size of the current guest virtual address range.
  425. *
  426. * Return: None
  427. */
  428. int sbi_remote_hfence_vvma(const unsigned long *hart_mask,
  429. unsigned long start,
  430. unsigned long size)
  431. {
  432. return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA,
  433. hart_mask, start, size, 0, 0);
  434. }
  435. EXPORT_SYMBOL(sbi_remote_hfence_vvma);
  436. /**
  437. * sbi_remote_hfence_vvma_asid() - Execute HFENCE.VVMA instructions on given
  438. * remote harts for current guest virtual address range belonging to a specific
  439. * ASID.
  440. *
  441. * @hart_mask: A cpu mask containing all the target harts.
  442. * @start: Start of the current guest virtual address
  443. * @size: Total size of the current guest virtual address range.
  444. * @asid: The value of address space identifier (ASID).
  445. *
  446. * Return: None
  447. */
  448. int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,
  449. unsigned long start,
  450. unsigned long size,
  451. unsigned long asid)
  452. {
  453. return __sbi_rfence(SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID,
  454. hart_mask, start, size, asid, 0);
  455. }
  456. EXPORT_SYMBOL(sbi_remote_hfence_vvma_asid);
  457. /**
  458. * sbi_probe_extension() - Check if an SBI extension ID is supported or not.
  459. * @extid: The extension ID to be probed.
  460. *
  461. * Return: Extension specific nonzero value f yes, -ENOTSUPP otherwise.
  462. */
  463. int sbi_probe_extension(int extid)
  464. {
  465. struct sbiret ret;
  466. ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid,
  467. 0, 0, 0, 0, 0);
  468. if (!ret.error)
  469. if (ret.value)
  470. return ret.value;
  471. return -ENOTSUPP;
  472. }
  473. EXPORT_SYMBOL(sbi_probe_extension);
  474. static long __sbi_base_ecall(int fid)
  475. {
  476. struct sbiret ret;
  477. ret = sbi_ecall(SBI_EXT_BASE, fid, 0, 0, 0, 0, 0, 0);
  478. if (!ret.error)
  479. return ret.value;
  480. else
  481. return sbi_err_map_linux_errno(ret.error);
  482. }
  483. static inline long sbi_get_spec_version(void)
  484. {
  485. return __sbi_base_ecall(SBI_EXT_BASE_GET_SPEC_VERSION);
  486. }
  487. static inline long sbi_get_firmware_id(void)
  488. {
  489. return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_ID);
  490. }
  491. static inline long sbi_get_firmware_version(void)
  492. {
  493. return __sbi_base_ecall(SBI_EXT_BASE_GET_IMP_VERSION);
  494. }
  495. long sbi_get_mvendorid(void)
  496. {
  497. return __sbi_base_ecall(SBI_EXT_BASE_GET_MVENDORID);
  498. }
  499. long sbi_get_marchid(void)
  500. {
  501. return __sbi_base_ecall(SBI_EXT_BASE_GET_MARCHID);
  502. }
  503. long sbi_get_mimpid(void)
  504. {
  505. return __sbi_base_ecall(SBI_EXT_BASE_GET_MIMPID);
  506. }
  507. static void sbi_send_cpumask_ipi(const struct cpumask *target)
  508. {
  509. struct cpumask hartid_mask;
  510. riscv_cpuid_to_hartid_mask(target, &hartid_mask);
  511. sbi_send_ipi(cpumask_bits(&hartid_mask));
  512. }
  513. static struct riscv_ipi_ops sbi_ipi_ops = {
  514. .ipi_inject = sbi_send_cpumask_ipi
  515. };
  516. int __init sbi_init(void)
  517. {
  518. int ret;
  519. sbi_set_power_off();
  520. ret = sbi_get_spec_version();
  521. if (ret > 0)
  522. sbi_spec_version = ret;
  523. pr_info("SBI specification v%lu.%lu detected\n",
  524. sbi_major_version(), sbi_minor_version());
  525. if (!sbi_spec_is_0_1()) {
  526. pr_info("SBI implementation ID=0x%lx Version=0x%lx\n",
  527. sbi_get_firmware_id(), sbi_get_firmware_version());
  528. if (sbi_probe_extension(SBI_EXT_TIME) > 0) {
  529. __sbi_set_timer = __sbi_set_timer_v02;
  530. pr_info("SBI v0.2 TIME extension detected\n");
  531. } else {
  532. __sbi_set_timer = __sbi_set_timer_v01;
  533. }
  534. if (sbi_probe_extension(SBI_EXT_IPI) > 0) {
  535. __sbi_send_ipi = __sbi_send_ipi_v02;
  536. pr_info("SBI v0.2 IPI extension detected\n");
  537. } else {
  538. __sbi_send_ipi = __sbi_send_ipi_v01;
  539. }
  540. if (sbi_probe_extension(SBI_EXT_RFENCE) > 0) {
  541. __sbi_rfence = __sbi_rfence_v02;
  542. pr_info("SBI v0.2 RFENCE extension detected\n");
  543. } else {
  544. __sbi_rfence = __sbi_rfence_v01;
  545. }
  546. } else {
  547. __sbi_set_timer = __sbi_set_timer_v01;
  548. __sbi_send_ipi = __sbi_send_ipi_v01;
  549. __sbi_rfence = __sbi_rfence_v01;
  550. }
  551. riscv_set_ipi_ops(&sbi_ipi_ops);
  552. return 0;
  553. }