fsl_mpic_err.c 3.6 KB

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