+#endif /* CONTEXT_SAVING */
+
static void __gic_irq_dispatch(void);
static inline u32 gic_read32(unsigned int reg)
@@ -105,52 +147,94 @@ static inline void gic_update_bits(unsigned int reg, unsigned long mask,
gic_write(reg, regval);
}
-static inline void gic_reset_mask(unsigned int intr)
+static inline void gic_write_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)
+static inline void gic_reset_mask(unsigned int intr)
+{
+ gic_save_shared_mask(intr, 0);
+ gic_write_reset_mask(intr);
+}
+
+static inline void gic_write_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)
+static inline void gic_set_mask(unsigned int intr)
+{
+ gic_save_shared_mask(intr, 1);
+ gic_write_set_mask(intr);
+}
+
+static inline void gic_write_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)
+static inline void gic_set_polarity(unsigned int intr, unsigned int pol)
+{
+ gic_save_shared_polarity(intr, pol);
+ gic_write_polarity(intr, pol);
+}
+
+static inline void gic_write_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)
+static inline void gic_set_trigger(unsigned int intr, unsigned int trig)
+{
+ gic_save_shared_trigger(intr, trig);
+ gic_write_trigger(intr, trig);
+}
+
+static inline void gic_write_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)
+static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual)
+{
+ gic_save_shared_dual_edge(intr, dual);
+ gic_write_dual_edge(intr, dual);
+}
+
+static inline void gic_write_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)
+static inline void gic_map_to_pin(unsigned int intr, unsigned int pin)
+{
+ gic_save_shared_pin(intr, pin);
+ gic_write_map_to_pin(intr, pin);
+}
+
+static inline void gic_write_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));
}
+static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe)
+{
+ gic_save_shared_vpe(intr, vpe);
+ gic_write_map_to_vpe(intr, vpe);
+}
+
#ifdef CONFIG_CLKSRC_MIPS_GIC
cycle_t gic_read_count(void)
{
@@ -537,6 +621,7 @@ static void gic_mask_local_irq(struct irq_data *d)
{
int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
+ gic_save_local_rmask(smp_processor_id(), (1 << intr));
gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr);
}
@@ -544,6 +629,7 @@ static void gic_unmask_local_irq(struct irq_data *d)
{
int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
+ gic_save_local_smask(smp_processor_id(), (1 << intr));
gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr);
}
@@ -561,6 +647,7 @@ 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_save_local_rmask(mips_cm_vp_id(i), 1 << intr);
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);
@@ -576,6 +663,7 @@ 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_save_local_smask(mips_cm_vp_id(i), 1 << intr);
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);
@@ -983,6 +1071,85 @@ static struct irq_domain_ops gic_ipi_domain_ops = {
.match = gic_ipi_domain_match,
};
+#ifdef CONTEXT_SAVING
+static void gic_restore_shared(void)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&gic_lock, flags);
+ for (i = 0; i < gic_shared_intrs; i++) {
+ gic_write_polarity(i, gic_shared_state[i].polarity);
+ gic_write_trigger(i, gic_shared_state[i].trigger);
+ gic_write_dual_edge(i, gic_shared_state[i].dual_edge);
+ gic_write_map_to_vpe(i, gic_shared_state[i].vpe);
+ gic_write_map_to_pin(i, gic_shared_state[i].pin);
+
+ if (gic_shared_state[i].mask)
+ gic_write_set_mask(i);
+ else
+ gic_write_reset_mask(i);
+ }
+ spin_unlock_irqrestore(&gic_lock, flags);
+}
+
+static void gic_restore_local(unsigned int vpe)
+{
+ int hw, virq, intr, mask;
+ unsigned long flags;
+
+ for (hw = 0; hw < GIC_NUM_LOCAL_INTRS; hw++) {
+ intr = GIC_LOCAL_TO_HWIRQ(hw);
+ virq = irq_linear_revmap(gic_irq_domain, intr);
+ gic_local_irq_domain_map(gic_irq_domain, virq, hw);
+ }
+
+ local_irq_save(flags);
+ gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), vpe);
+
+ /* Enable EIC mode if necessary */
+ gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_CTL), cpu_has_veic);
+
+ /* Restore interrupt masks */
+ mask = gic_local_state[vpe].mask;
+ gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), ~mask);
+ gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), mask);
+
+ local_irq_restore(flags);
+}
+#endif /* CONTEXT_SAVING */
+
+#ifdef CONFIG_MIPS_RPROC