sbi-ipi.c 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Multiplex several IPIs over a single HW IPI.
  4. *
  5. * Copyright (c) 2022 Ventana Micro Systems Inc.
  6. */
  7. #define pr_fmt(fmt) "riscv: " fmt
  8. #include <linux/cpu.h>
  9. #include <linux/init.h>
  10. #include <linux/irq.h>
  11. #include <linux/irqchip/chained_irq.h>
  12. #include <linux/irqdomain.h>
  13. #include <asm/sbi.h>
  14. DEFINE_STATIC_KEY_FALSE(riscv_sbi_for_rfence);
  15. EXPORT_SYMBOL_GPL(riscv_sbi_for_rfence);
  16. static int sbi_ipi_virq;
  17. static void sbi_ipi_handle(struct irq_desc *desc)
  18. {
  19. struct irq_chip *chip = irq_desc_get_chip(desc);
  20. chained_irq_enter(chip, desc);
  21. csr_clear(CSR_IP, IE_SIE);
  22. ipi_mux_process();
  23. chained_irq_exit(chip, desc);
  24. }
  25. static int sbi_ipi_starting_cpu(unsigned int cpu)
  26. {
  27. enable_percpu_irq(sbi_ipi_virq, irq_get_trigger_type(sbi_ipi_virq));
  28. return 0;
  29. }
  30. void __init sbi_ipi_init(void)
  31. {
  32. int virq;
  33. struct irq_domain *domain;
  34. if (riscv_ipi_have_virq_range())
  35. return;
  36. domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(),
  37. DOMAIN_BUS_ANY);
  38. if (!domain) {
  39. pr_err("unable to find INTC IRQ domain\n");
  40. return;
  41. }
  42. sbi_ipi_virq = irq_create_mapping(domain, RV_IRQ_SOFT);
  43. if (!sbi_ipi_virq) {
  44. pr_err("unable to create INTC IRQ mapping\n");
  45. return;
  46. }
  47. virq = ipi_mux_create(BITS_PER_BYTE, sbi_send_ipi);
  48. if (virq <= 0) {
  49. pr_err("unable to create muxed IPIs\n");
  50. irq_dispose_mapping(sbi_ipi_virq);
  51. return;
  52. }
  53. irq_set_chained_handler(sbi_ipi_virq, sbi_ipi_handle);
  54. /*
  55. * Don't disable IPI when CPU goes offline because
  56. * the masking/unmasking of virtual IPIs is done
  57. * via generic IPI-Mux
  58. */
  59. cpuhp_setup_state(CPUHP_AP_IRQ_RISCV_SBI_IPI_STARTING,
  60. "irqchip/sbi-ipi:starting",
  61. sbi_ipi_starting_cpu, NULL);
  62. riscv_ipi_set_virq_range(virq, BITS_PER_BYTE);
  63. pr_info("providing IPIs using SBI IPI extension\n");
  64. /*
  65. * Use the SBI remote fence extension to avoid
  66. * the extra context switch needed to handle IPIs.
  67. */
  68. static_branch_enable(&riscv_sbi_for_rfence);
  69. }