#include <linux/irqchip/arm-gic-common.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <linux/irqchip/arm-gic-v3-prio.h>
-#include <linux/irqchip/irq-partition-percpu.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/arm-smccc.h>
#define FLAGS_WORKAROUND_ASR_ERRATUM_8601001 (1ULL << 2)
#define FLAGS_WORKAROUND_INSECURE (1ULL << 3)
-#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1)
-
static struct cpumask broken_rdists __read_mostly __maybe_unused;
struct redist_region {
u64 flags;
bool has_rss;
unsigned int ppi_nr;
- struct partition_desc **ppi_descs;
struct partition_affinity *parts;
unsigned int nr_parts;
};
+struct partition_affinity {
+ cpumask_t mask;
+ struct fwnode_handle *partition_id;
+};
+
#define T241_CHIPS_MAX 4
static void __iomem *t241_dist_base_alias[T241_CHIPS_MAX] __read_mostly;
static DEFINE_STATIC_KEY_FALSE(gic_nvidia_t241_erratum);
writeb_relaxed(prio, base + offset + index);
}
-static u32 __gic_get_ppi_index(irq_hw_number_t hwirq)
-{
- switch (__get_intid_range(hwirq)) {
- case PPI_RANGE:
- return hwirq - 16;
- case EPPI_RANGE:
- return hwirq - EPPI_BASE_INTID + 16;
- default:
- unreachable();
- }
-}
-
static int gic_irq_nmi_setup(struct irq_data *d)
{
struct irq_desc *desc = irq_to_desc(d->irq);
case GIC_IRQ_TYPE_LPI: /* LPI */
*hwirq = fwspec->param[1];
break;
- case GIC_IRQ_TYPE_PARTITION:
- *hwirq = fwspec->param[1];
- if (fwspec->param[1] >= 16)
- *hwirq += EPPI_BASE_INTID - 16;
- else
- *hwirq += 16;
- break;
default:
return -EINVAL;
}
/*
* Make it clear that broken DTs are... broken.
- * Partitioned PPIs are an unfortunate exception.
*/
- WARN_ON(*type == IRQ_TYPE_NONE &&
- fwspec->param[0] != GIC_IRQ_TYPE_PARTITION);
+ WARN_ON(*type == IRQ_TYPE_NONE);
return 0;
}
}
}
-static bool fwspec_is_partitioned_ppi(struct irq_fwspec *fwspec,
- irq_hw_number_t hwirq)
-{
- enum gic_intid_range range;
-
- if (!gic_data.ppi_descs)
- return false;
-
- if (!is_of_node(fwspec->fwnode))
- return false;
-
- if (fwspec->param_count < 4 || !fwspec->param[3])
- return false;
-
- range = __get_intid_range(hwirq);
- if (range != PPI_RANGE && range != EPPI_RANGE)
- return false;
-
- return true;
-}
-
static int gic_irq_domain_select(struct irq_domain *d,
struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token)
{
- unsigned int type, ppi_idx;
irq_hw_number_t hwirq;
+ unsigned int type;
int ret;
/* Not for us */
if (WARN_ON_ONCE(ret))
return 0;
- if (!fwspec_is_partitioned_ppi(fwspec, hwirq))
- return d == gic_data.domain;
-
- /*
- * If this is a PPI and we have a 4th (non-null) parameter,
- * then we need to match the partition domain.
- */
- ppi_idx = __gic_get_ppi_index(hwirq);
- return d == partition_get_domain(gic_data.ppi_descs[ppi_idx]);
+ return d == gic_data.domain;
}
static int gic_irq_get_fwspec_info(struct irq_fwspec *fwspec, struct irq_fwspec_info *info)
.get_fwspec_info = gic_irq_get_fwspec_info,
};
-static int partition_domain_translate(struct irq_domain *d,
- struct irq_fwspec *fwspec,
- unsigned long *hwirq,
- unsigned int *type)
-{
- unsigned long ppi_intid;
- struct device_node *np;
- unsigned int ppi_idx;
- int ret;
-
- if (!gic_data.ppi_descs)
- return -ENOMEM;
-
- np = of_find_node_by_phandle(fwspec->param[3]);
- if (WARN_ON(!np))
- return -EINVAL;
-
- ret = gic_irq_domain_translate(d, fwspec, &ppi_intid, type);
- if (WARN_ON_ONCE(ret))
- return 0;
-
- ppi_idx = __gic_get_ppi_index(ppi_intid);
- ret = partition_translate_id(gic_data.ppi_descs[ppi_idx],
- of_fwnode_handle(np));
- if (ret < 0)
- return ret;
-
- *hwirq = ret;
- *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
-
- return 0;
-}
-
-static const struct irq_domain_ops partition_domain_ops = {
- .translate = partition_domain_translate,
- .select = gic_irq_domain_select,
- .get_fwspec_info = gic_irq_get_fwspec_info,
-};
-
static bool gic_enable_quirk_msm8996(void *data)
{
struct gic_chip_data *d = data;
if (!parts_node)
return;
- gic_data.ppi_descs = kcalloc(gic_data.ppi_nr, sizeof(*gic_data.ppi_descs), GFP_KERNEL);
- if (!gic_data.ppi_descs)
- goto out_put_node;
-
nr_parts = of_get_child_count(parts_node);
-
if (!nr_parts)
goto out_put_node;
gic_data.parts = parts;
gic_data.nr_parts = nr_parts;
- for (i = 0; i < gic_data.ppi_nr; i++) {
- unsigned int irq;
- struct partition_desc *desc;
- struct irq_fwspec ppi_fwspec = {
- .fwnode = gic_data.fwnode,
- .param_count = 3,
- .param = {
- [0] = GIC_IRQ_TYPE_PARTITION,
- [1] = i,
- [2] = IRQ_TYPE_NONE,
- },
- };
-
- irq = irq_create_fwspec_mapping(&ppi_fwspec);
- if (WARN_ON(!irq))
- continue;
- desc = partition_create_desc(gic_data.fwnode, parts, nr_parts,
- irq, &partition_domain_ops);
- if (WARN_ON(!desc))
- continue;
-
- gic_data.ppi_descs[i] = desc;
- }
-
out_put_node:
of_node_put(parts_node);
}