@@ -812,18 +812,26 @@ static inline u32 its_get_event_id(struct irq_data *d)
812
812
return d -> hwirq - its_dev -> event_map .lpi_base ;
813
813
}
814
814
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 )
816
816
{
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 ;
819
818
struct page * prop_page ;
820
819
u8 * cfg ;
821
820
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
+ }
823
831
824
832
cfg = page_address (prop_page ) + hwirq - 8192 ;
825
833
* cfg &= ~clr ;
826
- * cfg |= set ;
834
+ * cfg |= set | LPI_PROP_GROUP1 ;
827
835
828
836
/*
829
837
* 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)
834
842
gic_flush_dcache_to_poc (cfg , sizeof (* cfg ));
835
843
else
836
844
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 );
837
852
its_send_inv (its_dev , its_get_event_id (d ));
838
853
}
839
854
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
+
840
878
static void its_mask_irq (struct irq_data * d )
841
879
{
880
+ if (irqd_is_forwarded_to_vcpu (d ))
881
+ its_vlpi_set_doorbell (d , false);
882
+
842
883
lpi_update_config (d , LPI_PROP_ENABLED , 0 );
843
884
}
844
885
845
886
static void its_unmask_irq (struct irq_data * d )
846
887
{
888
+ if (irqd_is_forwarded_to_vcpu (d ))
889
+ its_vlpi_set_doorbell (d , true);
890
+
847
891
lpi_update_config (d , 0 , LPI_PROP_ENABLED );
848
892
}
849
893
@@ -856,6 +900,10 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
856
900
struct its_collection * target_col ;
857
901
u32 id = its_get_event_id (d );
858
902
903
+ /* A forwarded interrupt should use irq_set_vcpu_affinity */
904
+ if (irqd_is_forwarded_to_vcpu (d ))
905
+ return - EINVAL ;
906
+
859
907
/* lpi cannot be routed to a redistributor that is on a foreign node */
860
908
if (its_dev -> its -> flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144 ) {
861
909
if (its_dev -> its -> numa_node >= 0 ) {
@@ -1024,6 +1072,22 @@ static int its_vlpi_unmap(struct irq_data *d)
1024
1072
return ret ;
1025
1073
}
1026
1074
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
+
1027
1091
static int its_irq_set_vcpu_affinity (struct irq_data * d , void * vcpu_info )
1028
1092
{
1029
1093
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)
1046
1110
1047
1111
case PROP_UPDATE_VLPI :
1048
1112
case PROP_UPDATE_AND_INV_VLPI :
1113
+ return its_vlpi_prop_update (d , info );
1049
1114
1050
1115
default :
1051
1116
return - EINVAL ;
0 commit comments