irqchip/gic-v3-its: Allow LPI invalidation via the DirectLPI interface
authorMarc Zyngier <maz@kernel.org>
Fri, 8 Nov 2019 16:57:57 +0000 (16:57 +0000)
committerMarc Zyngier <maz@kernel.org>
Sun, 10 Nov 2019 18:47:51 +0000 (18:47 +0000)
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: Marc Zyngier <maz@kernel.org>
Reviewed-by: Zenghui 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
drivers/irqchip/irq-gic-v3-its.c

index 78d3e73fc9c74e0e5825a265a614296f34b6c2d2..6065b09d6c43a4672c589e0b47e78f4153af1b07 100644 (file)
@@ -191,6 +191,12 @@ static u16 get_its_list(struct its_vm *vm)
        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,
                                               u32 event)
 {
@@ -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];
 }
 
+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)
 {
        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)
  * 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)
 {
        irq_hw_number_t hwirq;
@@ -1099,12 +1106,28 @@ static void wait_for_syncr(void __iomem *rdbase)
                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)
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
 
        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)
@@ -2935,8 +2958,9 @@ static void its_vpe_send_inv(struct irq_data *d)
        if (gic_rdists->has_direct_lpi) {
                void __iomem *rdbase;
 
+               /* Target the redistributor this VPE is currently known on */
                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);
        } else {
                its_vpe_send_cmd(vpe, its_send_inv);