fsl_mpic_err.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2012 Freescale Semiconductor, Inc.
  4. *
  5. * Author: Varun Sethi <[email protected]>
  6. */
  7. #include <linux/irq.h>
  8. #include <linux/smp.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/irqdomain.h>
  11. #include <asm/io.h>
  12. #include <asm/irq.h>
  13. #include <asm/mpic.h>
  14. #include "mpic.h"
  15. #define MPIC_ERR_INT_BASE 0x3900
  16. #define MPIC_ERR_INT_EISR 0x0000
  17. #define MPIC_ERR_INT_EIMR 0x0010
  18. static inline u32 mpic_fsl_err_read(u32 __iomem *base, unsigned int err_reg)
  19. {
  20. return in_be32(base + (err_reg >> 2));
  21. }
  22. static inline void mpic_fsl_err_write(u32 __iomem *base, u32 value)
  23. {
  24. out_be32(base + (MPIC_ERR_INT_EIMR >> 2), value);
  25. }
  26. static void fsl_mpic_mask_err(struct irq_data *d)
  27. {
  28. u32 eimr;
  29. struct mpic *mpic = irq_data_get_irq_chip_data(d);
  30. unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
  31. eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
  32. eimr |= (1 << (31 - src));
  33. mpic_fsl_err_write(mpic->err_regs, eimr);
  34. }
  35. static void fsl_mpic_unmask_err(struct irq_data *d)
  36. {
  37. u32 eimr;
  38. struct mpic *mpic = irq_data_get_irq_chip_data(d);
  39. unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
  40. eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
  41. eimr &= ~(1 << (31 - src));
  42. mpic_fsl_err_write(mpic->err_regs, eimr);
  43. }
  44. static struct irq_chip fsl_mpic_err_chip = {
  45. .irq_disable = fsl_mpic_mask_err,
  46. .irq_mask = fsl_mpic_mask_err,
  47. .irq_unmask = fsl_mpic_unmask_err,
  48. };
  49. int __init mpic_setup_error_int(struct mpic *mpic, int intvec)
  50. {
  51. int i;
  52. mpic->err_regs = ioremap(mpic->paddr + MPIC_ERR_INT_BASE, 0x1000);
  53. if (!mpic->err_regs) {
  54. pr_err("could not map mpic error registers\n");
  55. return -ENOMEM;
  56. }
  57. mpic->hc_err = fsl_mpic_err_chip;
  58. mpic->hc_err.name = mpic->name;
  59. mpic->flags |= MPIC_FSL_HAS_EIMR;
  60. /* allocate interrupt vectors for error interrupts */
  61. for (i = MPIC_MAX_ERR - 1; i >= 0; i--)
  62. mpic->err_int_vecs[i] = intvec--;
  63. return 0;
  64. }
  65. int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw)
  66. {
  67. if ((mpic->flags & MPIC_FSL_HAS_EIMR) &&
  68. (hw >= mpic->err_int_vecs[0] &&
  69. hw <= mpic->err_int_vecs[MPIC_MAX_ERR - 1])) {
  70. WARN_ON(mpic->flags & MPIC_SECONDARY);
  71. pr_debug("mpic: mapping as Error Interrupt\n");
  72. irq_set_chip_data(virq, mpic);
  73. irq_set_chip_and_handler(virq, &mpic->hc_err,
  74. handle_level_irq);
  75. return 1;
  76. }
  77. return 0;
  78. }
  79. static irqreturn_t fsl_error_int_handler(int irq, void *data)
  80. {
  81. struct mpic *mpic = (struct mpic *) data;
  82. u32 eisr, eimr;
  83. int errint;
  84. eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR);
  85. eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
  86. if (!(eisr & ~eimr))
  87. return IRQ_NONE;
  88. while (eisr) {
  89. int ret;
  90. errint = __builtin_clz(eisr);
  91. ret = generic_handle_domain_irq(mpic->irqhost,
  92. mpic->err_int_vecs[errint]);
  93. if (WARN_ON(ret)) {
  94. eimr |= 1 << (31 - errint);
  95. mpic_fsl_err_write(mpic->err_regs, eimr);
  96. }
  97. eisr &= ~(1 << (31 - errint));
  98. }
  99. return IRQ_HANDLED;
  100. }
  101. void __init mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
  102. {
  103. unsigned int virq;
  104. int ret;
  105. virq = irq_create_mapping(mpic->irqhost, irqnum);
  106. if (!virq) {
  107. pr_err("Error interrupt setup failed\n");
  108. return;
  109. }
  110. /* Mask all error interrupts */
  111. mpic_fsl_err_write(mpic->err_regs, ~0);
  112. ret = request_irq(virq, fsl_error_int_handler, IRQF_NO_THREAD,
  113. "mpic-error-int", mpic);
  114. if (ret)
  115. pr_err("Failed to register error interrupt handler\n");
  116. }