@@ -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+
840878static 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
845886static 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+
10271091static 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