021-v5.19-03-gpio-realtek-otto-Support-per-cpu-interrupts.patch 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. From 95fa6dbe58f286a8f87cb37b7516232eb678de2d Mon Sep 17 00:00:00 2001
  2. From: Sander Vanheule <[email protected]>
  3. Date: Sat, 9 Apr 2022 21:55:48 +0200
  4. Subject: [PATCH 3/6] gpio: realtek-otto: Support per-cpu interrupts
  5. On SoCs with multiple cores, it is possible that the GPIO interrupt
  6. controller supports assigning specific pins to one or more cores.
  7. IRQ balancing can be performed on a line-by-line basis if the parent
  8. interrupt is routed to all available cores, which is the default upon
  9. initialisation.
  10. Signed-off-by: Sander Vanheule <[email protected]>
  11. Signed-off-by: Bartosz Golaszewski <[email protected]>
  12. ---
  13. drivers/gpio/gpio-realtek-otto.c | 75 +++++++++++++++++++++++++++++++-
  14. 1 file changed, 74 insertions(+), 1 deletion(-)
  15. --- a/drivers/gpio/gpio-realtek-otto.c
  16. +++ b/drivers/gpio/gpio-realtek-otto.c
  17. @@ -1,6 +1,7 @@
  18. // SPDX-License-Identifier: GPL-2.0-only
  19. #include <linux/gpio/driver.h>
  20. +#include <linux/cpumask.h>
  21. #include <linux/irq.h>
  22. #include <linux/minmax.h>
  23. #include <linux/mod_devicetable.h>
  24. @@ -55,6 +56,8 @@
  25. struct realtek_gpio_ctrl {
  26. struct gpio_chip gc;
  27. void __iomem *base;
  28. + void __iomem *cpumask_base;
  29. + struct cpumask cpu_irq_maskable;
  30. raw_spinlock_t lock;
  31. u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK];
  32. u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK];
  33. @@ -76,6 +79,11 @@ enum realtek_gpio_flags {
  34. * fields, and [BA, DC] for 2-bit fields.
  35. */
  36. GPIO_PORTS_REVERSED = BIT(1),
  37. + /*
  38. + * Interrupts can be enabled per cpu. This requires a secondary IO
  39. + * range, where the per-cpu enable masks are located.
  40. + */
  41. + GPIO_INTERRUPTS_PER_CPU = BIT(2),
  42. };
  43. static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data)
  44. @@ -247,14 +255,61 @@ static void realtek_gpio_irq_handler(str
  45. chained_irq_exit(irq_chip, desc);
  46. }
  47. +static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl,
  48. + unsigned int port, int cpu)
  49. +{
  50. + return ctrl->cpumask_base + ctrl->port_offset_u8(port) +
  51. + REALTEK_GPIO_PORTS_PER_BANK * cpu;
  52. +}
  53. +
  54. +static int realtek_gpio_irq_set_affinity(struct irq_data *data,
  55. + const struct cpumask *dest, bool force)
  56. +{
  57. + struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
  58. + unsigned int line = irqd_to_hwirq(data);
  59. + unsigned int port = line / 8;
  60. + unsigned int port_pin = line % 8;
  61. + void __iomem *irq_cpu_mask;
  62. + unsigned long flags;
  63. + int cpu;
  64. + u8 v;
  65. +
  66. + if (!ctrl->cpumask_base)
  67. + return -ENXIO;
  68. +
  69. + raw_spin_lock_irqsave(&ctrl->lock, flags);
  70. +
  71. + for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
  72. + irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
  73. + v = ioread8(irq_cpu_mask);
  74. +
  75. + if (cpumask_test_cpu(cpu, dest))
  76. + v |= BIT(port_pin);
  77. + else
  78. + v &= ~BIT(port_pin);
  79. +
  80. + iowrite8(v, irq_cpu_mask);
  81. + }
  82. +
  83. + raw_spin_unlock_irqrestore(&ctrl->lock, flags);
  84. +
  85. + irq_data_update_effective_affinity(data, dest);
  86. +
  87. + return 0;
  88. +}
  89. +
  90. static int realtek_gpio_irq_init(struct gpio_chip *gc)
  91. {
  92. struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
  93. unsigned int port;
  94. + int cpu;
  95. for (port = 0; (port * 8) < gc->ngpio; port++) {
  96. realtek_gpio_write_imr(ctrl, port, 0, 0);
  97. realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0));
  98. +
  99. + for_each_cpu(cpu, &ctrl->cpu_irq_maskable)
  100. + iowrite8(GENMASK(7, 0), realtek_gpio_irq_cpu_mask(ctrl, port, cpu));
  101. }
  102. return 0;
  103. @@ -266,6 +321,7 @@ static struct irq_chip realtek_gpio_irq_
  104. .irq_mask = realtek_gpio_irq_mask,
  105. .irq_unmask = realtek_gpio_irq_unmask,
  106. .irq_set_type = realtek_gpio_irq_set_type,
  107. + .irq_set_affinity = realtek_gpio_irq_set_affinity,
  108. };
  109. static const struct of_device_id realtek_gpio_of_match[] = {
  110. @@ -290,8 +346,10 @@ static int realtek_gpio_probe(struct pla
  111. unsigned int dev_flags;
  112. struct gpio_irq_chip *girq;
  113. struct realtek_gpio_ctrl *ctrl;
  114. + struct resource *res;
  115. u32 ngpios;
  116. - int err, irq;
  117. + unsigned int nr_cpus;
  118. + int cpu, err, irq;
  119. ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
  120. if (!ctrl)
  121. @@ -352,6 +410,21 @@ static int realtek_gpio_probe(struct pla
  122. girq->init_hw = realtek_gpio_irq_init;
  123. }
  124. + cpumask_clear(&ctrl->cpu_irq_maskable);
  125. +
  126. + if ((dev_flags & GPIO_INTERRUPTS_PER_CPU) && irq > 0) {
  127. + ctrl->cpumask_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
  128. + if (IS_ERR(ctrl->cpumask_base))
  129. + return dev_err_probe(dev, PTR_ERR(ctrl->cpumask_base),
  130. + "missing CPU IRQ mask registers");
  131. +
  132. + nr_cpus = resource_size(res) / REALTEK_GPIO_PORTS_PER_BANK;
  133. + nr_cpus = min(nr_cpus, num_present_cpus());
  134. +
  135. + for (cpu = 0; cpu < nr_cpus; cpu++)
  136. + cpumask_set_cpu(cpu, &ctrl->cpu_irq_maskable);
  137. + }
  138. +
  139. return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
  140. }