Skip to content

Commit 015ec03

Browse files
author
Marc Zyngier
committed
irqchip/gic-v3-its: Add VLPI configuration handling
When a VLPI is reconfigured (enabled, disabled, change in priority), the full configuration byte must be written, and the caches invalidated. Also, when using the irq_mask/irq_unmask methods, it is necessary to disable the doorbell for that particular interrupt (by mapping it to 1023) on top of clearing the Enable bit. Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Eric Auger <eric.auger@redhat.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent d011e4e commit 015ec03

File tree

1 file changed

+70
-5
lines changed

1 file changed

+70
-5
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -812,18 +812,26 @@ static inline u32 its_get_event_id(struct irq_data *d)
812812
return d->hwirq - its_dev->event_map.lpi_base;
813813
}
814814

815-
static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)
815+
static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)
816816
{
817-
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
818-
irq_hw_number_t hwirq = d->hwirq;
817+
irq_hw_number_t hwirq;
819818
struct page *prop_page;
820819
u8 *cfg;
821820

822-
prop_page = gic_rdists->prop_page;
821+
if (irqd_is_forwarded_to_vcpu(d)) {
822+
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
823+
u32 event = its_get_event_id(d);
824+
825+
prop_page = its_dev->event_map.vm->vprop_page;
826+
hwirq = its_dev->event_map.vlpi_maps[event].vintid;
827+
} else {
828+
prop_page = gic_rdists->prop_page;
829+
hwirq = d->hwirq;
830+
}
823831

824832
cfg = page_address(prop_page) + hwirq - 8192;
825833
*cfg &= ~clr;
826-
*cfg |= set;
834+
*cfg |= set | LPI_PROP_GROUP1;
827835

828836
/*
829837
* Make the above write visible to the redistributors.
@@ -834,16 +842,52 @@ static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)
834842
gic_flush_dcache_to_poc(cfg, sizeof(*cfg));
835843
else
836844
dsb(ishst);
845+
}
846+
847+
static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)
848+
{
849+
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
850+
851+
lpi_write_config(d, clr, set);
837852
its_send_inv(its_dev, its_get_event_id(d));
838853
}
839854

855+
static void its_vlpi_set_doorbell(struct irq_data *d, bool enable)
856+
{
857+
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
858+
u32 event = its_get_event_id(d);
859+
860+
if (its_dev->event_map.vlpi_maps[event].db_enabled == enable)
861+
return;
862+
863+
its_dev->event_map.vlpi_maps[event].db_enabled = enable;
864+
865+
/*
866+
* More fun with the architecture:
867+
*
868+
* Ideally, we'd issue a VMAPTI to set the doorbell to its LPI
869+
* value or to 1023, depending on the enable bit. But that
870+
* would be issueing a mapping for an /existing/ DevID+EventID
871+
* pair, which is UNPREDICTABLE. Instead, let's issue a VMOVI
872+
* to the /same/ vPE, using this opportunity to adjust the
873+
* doorbell. Mouahahahaha. We loves it, Precious.
874+
*/
875+
its_send_vmovi(its_dev, event);
876+
}
877+
840878
static void its_mask_irq(struct irq_data *d)
841879
{
880+
if (irqd_is_forwarded_to_vcpu(d))
881+
its_vlpi_set_doorbell(d, false);
882+
842883
lpi_update_config(d, LPI_PROP_ENABLED, 0);
843884
}
844885

845886
static void its_unmask_irq(struct irq_data *d)
846887
{
888+
if (irqd_is_forwarded_to_vcpu(d))
889+
its_vlpi_set_doorbell(d, true);
890+
847891
lpi_update_config(d, 0, LPI_PROP_ENABLED);
848892
}
849893

@@ -856,6 +900,10 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
856900
struct its_collection *target_col;
857901
u32 id = its_get_event_id(d);
858902

903+
/* A forwarded interrupt should use irq_set_vcpu_affinity */
904+
if (irqd_is_forwarded_to_vcpu(d))
905+
return -EINVAL;
906+
859907
/* lpi cannot be routed to a redistributor that is on a foreign node */
860908
if (its_dev->its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
861909
if (its_dev->its->numa_node >= 0) {
@@ -1024,6 +1072,22 @@ static int its_vlpi_unmap(struct irq_data *d)
10241072
return ret;
10251073
}
10261074

1075+
static int its_vlpi_prop_update(struct irq_data *d, struct its_cmd_info *info)
1076+
{
1077+
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
1078+
1079+
if (!its_dev->event_map.vm || !irqd_is_forwarded_to_vcpu(d))
1080+
return -EINVAL;
1081+
1082+
if (info->cmd_type == PROP_UPDATE_AND_INV_VLPI)
1083+
lpi_update_config(d, 0xff, info->config);
1084+
else
1085+
lpi_write_config(d, 0xff, info->config);
1086+
its_vlpi_set_doorbell(d, !!(info->config & LPI_PROP_ENABLED));
1087+
1088+
return 0;
1089+
}
1090+
10271091
static int its_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
10281092
{
10291093
struct its_device *its_dev = irq_data_get_irq_chip_data(d);
@@ -1046,6 +1110,7 @@ static int its_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
10461110

10471111
case PROP_UPDATE_VLPI:
10481112
case PROP_UPDATE_AND_INV_VLPI:
1113+
return its_vlpi_prop_update(d, info);
10491114

10501115
default:
10511116
return -EINVAL;

0 commit comments

Comments
 (0)