balancing.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * Support for hardware-managed IRQ auto-distribution.
  3. *
  4. * Copyright (C) 2010 Paul Mundt
  5. *
  6. * This file is subject to the terms and conditions of the GNU General Public
  7. * License. See the file "COPYING" in the main directory of this archive
  8. * for more details.
  9. */
  10. #include "internals.h"
  11. static unsigned long dist_handle[INTC_NR_IRQS];
  12. void intc_balancing_enable(unsigned int irq)
  13. {
  14. struct intc_desc_int *d = get_intc_desc(irq);
  15. unsigned long handle = dist_handle[irq];
  16. unsigned long addr;
  17. if (irq_balancing_disabled(irq) || !handle)
  18. return;
  19. addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
  20. intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
  21. }
  22. void intc_balancing_disable(unsigned int irq)
  23. {
  24. struct intc_desc_int *d = get_intc_desc(irq);
  25. unsigned long handle = dist_handle[irq];
  26. unsigned long addr;
  27. if (irq_balancing_disabled(irq) || !handle)
  28. return;
  29. addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
  30. intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
  31. }
  32. static unsigned int intc_dist_data(struct intc_desc *desc,
  33. struct intc_desc_int *d,
  34. intc_enum enum_id)
  35. {
  36. struct intc_mask_reg *mr = desc->hw.mask_regs;
  37. unsigned int i, j, fn, mode;
  38. unsigned long reg_e, reg_d;
  39. for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
  40. mr = desc->hw.mask_regs + i;
  41. /*
  42. * Skip this entry if there's no auto-distribution
  43. * register associated with it.
  44. */
  45. if (!mr->dist_reg)
  46. continue;
  47. for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
  48. if (mr->enum_ids[j] != enum_id)
  49. continue;
  50. fn = REG_FN_MODIFY_BASE;
  51. mode = MODE_ENABLE_REG;
  52. reg_e = mr->dist_reg;
  53. reg_d = mr->dist_reg;
  54. fn += (mr->reg_width >> 3) - 1;
  55. return _INTC_MK(fn, mode,
  56. intc_get_reg(d, reg_e),
  57. intc_get_reg(d, reg_d),
  58. 1,
  59. (mr->reg_width - 1) - j);
  60. }
  61. }
  62. /*
  63. * It's possible we've gotten here with no distribution options
  64. * available for the IRQ in question, so we just skip over those.
  65. */
  66. return 0;
  67. }
  68. void intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
  69. struct intc_desc_int *d, intc_enum id)
  70. {
  71. unsigned long flags;
  72. /*
  73. * Nothing to do for this IRQ.
  74. */
  75. if (!desc->hw.mask_regs)
  76. return;
  77. raw_spin_lock_irqsave(&intc_big_lock, flags);
  78. dist_handle[irq] = intc_dist_data(desc, d, id);
  79. raw_spin_unlock_irqrestore(&intc_big_lock, flags);
  80. }