@@ -587,12 +587,47 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
587
587
return IRQ_SET_MASK_OK_DONE ;
588
588
}
589
589
590
+ static void its_irq_compose_msi_msg (struct irq_data * d , struct msi_msg * msg )
591
+ {
592
+ struct its_device * its_dev = irq_data_get_irq_chip_data (d );
593
+ struct its_node * its ;
594
+ u64 addr ;
595
+
596
+ its = its_dev -> its ;
597
+ addr = its -> phys_base + GITS_TRANSLATER ;
598
+
599
+ msg -> address_lo = addr & ((1UL << 32 ) - 1 );
600
+ msg -> address_hi = addr >> 32 ;
601
+ msg -> data = its_get_event_id (d );
602
+ }
603
+
590
604
static struct irq_chip its_irq_chip = {
591
605
.name = "ITS" ,
592
606
.irq_mask = its_mask_irq ,
593
607
.irq_unmask = its_unmask_irq ,
594
608
.irq_eoi = its_eoi_irq ,
595
609
.irq_set_affinity = its_set_affinity ,
610
+ .irq_compose_msi_msg = its_irq_compose_msi_msg ,
611
+ };
612
+
613
+ static void its_mask_msi_irq (struct irq_data * d )
614
+ {
615
+ pci_msi_mask_irq (d );
616
+ irq_chip_mask_parent (d );
617
+ }
618
+
619
+ static void its_unmask_msi_irq (struct irq_data * d )
620
+ {
621
+ pci_msi_unmask_irq (d );
622
+ irq_chip_unmask_parent (d );
623
+ }
624
+
625
+ static struct irq_chip its_msi_irq_chip = {
626
+ .name = "ITS-MSI" ,
627
+ .irq_unmask = its_unmask_msi_irq ,
628
+ .irq_mask = its_mask_msi_irq ,
629
+ .irq_eoi = irq_chip_eoi_parent ,
630
+ .irq_write_msi_msg = pci_msi_domain_write_msg ,
596
631
};
597
632
598
633
/*
@@ -1055,3 +1090,144 @@ static void its_free_device(struct its_device *its_dev)
1055
1090
kfree (its_dev -> itt );
1056
1091
kfree (its_dev );
1057
1092
}
1093
+
1094
+ static int its_alloc_device_irq (struct its_device * dev , irq_hw_number_t * hwirq )
1095
+ {
1096
+ int idx ;
1097
+
1098
+ idx = find_first_zero_bit (dev -> lpi_map , dev -> nr_lpis );
1099
+ if (idx == dev -> nr_lpis )
1100
+ return - ENOSPC ;
1101
+
1102
+ * hwirq = dev -> lpi_base + idx ;
1103
+ set_bit (idx , dev -> lpi_map );
1104
+
1105
+ /* Map the GIC irq ID to the device */
1106
+ its_send_mapvi (dev , * hwirq , idx );
1107
+
1108
+ return 0 ;
1109
+ }
1110
+
1111
+ static int its_msi_prepare (struct irq_domain * domain , struct device * dev ,
1112
+ int nvec , msi_alloc_info_t * info )
1113
+ {
1114
+ struct pci_dev * pdev ;
1115
+ struct its_node * its ;
1116
+ u32 dev_id ;
1117
+ struct its_device * its_dev ;
1118
+
1119
+ if (!dev_is_pci (dev ))
1120
+ return - EINVAL ;
1121
+
1122
+ pdev = to_pci_dev (dev );
1123
+ dev_id = PCI_DEVID (pdev -> bus -> number , pdev -> devfn );
1124
+ its = domain -> parent -> host_data ;
1125
+
1126
+ its_dev = its_find_device (its , dev_id );
1127
+ if (WARN_ON (its_dev ))
1128
+ return - EINVAL ;
1129
+
1130
+ its_dev = its_create_device (its , dev_id , nvec );
1131
+ if (!its_dev )
1132
+ return - ENOMEM ;
1133
+
1134
+ dev_dbg (& pdev -> dev , "ITT %d entries, %d bits\n" , nvec , ilog2 (nvec ));
1135
+
1136
+ info -> scratchpad [0 ].ptr = its_dev ;
1137
+ info -> scratchpad [1 ].ptr = dev ;
1138
+ return 0 ;
1139
+ }
1140
+
1141
+ static struct msi_domain_ops its_pci_msi_ops = {
1142
+ .msi_prepare = its_msi_prepare ,
1143
+ };
1144
+
1145
+ static struct msi_domain_info its_pci_msi_domain_info = {
1146
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
1147
+ MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX ),
1148
+ .ops = & its_pci_msi_ops ,
1149
+ .chip = & its_msi_irq_chip ,
1150
+ };
1151
+
1152
+ static int its_irq_gic_domain_alloc (struct irq_domain * domain ,
1153
+ unsigned int virq ,
1154
+ irq_hw_number_t hwirq )
1155
+ {
1156
+ struct of_phandle_args args ;
1157
+
1158
+ args .np = domain -> parent -> of_node ;
1159
+ args .args_count = 3 ;
1160
+ args .args [0 ] = GIC_IRQ_TYPE_LPI ;
1161
+ args .args [1 ] = hwirq ;
1162
+ args .args [2 ] = IRQ_TYPE_EDGE_RISING ;
1163
+
1164
+ return irq_domain_alloc_irqs_parent (domain , virq , 1 , & args );
1165
+ }
1166
+
1167
+ static int its_irq_domain_alloc (struct irq_domain * domain , unsigned int virq ,
1168
+ unsigned int nr_irqs , void * args )
1169
+ {
1170
+ msi_alloc_info_t * info = args ;
1171
+ struct its_device * its_dev = info -> scratchpad [0 ].ptr ;
1172
+ irq_hw_number_t hwirq ;
1173
+ int err ;
1174
+ int i ;
1175
+
1176
+ for (i = 0 ; i < nr_irqs ; i ++ ) {
1177
+ err = its_alloc_device_irq (its_dev , & hwirq );
1178
+ if (err )
1179
+ return err ;
1180
+
1181
+ err = its_irq_gic_domain_alloc (domain , virq + i , hwirq );
1182
+ if (err )
1183
+ return err ;
1184
+
1185
+ irq_domain_set_hwirq_and_chip (domain , virq + i ,
1186
+ hwirq , & its_irq_chip , its_dev );
1187
+ dev_dbg (info -> scratchpad [1 ].ptr , "ID:%d pID:%d vID:%d\n" ,
1188
+ (int )(hwirq - its_dev -> lpi_base ), (int )hwirq , virq + i );
1189
+ }
1190
+
1191
+ return 0 ;
1192
+ }
1193
+
1194
+ static void its_irq_domain_free (struct irq_domain * domain , unsigned int virq ,
1195
+ unsigned int nr_irqs )
1196
+ {
1197
+ struct irq_data * d = irq_domain_get_irq_data (domain , virq );
1198
+ struct its_device * its_dev = irq_data_get_irq_chip_data (d );
1199
+ int i ;
1200
+
1201
+ for (i = 0 ; i < nr_irqs ; i ++ ) {
1202
+ struct irq_data * data = irq_domain_get_irq_data (domain ,
1203
+ virq + i );
1204
+ int event = its_get_event_id (data );
1205
+
1206
+ /* Stop the delivery of interrupts */
1207
+ its_send_discard (its_dev , event );
1208
+
1209
+ /* Mark interrupt index as unused */
1210
+ clear_bit (event , its_dev -> lpi_map );
1211
+
1212
+ /* Nuke the entry in the domain */
1213
+ irq_domain_reset_irq_data (d );
1214
+ }
1215
+
1216
+ /* If all interrupts have been freed, start mopping the floor */
1217
+ if (bitmap_empty (its_dev -> lpi_map , its_dev -> nr_lpis )) {
1218
+ its_lpi_free (its_dev -> lpi_map ,
1219
+ its_dev -> lpi_base ,
1220
+ its_dev -> nr_lpis );
1221
+
1222
+ /* Unmap device/itt */
1223
+ its_send_mapd (its_dev , 0 );
1224
+ its_free_device (its_dev );
1225
+ }
1226
+
1227
+ irq_domain_free_irqs_parent (domain , virq , nr_irqs );
1228
+ }
1229
+
1230
+ static const struct irq_domain_ops its_domain_ops = {
1231
+ .alloc = its_irq_domain_alloc ,
1232
+ .free = its_irq_domain_free ,
1233
+ };
0 commit comments