Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Support for hardware-managed IRQ auto-distribution.
0003  *
0004  * Copyright (C) 2010  Paul Mundt
0005  *
0006  * This file is subject to the terms and conditions of the GNU General Public
0007  * License.  See the file "COPYING" in the main directory of this archive
0008  * for more details.
0009  */
0010 #include "internals.h"
0011 
0012 static unsigned long dist_handle[INTC_NR_IRQS];
0013 
0014 void intc_balancing_enable(unsigned int irq)
0015 {
0016     struct intc_desc_int *d = get_intc_desc(irq);
0017     unsigned long handle = dist_handle[irq];
0018     unsigned long addr;
0019 
0020     if (irq_balancing_disabled(irq) || !handle)
0021         return;
0022 
0023     addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
0024     intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
0025 }
0026 
0027 void intc_balancing_disable(unsigned int irq)
0028 {
0029     struct intc_desc_int *d = get_intc_desc(irq);
0030     unsigned long handle = dist_handle[irq];
0031     unsigned long addr;
0032 
0033     if (irq_balancing_disabled(irq) || !handle)
0034         return;
0035 
0036     addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
0037     intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
0038 }
0039 
0040 static unsigned int intc_dist_data(struct intc_desc *desc,
0041                    struct intc_desc_int *d,
0042                    intc_enum enum_id)
0043 {
0044     struct intc_mask_reg *mr = desc->hw.mask_regs;
0045     unsigned int i, j, fn, mode;
0046     unsigned long reg_e, reg_d;
0047 
0048     for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
0049         mr = desc->hw.mask_regs + i;
0050 
0051         /*
0052          * Skip this entry if there's no auto-distribution
0053          * register associated with it.
0054          */
0055         if (!mr->dist_reg)
0056             continue;
0057 
0058         for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
0059             if (mr->enum_ids[j] != enum_id)
0060                 continue;
0061 
0062             fn = REG_FN_MODIFY_BASE;
0063             mode = MODE_ENABLE_REG;
0064             reg_e = mr->dist_reg;
0065             reg_d = mr->dist_reg;
0066 
0067             fn += (mr->reg_width >> 3) - 1;
0068             return _INTC_MK(fn, mode,
0069                     intc_get_reg(d, reg_e),
0070                     intc_get_reg(d, reg_d),
0071                     1,
0072                     (mr->reg_width - 1) - j);
0073         }
0074     }
0075 
0076     /*
0077      * It's possible we've gotten here with no distribution options
0078      * available for the IRQ in question, so we just skip over those.
0079      */
0080     return 0;
0081 }
0082 
0083 void intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
0084               struct intc_desc_int *d, intc_enum id)
0085 {
0086     unsigned long flags;
0087 
0088     /*
0089      * Nothing to do for this IRQ.
0090      */
0091     if (!desc->hw.mask_regs)
0092         return;
0093 
0094     raw_spin_lock_irqsave(&intc_big_lock, flags);
0095     dist_handle[irq] = intc_dist_data(desc, d, id);
0096     raw_spin_unlock_irqrestore(&intc_big_lock, flags);
0097 }