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