Commit 425c09be authored by Marc Zyngier's avatar Marc Zyngier

irqchip/gic-v3-its: Allow LPI invalidation via the DirectLPI interface

We currently don't make much use of the DirectLPI feature, and it would
be beneficial to do this more, if only because it becomes a mandatory
feature for GICv4.1.
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Reviewed-by: default avatarZenghui Yu <yuzenghui@huawei.com>
Link: https://lore.kernel.org/r/20191027144234.8395-4-maz@kernel.org
Link: https://lore.kernel.org/r/20191108165805.3071-4-maz@kernel.org
parent 2f4f064b
...@@ -191,6 +191,12 @@ static u16 get_its_list(struct its_vm *vm) ...@@ -191,6 +191,12 @@ static u16 get_its_list(struct its_vm *vm)
return (u16)its_list; return (u16)its_list;
} }
static inline u32 its_get_event_id(struct irq_data *d)
{
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
return d->hwirq - its_dev->event_map.lpi_base;
}
static struct its_collection *dev_event_to_col(struct its_device *its_dev, static struct its_collection *dev_event_to_col(struct its_device *its_dev,
u32 event) u32 event)
{ {
...@@ -199,6 +205,13 @@ static struct its_collection *dev_event_to_col(struct its_device *its_dev, ...@@ -199,6 +205,13 @@ static struct its_collection *dev_event_to_col(struct its_device *its_dev,
return its->collections + its_dev->event_map.col_map[event]; return its->collections + its_dev->event_map.col_map[event];
} }
static struct its_collection *irq_to_col(struct irq_data *d)
{
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
return dev_event_to_col(its_dev, its_get_event_id(d));
}
static struct its_collection *valid_col(struct its_collection *col) static struct its_collection *valid_col(struct its_collection *col)
{ {
if (WARN_ON_ONCE(col->target_address & GENMASK_ULL(15, 0))) if (WARN_ON_ONCE(col->target_address & GENMASK_ULL(15, 0)))
...@@ -1049,12 +1062,6 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe) ...@@ -1049,12 +1062,6 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)
* irqchip functions - assumes MSI, mostly. * irqchip functions - assumes MSI, mostly.
*/ */
static inline u32 its_get_event_id(struct irq_data *d)
{
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
return d->hwirq - its_dev->event_map.lpi_base;
}
static void lpi_write_config(struct irq_data *d, u8 clr, u8 set) static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)
{ {
irq_hw_number_t hwirq; irq_hw_number_t hwirq;
...@@ -1099,12 +1106,28 @@ static void wait_for_syncr(void __iomem *rdbase) ...@@ -1099,12 +1106,28 @@ static void wait_for_syncr(void __iomem *rdbase)
cpu_relax(); cpu_relax();
} }
static void direct_lpi_inv(struct irq_data *d)
{
struct its_collection *col;
void __iomem *rdbase;
/* Target the redistributor this LPI is currently routed to */
col = irq_to_col(d);
rdbase = per_cpu_ptr(gic_rdists->rdist, col->col_id)->rd_base;
gic_write_lpir(d->hwirq, rdbase + GICR_INVLPIR);
wait_for_syncr(rdbase);
}
static void lpi_update_config(struct irq_data *d, u8 clr, u8 set) static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)
{ {
struct its_device *its_dev = irq_data_get_irq_chip_data(d); struct its_device *its_dev = irq_data_get_irq_chip_data(d);
lpi_write_config(d, clr, set); lpi_write_config(d, clr, set);
its_send_inv(its_dev, its_get_event_id(d)); if (gic_rdists->has_direct_lpi && !irqd_is_forwarded_to_vcpu(d))
direct_lpi_inv(d);
else
its_send_inv(its_dev, its_get_event_id(d));
} }
static void its_vlpi_set_doorbell(struct irq_data *d, bool enable) static void its_vlpi_set_doorbell(struct irq_data *d, bool enable)
...@@ -2935,8 +2958,9 @@ static void its_vpe_send_inv(struct irq_data *d) ...@@ -2935,8 +2958,9 @@ static void its_vpe_send_inv(struct irq_data *d)
if (gic_rdists->has_direct_lpi) { if (gic_rdists->has_direct_lpi) {
void __iomem *rdbase; void __iomem *rdbase;
/* Target the redistributor this VPE is currently known on */
rdbase = per_cpu_ptr(gic_rdists->rdist, vpe->col_idx)->rd_base; rdbase = per_cpu_ptr(gic_rdists->rdist, vpe->col_idx)->rd_base;
gic_write_lpir(vpe->vpe_db_lpi, rdbase + GICR_INVLPIR); gic_write_lpir(d->parent_data->hwirq, rdbase + GICR_INVLPIR);
wait_for_syncr(rdbase); wait_for_syncr(rdbase);
} else { } else {
its_vpe_send_cmd(vpe, its_send_inv); its_vpe_send_cmd(vpe, its_send_inv);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment