smp.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2019 Fraunhofer AISEC,
  4. * Lukas Auer <lukas.auer@aisec.fraunhofer.de>
  5. */
  6. #include <common.h>
  7. #include <cpu_func.h>
  8. #include <dm.h>
  9. #include <asm/barrier.h>
  10. #include <asm/global_data.h>
  11. #include <asm/smp.h>
  12. DECLARE_GLOBAL_DATA_PTR;
  13. static int send_ipi_many(struct ipi_data *ipi, int wait)
  14. {
  15. ofnode node, cpus;
  16. u32 reg;
  17. int ret, pending;
  18. cpus = ofnode_path("/cpus");
  19. if (!ofnode_valid(cpus)) {
  20. pr_err("Can't find cpus node!\n");
  21. return -EINVAL;
  22. }
  23. ofnode_for_each_subnode(node, cpus) {
  24. /* skip if hart is marked as not available in the device tree */
  25. if (!ofnode_is_available(node))
  26. continue;
  27. /* read hart ID of CPU */
  28. ret = ofnode_read_u32(node, "reg", &reg);
  29. if (ret)
  30. continue;
  31. /* skip if it is the hart we are running on */
  32. if (reg == gd->arch.boot_hart)
  33. continue;
  34. if (reg >= CONFIG_NR_CPUS) {
  35. pr_err("Hart ID %d is out of range, increase CONFIG_NR_CPUS\n",
  36. reg);
  37. continue;
  38. }
  39. #ifndef CONFIG_XIP
  40. /* skip if hart is not available */
  41. if (!(gd->arch.available_harts & (1 << reg)))
  42. continue;
  43. #endif
  44. gd->arch.ipi[reg].addr = ipi->addr;
  45. gd->arch.ipi[reg].arg0 = ipi->arg0;
  46. gd->arch.ipi[reg].arg1 = ipi->arg1;
  47. /*
  48. * Ensure valid only becomes set when the IPI parameters are
  49. * set. An IPI may already be pending on other harts, so we
  50. * need a way to signal that the IPI device has been
  51. * initialized, and that it is ok to call the function.
  52. */
  53. __smp_store_release(&gd->arch.ipi[reg].valid, 1);
  54. ret = riscv_send_ipi(reg);
  55. if (ret) {
  56. pr_err("Cannot send IPI to hart %d\n", reg);
  57. return ret;
  58. }
  59. if (wait) {
  60. pending = 1;
  61. while (pending) {
  62. ret = riscv_get_ipi(reg, &pending);
  63. if (ret)
  64. return ret;
  65. }
  66. }
  67. }
  68. return 0;
  69. }
  70. void handle_ipi(ulong hart)
  71. {
  72. int ret;
  73. void (*smp_function)(ulong hart, ulong arg0, ulong arg1);
  74. if (hart >= CONFIG_NR_CPUS)
  75. return;
  76. /*
  77. * If valid is not set, then U-Boot has not requested the IPI. The
  78. * IPI device may not be initialized, so all we can do is wait for
  79. * U-Boot to initialize it and send an IPI
  80. */
  81. if (!__smp_load_acquire(&gd->arch.ipi[hart].valid))
  82. return;
  83. smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
  84. invalidate_icache_all();
  85. /*
  86. * Clear the IPI to acknowledge the request before jumping to the
  87. * requested function.
  88. */
  89. ret = riscv_clear_ipi(hart);
  90. if (ret) {
  91. pr_err("Cannot clear IPI of hart %ld (error %d)\n", hart, ret);
  92. return;
  93. }
  94. smp_function(hart, gd->arch.ipi[hart].arg0, gd->arch.ipi[hart].arg1);
  95. }
  96. int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait)
  97. {
  98. struct ipi_data ipi = {
  99. .addr = addr,
  100. .arg0 = arg0,
  101. .arg1 = arg1,
  102. };
  103. return send_ipi_many(&ipi, wait);
  104. }