mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 11:41:38 -04:00
irqchip updates for 4.15, take #2
- A number of MIPS GIC updates and cleanups - One GICv4 update - Another firmware workaround for GICv2 - Support for Mason8 GPIOs - Tiny documentation fix -----BEGIN PGP SIGNATURE----- iQJJBAABCAAzFiEEn9UcU+C1Yxj9lZw9I9DQutE9ekMFAln7UeAVHG1hcmMuenlu Z2llckBhcm0uY29tAAoJECPQ0LrRPXpDtLkQAII8Ij6h2nWN8MaSOcrOsar58PU9 gfa8HidjH7QRht5xcpaAYXO0+VO7etP37JpTlzcJfpaAU8tFTKAMJKbWaHRe2KKV YbfRYWhnyizmb2Sn5+JDKlVVPAgR9tZN9UQyDceERb4yZmGOc9nHBObJIPAYtvnr zKLPo5ldVs7bCQan+uGXMyncVGgJ70rYCNPhHqzyNbAUgkI3XA85Wk9NgBXQCr/2 8SiE6hs+QdkELy545Pi0oPxvqY5q4f2QmgOjWhQtJgbAQvWpizMi2Qz4zH8Gs89t Iln6zaw8315vfPSiyXckbIlMoUUzejLuxtvwvdgdrjE5vogNkj+Z874R3yNbLZ2H CW+DZz9gv+e2uzIiqBBpw1DatWBQQxoXvUVW1fyEOqwZPpr7JvAKwJ9Nwhc0kUdG H2AjO1KL/WqiqCpEDAYF+zY3zLUSAaoNjMWX8+nlaUstgQO4hSyPyU3RUJXmpHf8 DHIVelZlhurKjQP6SfH1QKs+Wqv2QAZb8Otb8Pt/IMw73mXmRMbMPB7uOc2A7TqG uceAQuOyVBG+QF2dGiXZ5RqTNtL1gWns+S+abJCtRkD+JV83teZw3I4sMnVpeqtO rdavJVejrePck8Tgd1qOCGfXUQrBhCG1xJFkt/Y9tWbduU0R4V1y5J7LcGBLMYSy cV5WD3fejfjayTlT =Aozt -----END PGP SIGNATURE----- Merge tag 'irqchip-4.15-2' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core Pull the second batch of irqchip updates for 4.15 from marc Zyngier: - A number of MIPS GIC updates and cleanups - One GICv4 update - Another firmware workaround for GICv2 - Support for Mason8 GPIOs - Tiny documentation fix
This commit is contained in:
commit
722c908f84
241 changed files with 3090 additions and 1903 deletions
|
|
@ -1008,9 +1008,15 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)
|
|||
if (irqd_is_forwarded_to_vcpu(d)) {
|
||||
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
|
||||
u32 event = its_get_event_id(d);
|
||||
struct its_vlpi_map *map;
|
||||
|
||||
prop_page = its_dev->event_map.vm->vprop_page;
|
||||
hwirq = its_dev->event_map.vlpi_maps[event].vintid;
|
||||
map = &its_dev->event_map.vlpi_maps[event];
|
||||
hwirq = map->vintid;
|
||||
|
||||
/* Remember the updated property */
|
||||
map->properties &= ~clr;
|
||||
map->properties |= set | LPI_PROP_GROUP1;
|
||||
} else {
|
||||
prop_page = gic_rdists->prop_page;
|
||||
hwirq = d->hwirq;
|
||||
|
|
@ -1249,12 +1255,20 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)
|
|||
/* Ensure all the VPEs are mapped on this ITS */
|
||||
its_map_vm(its_dev->its, info->map->vm);
|
||||
|
||||
/*
|
||||
* Flag the interrupt as forwarded so that we can
|
||||
* start poking the virtual property table.
|
||||
*/
|
||||
irqd_set_forwarded_to_vcpu(d);
|
||||
|
||||
/* Write out the property to the prop table */
|
||||
lpi_write_config(d, 0xff, info->map->properties);
|
||||
|
||||
/* Drop the physical mapping */
|
||||
its_send_discard(its_dev, event);
|
||||
|
||||
/* and install the virtual one */
|
||||
its_send_vmapti(its_dev, event);
|
||||
irqd_set_forwarded_to_vcpu(d);
|
||||
|
||||
/* Increment the number of VLPIs */
|
||||
its_dev->event_map.nr_vlpis++;
|
||||
|
|
|
|||
|
|
@ -1256,6 +1256,19 @@ static void gic_teardown(struct gic_chip_data *gic)
|
|||
|
||||
#ifdef CONFIG_OF
|
||||
static int gic_cnt __initdata;
|
||||
static bool gicv2_force_probe;
|
||||
|
||||
static int __init gicv2_force_probe_cfg(char *buf)
|
||||
{
|
||||
return strtobool(buf, &gicv2_force_probe);
|
||||
}
|
||||
early_param("irqchip.gicv2_force_probe", gicv2_force_probe_cfg);
|
||||
|
||||
static bool gic_check_gicv2(void __iomem *base)
|
||||
{
|
||||
u32 val = readl_relaxed(base + GIC_CPU_IDENT);
|
||||
return (val & 0xff0fff) == 0x02043B;
|
||||
}
|
||||
|
||||
static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
|
||||
{
|
||||
|
|
@ -1265,20 +1278,60 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
|
|||
|
||||
if (!is_hyp_mode_available())
|
||||
return false;
|
||||
if (resource_size(&cpuif_res) < SZ_8K)
|
||||
return false;
|
||||
if (resource_size(&cpuif_res) == SZ_128K) {
|
||||
u32 val_low, val_high;
|
||||
if (resource_size(&cpuif_res) < SZ_8K) {
|
||||
void __iomem *alt;
|
||||
/*
|
||||
* Check for a stupid firmware that only exposes the
|
||||
* first page of a GICv2.
|
||||
*/
|
||||
if (!gic_check_gicv2(*base))
|
||||
return false;
|
||||
|
||||
if (!gicv2_force_probe) {
|
||||
pr_warn("GIC: GICv2 detected, but range too small and irqchip.gicv2_force_probe not set\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
alt = ioremap(cpuif_res.start, SZ_8K);
|
||||
if (!alt)
|
||||
return false;
|
||||
if (!gic_check_gicv2(alt + SZ_4K)) {
|
||||
/*
|
||||
* The first page was that of a GICv2, and
|
||||
* the second was *something*. Let's trust it
|
||||
* to be a GICv2, and update the mapping.
|
||||
*/
|
||||
pr_warn("GIC: GICv2 at %pa, but range is too small (broken DT?), assuming 8kB\n",
|
||||
&cpuif_res.start);
|
||||
iounmap(*base);
|
||||
*base = alt;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that we have the first 4kB of a GIC400
|
||||
* We detected *two* initial GICv2 pages in a
|
||||
* row. Could be a GICv2 aliased over two 64kB
|
||||
* pages. Update the resource, map the iospace, and
|
||||
* pray.
|
||||
*/
|
||||
iounmap(alt);
|
||||
alt = ioremap(cpuif_res.start, SZ_128K);
|
||||
if (!alt)
|
||||
return false;
|
||||
pr_warn("GIC: Aliased GICv2 at %pa, trying to find the canonical range over 128kB\n",
|
||||
&cpuif_res.start);
|
||||
cpuif_res.end = cpuif_res.start + SZ_128K -1;
|
||||
iounmap(*base);
|
||||
*base = alt;
|
||||
}
|
||||
if (resource_size(&cpuif_res) == SZ_128K) {
|
||||
/*
|
||||
* Verify that we have the first 4kB of a GICv2
|
||||
* aliased over the first 64kB by checking the
|
||||
* GICC_IIDR register on both ends.
|
||||
*/
|
||||
val_low = readl_relaxed(*base + GIC_CPU_IDENT);
|
||||
val_high = readl_relaxed(*base + GIC_CPU_IDENT + 0xf000);
|
||||
if ((val_low & 0xffff0fff) != 0x0202043B ||
|
||||
val_low != val_high)
|
||||
if (!gic_check_gicv2(*base) ||
|
||||
!gic_check_gicv2(*base + 0xf000))
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ struct meson_gpio_irq_params {
|
|||
unsigned int nr_hwirq;
|
||||
};
|
||||
|
||||
static const struct meson_gpio_irq_params meson8_params = {
|
||||
.nr_hwirq = 134,
|
||||
};
|
||||
|
||||
static const struct meson_gpio_irq_params meson8b_params = {
|
||||
.nr_hwirq = 119,
|
||||
};
|
||||
|
|
@ -60,6 +64,7 @@ static const struct meson_gpio_irq_params gxl_params = {
|
|||
};
|
||||
|
||||
static const struct of_device_id meson_irq_gpio_matches[] = {
|
||||
{ .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
|
||||
{ .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
|
||||
{ .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params },
|
||||
{ .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params },
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
|
@ -48,12 +49,16 @@ static DEFINE_SPINLOCK(gic_lock);
|
|||
static struct irq_domain *gic_irq_domain;
|
||||
static struct irq_domain *gic_ipi_domain;
|
||||
static int gic_shared_intrs;
|
||||
static int gic_vpes;
|
||||
static unsigned int gic_cpu_pin;
|
||||
static unsigned int timer_cpu_pin;
|
||||
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 DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
|
||||
static DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS);
|
||||
|
||||
static struct gic_all_vpes_chip_data {
|
||||
u32 map;
|
||||
bool mask;
|
||||
} gic_all_vpes_chip_data[GIC_NUM_LOCAL_INTRS];
|
||||
|
||||
static void gic_clear_pcpu_masks(unsigned int intr)
|
||||
{
|
||||
|
|
@ -175,14 +180,13 @@ static void gic_mask_irq(struct irq_data *d)
|
|||
|
||||
static void gic_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
struct cpumask *affinity = irq_data_get_affinity_mask(d);
|
||||
unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq);
|
||||
unsigned int cpu;
|
||||
|
||||
write_gic_smask(intr);
|
||||
|
||||
gic_clear_pcpu_masks(intr);
|
||||
cpu = cpumask_first_and(affinity, cpu_online_mask);
|
||||
cpu = cpumask_first(irq_data_get_effective_affinity_mask(d));
|
||||
set_bit(intr, per_cpu_ptr(pcpu_masks, cpu));
|
||||
}
|
||||
|
||||
|
|
@ -195,46 +199,46 @@ static void gic_ack_irq(struct irq_data *d)
|
|||
|
||||
static int gic_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
|
||||
unsigned int irq, pol, trig, dual;
|
||||
unsigned long flags;
|
||||
bool is_edge;
|
||||
|
||||
irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
|
||||
|
||||
spin_lock_irqsave(&gic_lock, flags);
|
||||
switch (type & IRQ_TYPE_SENSE_MASK) {
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
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;
|
||||
pol = GIC_POL_FALLING_EDGE;
|
||||
trig = GIC_TRIG_EDGE;
|
||||
dual = GIC_DUAL_SINGLE;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
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;
|
||||
pol = GIC_POL_RISING_EDGE;
|
||||
trig = GIC_TRIG_EDGE;
|
||||
dual = GIC_DUAL_SINGLE;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
/* polarity is irrelevant in this case */
|
||||
change_gic_trig(irq, GIC_TRIG_EDGE);
|
||||
change_gic_dual(irq, GIC_DUAL_DUAL);
|
||||
is_edge = true;
|
||||
pol = 0; /* Doesn't matter */
|
||||
trig = GIC_TRIG_EDGE;
|
||||
dual = GIC_DUAL_DUAL;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
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;
|
||||
pol = GIC_POL_ACTIVE_LOW;
|
||||
trig = GIC_TRIG_LEVEL;
|
||||
dual = GIC_DUAL_SINGLE;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
default:
|
||||
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;
|
||||
pol = GIC_POL_ACTIVE_HIGH;
|
||||
trig = GIC_TRIG_LEVEL;
|
||||
dual = GIC_DUAL_SINGLE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_edge)
|
||||
change_gic_pol(irq, pol);
|
||||
change_gic_trig(irq, trig);
|
||||
change_gic_dual(irq, dual);
|
||||
|
||||
if (trig == GIC_TRIG_EDGE)
|
||||
irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller,
|
||||
handle_edge_irq, NULL);
|
||||
else
|
||||
|
|
@ -339,13 +343,17 @@ static struct irq_chip gic_local_irq_controller = {
|
|||
|
||||
static void gic_mask_local_irq_all_vpes(struct irq_data *d)
|
||||
{
|
||||
int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
||||
int i;
|
||||
struct gic_all_vpes_chip_data *cd;
|
||||
unsigned long flags;
|
||||
int intr, cpu;
|
||||
|
||||
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
||||
cd = irq_data_get_irq_chip_data(d);
|
||||
cd->mask = false;
|
||||
|
||||
spin_lock_irqsave(&gic_lock, flags);
|
||||
for (i = 0; i < gic_vpes; i++) {
|
||||
write_gic_vl_other(mips_cm_vp_id(i));
|
||||
for_each_online_cpu(cpu) {
|
||||
write_gic_vl_other(mips_cm_vp_id(cpu));
|
||||
write_gic_vo_rmask(BIT(intr));
|
||||
}
|
||||
spin_unlock_irqrestore(&gic_lock, flags);
|
||||
|
|
@ -353,22 +361,40 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d)
|
|||
|
||||
static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
|
||||
{
|
||||
int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
||||
int i;
|
||||
struct gic_all_vpes_chip_data *cd;
|
||||
unsigned long flags;
|
||||
int intr, cpu;
|
||||
|
||||
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
||||
cd = irq_data_get_irq_chip_data(d);
|
||||
cd->mask = true;
|
||||
|
||||
spin_lock_irqsave(&gic_lock, flags);
|
||||
for (i = 0; i < gic_vpes; i++) {
|
||||
write_gic_vl_other(mips_cm_vp_id(i));
|
||||
for_each_online_cpu(cpu) {
|
||||
write_gic_vl_other(mips_cm_vp_id(cpu));
|
||||
write_gic_vo_smask(BIT(intr));
|
||||
}
|
||||
spin_unlock_irqrestore(&gic_lock, flags);
|
||||
}
|
||||
|
||||
static void gic_all_vpes_irq_cpu_online(struct irq_data *d)
|
||||
{
|
||||
struct gic_all_vpes_chip_data *cd;
|
||||
unsigned int intr;
|
||||
|
||||
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
||||
cd = irq_data_get_irq_chip_data(d);
|
||||
|
||||
write_gic_vl_map(intr, cd->map);
|
||||
if (cd->mask)
|
||||
write_gic_vl_smask(BIT(intr));
|
||||
}
|
||||
|
||||
static struct irq_chip gic_all_vpes_local_irq_controller = {
|
||||
.name = "MIPS GIC Local",
|
||||
.irq_mask = gic_mask_local_irq_all_vpes,
|
||||
.irq_unmask = gic_unmask_local_irq_all_vpes,
|
||||
.name = "MIPS GIC Local",
|
||||
.irq_mask = gic_mask_local_irq_all_vpes,
|
||||
.irq_unmask = gic_unmask_local_irq_all_vpes,
|
||||
.irq_cpu_online = gic_all_vpes_irq_cpu_online,
|
||||
};
|
||||
|
||||
static void __gic_irq_dispatch(void)
|
||||
|
|
@ -383,50 +409,21 @@ static void gic_irq_dispatch(struct irq_desc *desc)
|
|||
gic_handle_shared_int(true);
|
||||
}
|
||||
|
||||
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 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++) {
|
||||
write_gic_vl_other(mips_cm_vp_id(i));
|
||||
write_gic_vo_map(intr, val);
|
||||
}
|
||||
spin_unlock_irqrestore(&gic_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hw, unsigned int cpu)
|
||||
{
|
||||
int intr = GIC_HWIRQ_TO_SHARED(hw);
|
||||
struct irq_data *data;
|
||||
unsigned long flags;
|
||||
|
||||
data = irq_get_irq_data(virq);
|
||||
|
||||
spin_lock_irqsave(&gic_lock, flags);
|
||||
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));
|
||||
irq_data_update_effective_affinity(data, cpumask_of(cpu));
|
||||
spin_unlock_irqrestore(&gic_lock, flags);
|
||||
|
||||
return 0;
|
||||
|
|
@ -454,7 +451,11 @@ static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
|
|||
static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
int err;
|
||||
struct gic_all_vpes_chip_data *cd;
|
||||
unsigned long flags;
|
||||
unsigned int intr;
|
||||
int err, cpu;
|
||||
u32 map;
|
||||
|
||||
if (hwirq >= GIC_SHARED_HWIRQ_BASE) {
|
||||
/* verify that shared irqs don't conflict with an IPI irq */
|
||||
|
|
@ -471,8 +472,14 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
|||
return gic_shared_irq_domain_map(d, virq, hwirq, 0);
|
||||
}
|
||||
|
||||
switch (GIC_HWIRQ_TO_LOCAL(hwirq)) {
|
||||
intr = GIC_HWIRQ_TO_LOCAL(hwirq);
|
||||
map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
|
||||
|
||||
switch (intr) {
|
||||
case GIC_LOCAL_INT_TIMER:
|
||||
/* CONFIG_MIPS_CMP workaround (see __gic_init) */
|
||||
map = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin;
|
||||
/* fall-through */
|
||||
case GIC_LOCAL_INT_PERFCTR:
|
||||
case GIC_LOCAL_INT_FDC:
|
||||
/*
|
||||
|
|
@ -480,9 +487,11 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
|||
* the rest of the MIPS kernel code does not use the
|
||||
* percpu IRQ API for them.
|
||||
*/
|
||||
cd = &gic_all_vpes_chip_data[intr];
|
||||
cd->map = map;
|
||||
err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
|
||||
&gic_all_vpes_local_irq_controller,
|
||||
NULL);
|
||||
cd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -501,7 +510,17 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
|||
break;
|
||||
}
|
||||
|
||||
return gic_local_irq_domain_map(d, virq, hwirq);
|
||||
if (!gic_local_irq_is_routable(intr))
|
||||
return -EPERM;
|
||||
|
||||
spin_lock_irqsave(&gic_lock, flags);
|
||||
for_each_online_cpu(cpu) {
|
||||
write_gic_vl_other(mips_cm_vp_id(cpu));
|
||||
write_gic_vo_map(intr, map);
|
||||
}
|
||||
spin_unlock_irqrestore(&gic_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
|
||||
|
|
@ -633,11 +652,25 @@ static const struct irq_domain_ops gic_ipi_domain_ops = {
|
|||
.match = gic_ipi_domain_match,
|
||||
};
|
||||
|
||||
static int gic_cpu_startup(unsigned int cpu)
|
||||
{
|
||||
/* Enable or disable EIC */
|
||||
change_gic_vl_ctl(GIC_VX_CTL_EIC,
|
||||
cpu_has_veic ? GIC_VX_CTL_EIC : 0);
|
||||
|
||||
/* Clear all local IRQ masks (ie. disable all local interrupts) */
|
||||
write_gic_vl_rmask(~0);
|
||||
|
||||
/* Invoke irq_cpu_online callbacks to enable desired interrupts */
|
||||
irq_cpu_online();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init gic_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
unsigned int cpu_vec, i, j, gicconfig, cpu, v[2];
|
||||
unsigned int cpu_vec, i, gicconfig, v[2], num_ipis;
|
||||
unsigned long reserved;
|
||||
phys_addr_t gic_base;
|
||||
struct resource res;
|
||||
|
|
@ -645,7 +678,7 @@ static int __init gic_of_init(struct device_node *node,
|
|||
|
||||
/* Find the first available CPU vector. */
|
||||
i = 0;
|
||||
reserved = (C_SW0 | C_SW1) >> __fls(C_SW0);
|
||||
reserved = (C_SW0 | C_SW1) >> __ffs(C_SW0);
|
||||
while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors",
|
||||
i++, &cpu_vec))
|
||||
reserved |= BIT(cpu_vec);
|
||||
|
|
@ -684,20 +717,10 @@ static int __init gic_of_init(struct device_node *node,
|
|||
|
||||
gicconfig = read_gic_config();
|
||||
gic_shared_intrs = gicconfig & GIC_CONFIG_NUMINTERRUPTS;
|
||||
gic_shared_intrs >>= __fls(GIC_CONFIG_NUMINTERRUPTS);
|
||||
gic_shared_intrs >>= __ffs(GIC_CONFIG_NUMINTERRUPTS);
|
||||
gic_shared_intrs = (gic_shared_intrs + 1) * 8;
|
||||
|
||||
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) {
|
||||
write_gic_vl_other(mips_cm_vp_id(cpu));
|
||||
write_gic_vo_ctl(GIC_VX_CTL_EIC);
|
||||
}
|
||||
|
||||
/* Always use vector 1 in EIC mode */
|
||||
gic_cpu_pin = 0;
|
||||
timer_cpu_pin = gic_cpu_pin;
|
||||
|
|
@ -753,10 +776,12 @@ static int __init gic_of_init(struct device_node *node,
|
|||
!of_property_read_u32_array(node, "mti,reserved-ipi-vectors", v, 2)) {
|
||||
bitmap_set(ipi_resrv, v[0], v[1]);
|
||||
} else {
|
||||
/* Make the last 2 * gic_vpes available for IPIs */
|
||||
bitmap_set(ipi_resrv,
|
||||
gic_shared_intrs - 2 * gic_vpes,
|
||||
2 * gic_vpes);
|
||||
/*
|
||||
* Reserve 2 interrupts per possible CPU/VP for use as IPIs,
|
||||
* meeting the requirements of arch/mips SMP.
|
||||
*/
|
||||
num_ipis = 2 * num_possible_cpus();
|
||||
bitmap_set(ipi_resrv, gic_shared_intrs - num_ipis, num_ipis);
|
||||
}
|
||||
|
||||
bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS);
|
||||
|
|
@ -770,15 +795,8 @@ static int __init gic_of_init(struct device_node *node,
|
|||
write_gic_rmask(i);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return cpuhp_setup_state(CPUHP_AP_IRQ_MIPS_GIC_STARTING,
|
||||
"irqchip/mips/gic:starting",
|
||||
gic_cpu_startup, NULL);
|
||||
}
|
||||
IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init);
|
||||
|
|
|
|||
Loading…
Reference in a new issue