summaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-mips-gic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/irqchip/irq-mips-gic.c')
-rw-r--r--drivers/irqchip/irq-mips-gic.c616
1 files changed, 181 insertions, 435 deletions
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index b3a60da088db..6e52a88bbd9e 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -12,27 +12,38 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
-#include <linux/irqchip/mips-gic.h>
#include <linux/of_address.h>
+#include <linux/percpu.h>
#include <linux/sched.h>
#include <linux/smp.h>
-#include <asm/mips-cm.h>
+#include <asm/mips-cps.h>
#include <asm/setup.h>
#include <asm/traps.h>
#include <dt-bindings/interrupt-controller/mips-gic.h>
-unsigned int gic_present;
+#define GIC_MAX_INTRS 256
+#define GIC_MAX_LONGS BITS_TO_LONGS(GIC_MAX_INTRS)
-struct gic_pcpu_mask {
- DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
-};
+/* Add 2 to convert GIC CPU pin to core interrupt */
+#define GIC_CPU_PIN_OFFSET 2
+
+/* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */
+#define GIC_PIN_TO_VEC_OFFSET 1
+
+/* Convert between local/shared IRQ number and GIC HW IRQ number. */
+#define GIC_LOCAL_HWIRQ_BASE 0
+#define GIC_LOCAL_TO_HWIRQ(x) (GIC_LOCAL_HWIRQ_BASE + (x))
+#define GIC_HWIRQ_TO_LOCAL(x) ((x) - GIC_LOCAL_HWIRQ_BASE)
+#define GIC_SHARED_HWIRQ_BASE GIC_NUM_LOCAL_INTRS
+#define GIC_SHARED_TO_HWIRQ(x) (GIC_SHARED_HWIRQ_BASE + (x))
+#define GIC_HWIRQ_TO_SHARED(x) ((x) - GIC_SHARED_HWIRQ_BASE)
+
+void __iomem *mips_gic_base;
-static unsigned long __gic_base_addr;
+DEFINE_PER_CPU_READ_MOSTLY(unsigned long[GIC_MAX_LONGS], pcpu_masks);
-static void __iomem *gic_base;
-static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
static DEFINE_SPINLOCK(gic_lock);
static struct irq_domain *gic_irq_domain;
static struct irq_domain *gic_ipi_domain;
@@ -44,202 +55,13 @@ static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS);
-static void __gic_irq_dispatch(void);
-
-static inline u32 gic_read32(unsigned int reg)
-{
- return __raw_readl(gic_base + reg);
-}
-
-static inline u64 gic_read64(unsigned int reg)
-{
- return __raw_readq(gic_base + reg);
-}
-
-static inline unsigned long gic_read(unsigned int reg)
-{
- if (!mips_cm_is64)
- return gic_read32(reg);
- else
- return gic_read64(reg);
-}
-
-static inline void gic_write32(unsigned int reg, u32 val)
-{
- return __raw_writel(val, gic_base + reg);
-}
-
-static inline void gic_write64(unsigned int reg, u64 val)
-{
- return __raw_writeq(val, gic_base + reg);
-}
-
-static inline void gic_write(unsigned int reg, unsigned long val)
-{
- if (!mips_cm_is64)
- return gic_write32(reg, (u32)val);
- else
- return gic_write64(reg, (u64)val);
-}
-
-static inline void gic_update_bits(unsigned int reg, unsigned long mask,
- unsigned long val)
-{
- unsigned long regval;
-
- regval = gic_read(reg);
- regval &= ~mask;
- regval |= val;
- gic_write(reg, regval);
-}
-
-static inline void gic_reset_mask(unsigned int intr)
-{
- gic_write(GIC_REG(SHARED, GIC_SH_RMASK) + GIC_INTR_OFS(intr),
- 1ul << GIC_INTR_BIT(intr));
-}
-
-static inline void gic_set_mask(unsigned int intr)
-{
- gic_write(GIC_REG(SHARED, GIC_SH_SMASK) + GIC_INTR_OFS(intr),
- 1ul << GIC_INTR_BIT(intr));
-}
-
-static inline void gic_set_polarity(unsigned int intr, unsigned int pol)
-{
- gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) +
- GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr),
- (unsigned long)pol << GIC_INTR_BIT(intr));
-}
-
-static inline void gic_set_trigger(unsigned int intr, unsigned int trig)
-{
- gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) +
- GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr),
- (unsigned long)trig << GIC_INTR_BIT(intr));
-}
-
-static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual)
-{
- gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr),
- 1ul << GIC_INTR_BIT(intr),
- (unsigned long)dual << GIC_INTR_BIT(intr));
-}
-
-static inline void gic_map_to_pin(unsigned int intr, unsigned int pin)
-{
- gic_write32(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) +
- GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin);
-}
-
-static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe)
-{
- gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_VPE_BASE) +
- GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe),
- GIC_SH_MAP_TO_VPE_REG_BIT(vpe));
-}
-
-#ifdef CONFIG_CLKSRC_MIPS_GIC
-u64 notrace gic_read_count(void)
-{
- unsigned int hi, hi2, lo;
-
- if (mips_cm_is64)
- return (u64)gic_read(GIC_REG(SHARED, GIC_SH_COUNTER));
-
- do {
- hi = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32));
- lo = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_31_00));
- hi2 = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32));
- } while (hi2 != hi);
-
- return (((u64) hi) << 32) + lo;
-}
-
-unsigned int gic_get_count_width(void)
-{
- unsigned int bits, config;
-
- config = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
- bits = 32 + 4 * ((config & GIC_SH_CONFIG_COUNTBITS_MSK) >>
- GIC_SH_CONFIG_COUNTBITS_SHF);
-
- return bits;
-}
-
-void notrace gic_write_compare(u64 cnt)
-{
- if (mips_cm_is64) {
- gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE), cnt);
- } else {
- gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI),
- (int)(cnt >> 32));
- gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO),
- (int)(cnt & 0xffffffff));
- }
-}
-
-void notrace gic_write_cpu_compare(u64 cnt, int cpu)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), mips_cm_vp_id(cpu));
-
- if (mips_cm_is64) {
- gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt);
- } else {
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI),
- (int)(cnt >> 32));
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO),
- (int)(cnt & 0xffffffff));
- }
-
- local_irq_restore(flags);
-}
-
-u64 gic_read_compare(void)
-{
- unsigned int hi, lo;
-
- if (mips_cm_is64)
- return (u64)gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE));
-
- hi = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI));
- lo = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO));
-
- return (((u64) hi) << 32) + lo;
-}
-
-void gic_start_count(void)
+static void gic_clear_pcpu_masks(unsigned int intr)
{
- u32 gicconfig;
-
- /* Start the counter */
- gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
- gicconfig &= ~(1 << GIC_SH_CONFIG_COUNTSTOP_SHF);
- gic_write(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
-}
-
-void gic_stop_count(void)
-{
- u32 gicconfig;
-
- /* Stop the counter */
- gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
- gicconfig |= 1 << GIC_SH_CONFIG_COUNTSTOP_SHF;
- gic_write(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
-}
-
-#endif
-
-unsigned gic_read_local_vp_id(void)
-{
- unsigned long ident;
+ unsigned int i;
- ident = gic_read(GIC_REG(VPE_LOCAL, GIC_VP_IDENT));
- return ident & GIC_VP_IDENT_VCNUM_MSK;
+ /* Clear the interrupt's bit in all pcpu_masks */
+ for_each_possible_cpu(i)
+ clear_bit(intr, per_cpu_ptr(pcpu_masks, i));
}
static bool gic_local_irq_is_routable(int intr)
@@ -250,17 +72,17 @@ static bool gic_local_irq_is_routable(int intr)
if (cpu_has_veic)
return true;
- vpe_ctl = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_CTL));
+ vpe_ctl = read_gic_vl_ctl();
switch (intr) {
case GIC_LOCAL_INT_TIMER:
- return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK;
+ return vpe_ctl & GIC_VX_CTL_TIMER_ROUTABLE;
case GIC_LOCAL_INT_PERFCTR:
- return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK;
+ return vpe_ctl & GIC_VX_CTL_PERFCNT_ROUTABLE;
case GIC_LOCAL_INT_FDC:
- return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK;
+ return vpe_ctl & GIC_VX_CTL_FDC_ROUTABLE;
case GIC_LOCAL_INT_SWINT0:
case GIC_LOCAL_INT_SWINT1:
- return vpe_ctl & GIC_VPE_CTL_SWINT_RTBL_MSK;
+ return vpe_ctl & GIC_VX_CTL_SWINT_ROUTABLE;
default:
return true;
}
@@ -272,15 +94,14 @@ static void gic_bind_eic_interrupt(int irq, int set)
irq -= GIC_PIN_TO_VEC_OFFSET;
/* Set irq to use shadow set */
- gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_EIC_SHADOW_SET_BASE) +
- GIC_VPE_EIC_SS(irq), set);
+ write_gic_vl_eic_shadow_set(irq, set);
}
static void gic_send_ipi(struct irq_data *d, unsigned int cpu)
{
irq_hw_number_t hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(d));
- gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_SET(hwirq));
+ write_gic_wedge(GIC_WEDGE_RW | hwirq);
}
int gic_get_c0_compare_int(void)
@@ -316,47 +137,22 @@ int gic_get_c0_fdc_int(void)
GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
}
-int gic_get_usm_range(struct resource *gic_usm_res)
-{
- if (!gic_present)
- return -1;
-
- gic_usm_res->start = __gic_base_addr + USM_VISIBLE_SECTION_OFS;
- gic_usm_res->end = gic_usm_res->start + (USM_VISIBLE_SECTION_SIZE - 1);
-
- return 0;
-}
-
static void gic_handle_shared_int(bool chained)
{
- unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4;
+ unsigned int intr, virq;
unsigned long *pcpu_mask;
- unsigned long pending_reg, intrmask_reg;
DECLARE_BITMAP(pending, GIC_MAX_INTRS);
- DECLARE_BITMAP(intrmask, GIC_MAX_INTRS);
/* Get per-cpu bitmaps */
- pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
-
- pending_reg = GIC_REG(SHARED, GIC_SH_PEND);
- intrmask_reg = GIC_REG(SHARED, GIC_SH_MASK);
-
- for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) {
- pending[i] = gic_read(pending_reg);
- intrmask[i] = gic_read(intrmask_reg);
- pending_reg += gic_reg_step;
- intrmask_reg += gic_reg_step;
-
- if (!IS_ENABLED(CONFIG_64BIT) || mips_cm_is64)
- continue;
+ pcpu_mask = this_cpu_ptr(pcpu_masks);
- pending[i] |= (u64)gic_read(pending_reg) << 32;
- intrmask[i] |= (u64)gic_read(intrmask_reg) << 32;
- pending_reg += gic_reg_step;
- intrmask_reg += gic_reg_step;
- }
+ if (mips_cm_is64)
+ __ioread64_copy(pending, addr_gic_pend(),
+ DIV_ROUND_UP(gic_shared_intrs, 64));
+ else
+ __ioread32_copy(pending, addr_gic_pend(),
+ DIV_ROUND_UP(gic_shared_intrs, 32));
- bitmap_and(pending, pending, intrmask, gic_shared_intrs);
bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
for_each_set_bit(intr, pending, gic_shared_intrs) {
@@ -371,19 +167,30 @@ static void gic_handle_shared_int(bool chained)
static void gic_mask_irq(struct irq_data *d)
{
- gic_reset_mask(GIC_HWIRQ_TO_SHARED(d->hwirq));
+ unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq);
+
+ write_gic_rmask(BIT(intr));
+ gic_clear_pcpu_masks(intr);
}
static void gic_unmask_irq(struct irq_data *d)
{
- gic_set_mask(GIC_HWIRQ_TO_SHARED(d->hwirq));
+ struct cpumask *affinity = irq_data_get_affinity_mask(d);
+ unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq);
+ unsigned int cpu;
+
+ write_gic_smask(BIT(intr));
+
+ gic_clear_pcpu_masks(intr);
+ cpu = cpumask_first_and(affinity, cpu_online_mask);
+ set_bit(intr, per_cpu_ptr(pcpu_masks, cpu));
}
static void gic_ack_irq(struct irq_data *d)
{
unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
- gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_CLR(irq));
+ write_gic_wedge(irq);
}
static int gic_set_type(struct irq_data *d, unsigned int type)
@@ -395,34 +202,34 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
spin_lock_irqsave(&gic_lock, flags);
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_FALLING:
- gic_set_polarity(irq, GIC_POL_NEG);
- gic_set_trigger(irq, GIC_TRIG_EDGE);
- gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
+ change_gic_pol(irq, GIC_POL_FALLING_EDGE);
+ change_gic_trig(irq, GIC_TRIG_EDGE);
+ change_gic_dual(irq, GIC_DUAL_SINGLE);
is_edge = true;
break;
case IRQ_TYPE_EDGE_RISING:
- gic_set_polarity(irq, GIC_POL_POS);
- gic_set_trigger(irq, GIC_TRIG_EDGE);
- gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
+ change_gic_pol(irq, GIC_POL_RISING_EDGE);
+ change_gic_trig(irq, GIC_TRIG_EDGE);
+ change_gic_dual(irq, GIC_DUAL_SINGLE);
is_edge = true;
break;
case IRQ_TYPE_EDGE_BOTH:
/* polarity is irrelevant in this case */
- gic_set_trigger(irq, GIC_TRIG_EDGE);
- gic_set_dual_edge(irq, GIC_TRIG_DUAL_ENABLE);
+ change_gic_trig(irq, GIC_TRIG_EDGE);
+ change_gic_dual(irq, GIC_DUAL_DUAL);
is_edge = true;
break;
case IRQ_TYPE_LEVEL_LOW:
- gic_set_polarity(irq, GIC_POL_NEG);
- gic_set_trigger(irq, GIC_TRIG_LEVEL);
- gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
+ change_gic_pol(irq, GIC_POL_ACTIVE_LOW);
+ change_gic_trig(irq, GIC_TRIG_LEVEL);
+ change_gic_dual(irq, GIC_DUAL_SINGLE);
is_edge = false;
break;
case IRQ_TYPE_LEVEL_HIGH:
default:
- gic_set_polarity(irq, GIC_POL_POS);
- gic_set_trigger(irq, GIC_TRIG_LEVEL);
- gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE);
+ change_gic_pol(irq, GIC_POL_ACTIVE_HIGH);
+ change_gic_trig(irq, GIC_TRIG_LEVEL);
+ change_gic_dual(irq, GIC_DUAL_SINGLE);
is_edge = false;
break;
}
@@ -443,32 +250,28 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
bool force)
{
unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
- cpumask_t tmp = CPU_MASK_NONE;
- unsigned long flags;
- int i, cpu;
+ unsigned long flags;
+ unsigned int cpu;
- cpumask_and(&tmp, cpumask, cpu_online_mask);
- if (cpumask_empty(&tmp))
+ cpu = cpumask_first_and(cpumask, cpu_online_mask);
+ if (cpu >= NR_CPUS)
return -EINVAL;
- cpu = cpumask_first(&tmp);
-
/* Assumption : cpumask refers to a single CPU */
spin_lock_irqsave(&gic_lock, flags);
/* Re-route this IRQ */
- gic_map_to_vpe(irq, mips_cm_vp_id(cpu));
+ write_gic_map_vp(irq, BIT(mips_cm_vp_id(cpu)));
/* Update the pcpu_masks */
- for (i = 0; i < min(gic_vpes, NR_CPUS); i++)
- clear_bit(irq, pcpu_masks[i].pcpu_mask);
- set_bit(irq, pcpu_masks[cpu].pcpu_mask);
+ gic_clear_pcpu_masks(irq);
+ if (read_gic_mask(irq))
+ set_bit(irq, per_cpu_ptr(pcpu_masks, cpu));
- cpumask_copy(irq_data_get_affinity_mask(d), cpumask);
irq_data_update_effective_affinity(d, cpumask_of(cpu));
spin_unlock_irqrestore(&gic_lock, flags);
- return IRQ_SET_MASK_OK_NOCOPY;
+ return IRQ_SET_MASK_OK;
}
#endif
@@ -499,8 +302,8 @@ static void gic_handle_local_int(bool chained)
unsigned long pending, masked;
unsigned int intr, virq;
- pending = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_PEND));
- masked = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_MASK));
+ pending = read_gic_vl_pend();
+ masked = read_gic_vl_mask();
bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
@@ -518,14 +321,14 @@ static void gic_mask_local_irq(struct irq_data *d)
{
int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
- gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr);
+ write_gic_vl_rmask(BIT(intr));
}
static void gic_unmask_local_irq(struct irq_data *d)
{
int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
- gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr);
+ write_gic_vl_smask(BIT(intr));
}
static struct irq_chip gic_local_irq_controller = {
@@ -542,9 +345,8 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d)
spin_lock_irqsave(&gic_lock, flags);
for (i = 0; i < gic_vpes; i++) {
- gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
- mips_cm_vp_id(i));
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr);
+ write_gic_vl_other(mips_cm_vp_id(i));
+ write_gic_vo_rmask(BIT(intr));
}
spin_unlock_irqrestore(&gic_lock, flags);
}
@@ -557,9 +359,8 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
spin_lock_irqsave(&gic_lock, flags);
for (i = 0; i < gic_vpes; i++) {
- gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
- mips_cm_vp_id(i));
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr);
+ write_gic_vl_other(mips_cm_vp_id(i));
+ write_gic_vo_smask(BIT(intr));
}
spin_unlock_irqrestore(&gic_lock, flags);
}
@@ -582,103 +383,50 @@ static void gic_irq_dispatch(struct irq_desc *desc)
gic_handle_shared_int(true);
}
-static void __init gic_basic_init(void)
-{
- unsigned int i;
-
- board_bind_eic_interrupt = &gic_bind_eic_interrupt;
-
- /* Setup defaults */
- for (i = 0; i < gic_shared_intrs; i++) {
- gic_set_polarity(i, GIC_POL_POS);
- gic_set_trigger(i, GIC_TRIG_LEVEL);
- gic_reset_mask(i);
- }
-
- for (i = 0; i < gic_vpes; i++) {
- unsigned int j;
-
- gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
- mips_cm_vp_id(i));
- for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) {
- if (!gic_local_irq_is_routable(j))
- continue;
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j);
- }
- }
-}
-
static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw)
{
int intr = GIC_HWIRQ_TO_LOCAL(hw);
- int ret = 0;
int i;
unsigned long flags;
+ u32 val;
if (!gic_local_irq_is_routable(intr))
return -EPERM;
+ if (intr > GIC_LOCAL_INT_FDC) {
+ pr_err("Invalid local IRQ %d\n", intr);
+ return -EINVAL;
+ }
+
+ if (intr == GIC_LOCAL_INT_TIMER) {
+ /* CONFIG_MIPS_CMP workaround (see __gic_init) */
+ val = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin;
+ } else {
+ val = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
+ }
+
spin_lock_irqsave(&gic_lock, flags);
for (i = 0; i < gic_vpes; i++) {
- u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin;
-
- gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
- mips_cm_vp_id(i));
-
- switch (intr) {
- case GIC_LOCAL_INT_WD:
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val);
- break;
- case GIC_LOCAL_INT_COMPARE:
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP),
- val);
- break;
- case GIC_LOCAL_INT_TIMER:
- /* CONFIG_MIPS_CMP workaround (see __gic_init) */
- val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin;
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
- val);
- break;
- case GIC_LOCAL_INT_PERFCTR:
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
- val);
- break;
- case GIC_LOCAL_INT_SWINT0:
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP),
- val);
- break;
- case GIC_LOCAL_INT_SWINT1:
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP),
- val);
- break;
- case GIC_LOCAL_INT_FDC:
- gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val);
- break;
- default:
- pr_err("Invalid local IRQ %d\n", intr);
- ret = -EINVAL;
- break;
- }
+ write_gic_vl_other(mips_cm_vp_id(i));
+ write_gic_vo_map(intr, val);
}
spin_unlock_irqrestore(&gic_lock, flags);
- return ret;
+ return 0;
}
static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
- irq_hw_number_t hw, unsigned int vpe)
+ irq_hw_number_t hw, unsigned int cpu)
{
int intr = GIC_HWIRQ_TO_SHARED(hw);
unsigned long flags;
- int i;
spin_lock_irqsave(&gic_lock, flags);
- gic_map_to_pin(intr, gic_cpu_pin);
- gic_map_to_vpe(intr, mips_cm_vp_id(vpe));
- for (i = 0; i < min(gic_vpes, NR_CPUS); i++)
- clear_bit(intr, pcpu_masks[i].pcpu_mask);
- set_bit(intr, pcpu_masks[vpe].pcpu_mask);
+ write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin);
+ write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu)));
+ gic_clear_pcpu_masks(intr);
+ set_bit(intr, per_cpu_ptr(pcpu_masks, cpu));
spin_unlock_irqrestore(&gic_lock, flags);
return 0;
@@ -885,34 +633,69 @@ static const struct irq_domain_ops gic_ipi_domain_ops = {
.match = gic_ipi_domain_match,
};
-static void __init __gic_init(unsigned long gic_base_addr,
- unsigned long gic_addrspace_size,
- unsigned int cpu_vec, unsigned int irqbase,
- struct device_node *node)
+
+static int __init gic_of_init(struct device_node *node,
+ struct device_node *parent)
{
- unsigned int gicconfig, cpu;
- unsigned int v[2];
+ unsigned int cpu_vec, i, j, gicconfig, cpu, v[2];
+ unsigned long reserved;
+ phys_addr_t gic_base;
+ struct resource res;
+ size_t gic_len;
+
+ /* Find the first available CPU vector. */
+ i = 0;
+ reserved = (C_SW0 | C_SW1) >> __fls(C_SW0);
+ while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors",
+ i++, &cpu_vec))
+ reserved |= BIT(cpu_vec);
+
+ cpu_vec = find_first_zero_bit(&reserved, hweight_long(ST0_IM));
+ if (cpu_vec == hweight_long(ST0_IM)) {
+ pr_err("No CPU vectors available for GIC\n");
+ return -ENODEV;
+ }
+
+ if (of_address_to_resource(node, 0, &res)) {
+ /*
+ * Probe the CM for the GIC base address if not specified
+ * in the device-tree.
+ */
+ if (mips_cm_present()) {
+ gic_base = read_gcr_gic_base() &
+ ~CM_GCR_GIC_BASE_GICEN;
+ gic_len = 0x20000;
+ } else {
+ pr_err("Failed to get GIC memory range\n");
+ return -ENODEV;
+ }
+ } else {
+ gic_base = res.start;
+ gic_len = resource_size(&res);
+ }
- __gic_base_addr = gic_base_addr;
+ if (mips_cm_present()) {
+ write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN);
+ /* Ensure GIC region is enabled before trying to access it */
+ __sync();
+ }
- gic_base = ioremap_nocache(gic_base_addr, gic_addrspace_size);
+ mips_gic_base = ioremap_nocache(gic_base, gic_len);
- gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
- gic_shared_intrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
- GIC_SH_CONFIG_NUMINTRS_SHF;
- gic_shared_intrs = ((gic_shared_intrs + 1) * 8);
+ gicconfig = read_gic_config();
+ gic_shared_intrs = gicconfig & GIC_CONFIG_NUMINTERRUPTS;
+ gic_shared_intrs >>= __fls(GIC_CONFIG_NUMINTERRUPTS);
+ gic_shared_intrs = (gic_shared_intrs + 1) * 8;
- gic_vpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
- GIC_SH_CONFIG_NUMVPES_SHF;
+ gic_vpes = gicconfig & GIC_CONFIG_PVPS;
+ gic_vpes >>= __fls(GIC_CONFIG_PVPS);
gic_vpes = gic_vpes + 1;
if (cpu_has_veic) {
/* Set EIC mode for all VPEs */
for_each_present_cpu(cpu) {
- gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
- mips_cm_vp_id(cpu));
- gic_write(GIC_REG(VPE_OTHER, GIC_VPE_CTL),
- GIC_VPE_CTL_EIC_MODE_MSK);
+ write_gic_vl_other(mips_cm_vp_id(cpu));
+ write_gic_vo_ctl(GIC_VX_CTL_EIC);
}
/* Always use vector 1 in EIC mode */
@@ -937,9 +720,7 @@ static void __init __gic_init(unsigned long gic_base_addr,
*/
if (IS_ENABLED(CONFIG_MIPS_CMP) &&
gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) {
- timer_cpu_pin = gic_read32(GIC_REG(VPE_LOCAL,
- GIC_VPE_TIMER_MAP)) &
- GIC_MAP_MSK;
+ timer_cpu_pin = read_gic_vl_timer_map() & GIC_MAP_PIN_MAP;
irq_set_chained_handler(MIPS_CPU_IRQ_BASE +
GIC_CPU_PIN_OFFSET +
timer_cpu_pin,
@@ -950,17 +731,21 @@ static void __init __gic_init(unsigned long gic_base_addr,
}
gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS +
- gic_shared_intrs, irqbase,
+ gic_shared_intrs, 0,
&gic_irq_domain_ops, NULL);
- if (!gic_irq_domain)
- panic("Failed to add GIC IRQ domain");
+ if (!gic_irq_domain) {
+ pr_err("Failed to add GIC IRQ domain");
+ return -ENXIO;
+ }
gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain,
IRQ_DOMAIN_FLAG_IPI_PER_CPU,
GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
node, &gic_ipi_domain_ops, NULL);
- if (!gic_ipi_domain)
- panic("Failed to add GIC IPI domain");
+ if (!gic_ipi_domain) {
+ pr_err("Failed to add GIC IPI domain");
+ return -ENXIO;
+ }
irq_domain_update_bus_token(gic_ipi_domain, DOMAIN_BUS_IPI);
@@ -975,64 +760,25 @@ static void __init __gic_init(unsigned long gic_base_addr,
}
bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS);
- gic_basic_init();
-}
-
-void __init gic_init(unsigned long gic_base_addr,
- unsigned long gic_addrspace_size,
- unsigned int cpu_vec, unsigned int irqbase)
-{
- __gic_init(gic_base_addr, gic_addrspace_size, cpu_vec, irqbase, NULL);
-}
-static int __init gic_of_init(struct device_node *node,
- struct device_node *parent)
-{
- struct resource res;
- unsigned int cpu_vec, i = 0, reserved = 0;
- phys_addr_t gic_base;
- size_t gic_len;
+ board_bind_eic_interrupt = &gic_bind_eic_interrupt;
- /* Find the first available CPU vector. */
- while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors",
- i++, &cpu_vec))
- reserved |= BIT(cpu_vec);
- for (cpu_vec = 2; cpu_vec < 8; cpu_vec++) {
- if (!(reserved & BIT(cpu_vec)))
- break;
- }
- if (cpu_vec == 8) {
- pr_err("No CPU vectors available for GIC\n");
- return -ENODEV;
+ /* Setup defaults */
+ for (i = 0; i < gic_shared_intrs; i++) {
+ change_gic_pol(i, GIC_POL_ACTIVE_HIGH);
+ change_gic_trig(i, GIC_TRIG_LEVEL);
+ write_gic_rmask(BIT(i));
}
- if (of_address_to_resource(node, 0, &res)) {
- /*
- * Probe the CM for the GIC base address if not specified
- * in the device-tree.
- */
- if (mips_cm_present()) {
- gic_base = read_gcr_gic_base() &
- ~CM_GCR_GIC_BASE_GICEN_MSK;
- gic_len = 0x20000;
- } else {
- pr_err("Failed to get GIC memory range\n");
- return -ENODEV;
+ for (i = 0; i < gic_vpes; i++) {
+ write_gic_vl_other(mips_cm_vp_id(i));
+ for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) {
+ if (!gic_local_irq_is_routable(j))
+ continue;
+ write_gic_vo_rmask(BIT(j));
}
- } else {
- gic_base = res.start;
- gic_len = resource_size(&res);
}
- if (mips_cm_present()) {
- write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN_MSK);
- /* Ensure GIC region is enabled before trying to access it */
- __sync();
- }
- gic_present = true;
-
- __gic_init(gic_base, gic_len, cpu_vec, 0, node);
-
return 0;
}
IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init);