sbi.c 18 KB

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