irq_sim.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * Copyright (C) 2017 Bartosz Golaszewski <brgl@bgdev.pl>
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the
  6. * Free Software Foundation; either version 2 of the License, or (at your
  7. * option) any later version.
  8. */
  9. #include <linux/irq_sim.h>
  10. #include <linux/irq.h>
  11. struct irq_sim_devres {
  12. struct irq_sim *sim;
  13. };
  14. static void irq_sim_irqmask(struct irq_data *data)
  15. {
  16. struct irq_sim_irq_ctx *irq_ctx = irq_data_get_irq_chip_data(data);
  17. irq_ctx->enabled = false;
  18. }
  19. static void irq_sim_irqunmask(struct irq_data *data)
  20. {
  21. struct irq_sim_irq_ctx *irq_ctx = irq_data_get_irq_chip_data(data);
  22. irq_ctx->enabled = true;
  23. }
  24. static struct irq_chip irq_sim_irqchip = {
  25. .name = "irq_sim",
  26. .irq_mask = irq_sim_irqmask,
  27. .irq_unmask = irq_sim_irqunmask,
  28. };
  29. static void irq_sim_handle_irq(struct irq_work *work)
  30. {
  31. struct irq_sim_work_ctx *work_ctx;
  32. work_ctx = container_of(work, struct irq_sim_work_ctx, work);
  33. handle_simple_irq(irq_to_desc(work_ctx->irq));
  34. }
  35. /**
  36. * irq_sim_init - Initialize the interrupt simulator: allocate a range of
  37. * dummy interrupts.
  38. *
  39. * @sim: The interrupt simulator object to initialize.
  40. * @num_irqs: Number of interrupts to allocate
  41. *
  42. * Returns 0 on success and a negative error number on failure.
  43. */
  44. int irq_sim_init(struct irq_sim *sim, unsigned int num_irqs)
  45. {
  46. int i;
  47. sim->irqs = kmalloc_array(num_irqs, sizeof(*sim->irqs), GFP_KERNEL);
  48. if (!sim->irqs)
  49. return -ENOMEM;
  50. sim->irq_base = irq_alloc_descs(-1, 0, num_irqs, 0);
  51. if (sim->irq_base < 0) {
  52. kfree(sim->irqs);
  53. return sim->irq_base;
  54. }
  55. for (i = 0; i < num_irqs; i++) {
  56. sim->irqs[i].irqnum = sim->irq_base + i;
  57. sim->irqs[i].enabled = false;
  58. irq_set_chip(sim->irq_base + i, &irq_sim_irqchip);
  59. irq_set_chip_data(sim->irq_base + i, &sim->irqs[i]);
  60. irq_set_handler(sim->irq_base + i, &handle_simple_irq);
  61. irq_modify_status(sim->irq_base + i,
  62. IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
  63. }
  64. init_irq_work(&sim->work_ctx.work, irq_sim_handle_irq);
  65. sim->irq_count = num_irqs;
  66. return 0;
  67. }
  68. EXPORT_SYMBOL_GPL(irq_sim_init);
  69. /**
  70. * irq_sim_fini - Deinitialize the interrupt simulator: free the interrupt
  71. * descriptors and allocated memory.
  72. *
  73. * @sim: The interrupt simulator to tear down.
  74. */
  75. void irq_sim_fini(struct irq_sim *sim)
  76. {
  77. irq_work_sync(&sim->work_ctx.work);
  78. irq_free_descs(sim->irq_base, sim->irq_count);
  79. kfree(sim->irqs);
  80. }
  81. EXPORT_SYMBOL_GPL(irq_sim_fini);
  82. static void devm_irq_sim_release(struct device *dev, void *res)
  83. {
  84. struct irq_sim_devres *this = res;
  85. irq_sim_fini(this->sim);
  86. }
  87. /**
  88. * irq_sim_init - Initialize the interrupt simulator for a managed device.
  89. *
  90. * @dev: Device to initialize the simulator object for.
  91. * @sim: The interrupt simulator object to initialize.
  92. * @num_irqs: Number of interrupts to allocate
  93. *
  94. * Returns 0 on success and a negative error number on failure.
  95. */
  96. int devm_irq_sim_init(struct device *dev, struct irq_sim *sim,
  97. unsigned int num_irqs)
  98. {
  99. struct irq_sim_devres *dr;
  100. int rv;
  101. dr = devres_alloc(devm_irq_sim_release, sizeof(*dr), GFP_KERNEL);
  102. if (!dr)
  103. return -ENOMEM;
  104. rv = irq_sim_init(sim, num_irqs);
  105. if (rv) {
  106. devres_free(dr);
  107. return rv;
  108. }
  109. dr->sim = sim;
  110. devres_add(dev, dr);
  111. return 0;
  112. }
  113. EXPORT_SYMBOL_GPL(devm_irq_sim_init);
  114. /**
  115. * irq_sim_fire - Enqueue an interrupt.
  116. *
  117. * @sim: The interrupt simulator object.
  118. * @offset: Offset of the simulated interrupt which should be fired.
  119. */
  120. void irq_sim_fire(struct irq_sim *sim, unsigned int offset)
  121. {
  122. if (sim->irqs[offset].enabled) {
  123. sim->work_ctx.irq = irq_sim_irqnum(sim, offset);
  124. irq_work_queue(&sim->work_ctx.work);
  125. }
  126. }
  127. EXPORT_SYMBOL_GPL(irq_sim_fire);
  128. /**
  129. * irq_sim_irqnum - Get the allocated number of a dummy interrupt.
  130. *
  131. * @sim: The interrupt simulator object.
  132. * @offset: Offset of the simulated interrupt for which to retrieve
  133. * the number.
  134. */
  135. int irq_sim_irqnum(struct irq_sim *sim, unsigned int offset)
  136. {
  137. return sim->irqs[offset].irqnum;
  138. }
  139. EXPORT_SYMBOL_GPL(irq_sim_irqnum);