7
7
#include <linux/device.h>
8
8
#include <linux/interrupt.h>
9
9
#include <linux/irq.h>
10
+ #include <linux/irqchip/irq-msi-lib.h>
10
11
#include <linux/kernel.h>
11
12
#include <linux/module.h>
12
13
#include <linux/msi.h>
@@ -174,9 +175,6 @@ static void vmd_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
174
175
msg -> arch_addr_lo .destid_0_7 = index_from_irqs (vmd , irq );
175
176
}
176
177
177
- /*
178
- * We rely on MSI_FLAG_USE_DEF_CHIP_OPS to set the IRQ mask/unmask ops.
179
- */
180
178
static void vmd_irq_enable (struct irq_data * data )
181
179
{
182
180
struct vmd_irq * vmdirq = data -> chip_data ;
@@ -186,16 +184,18 @@ static void vmd_irq_enable(struct irq_data *data)
186
184
list_add_tail_rcu (& vmdirq -> node , & vmdirq -> irq -> irq_list );
187
185
vmdirq -> enabled = true;
188
186
}
187
+ }
189
188
189
+ static void vmd_pci_msi_enable (struct irq_data * data )
190
+ {
191
+ vmd_irq_enable (data -> parent_data );
190
192
data -> chip -> irq_unmask (data );
191
193
}
192
194
193
195
static void vmd_irq_disable (struct irq_data * data )
194
196
{
195
197
struct vmd_irq * vmdirq = data -> chip_data ;
196
198
197
- data -> chip -> irq_mask (data );
198
-
199
199
scoped_guard (raw_spinlock_irqsave , & list_lock ) {
200
200
if (vmdirq -> enabled ) {
201
201
list_del_rcu (& vmdirq -> node );
@@ -204,19 +204,17 @@ static void vmd_irq_disable(struct irq_data *data)
204
204
}
205
205
}
206
206
207
+ static void vmd_pci_msi_disable (struct irq_data * data )
208
+ {
209
+ data -> chip -> irq_mask (data );
210
+ vmd_irq_disable (data -> parent_data );
211
+ }
212
+
207
213
static struct irq_chip vmd_msi_controller = {
208
214
.name = "VMD-MSI" ,
209
- .irq_enable = vmd_irq_enable ,
210
- .irq_disable = vmd_irq_disable ,
211
215
.irq_compose_msi_msg = vmd_compose_msi_msg ,
212
216
};
213
217
214
- static irq_hw_number_t vmd_get_hwirq (struct msi_domain_info * info ,
215
- msi_alloc_info_t * arg )
216
- {
217
- return 0 ;
218
- }
219
-
220
218
/*
221
219
* XXX: We can be even smarter selecting the best IRQ once we solve the
222
220
* affinity problem.
@@ -250,100 +248,118 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d
250
248
return & vmd -> irqs [best ];
251
249
}
252
250
253
- static int vmd_msi_init (struct irq_domain * domain , struct msi_domain_info * info ,
254
- unsigned int virq , irq_hw_number_t hwirq ,
255
- msi_alloc_info_t * arg )
251
+ static void vmd_msi_free (struct irq_domain * domain , unsigned int virq ,
252
+ unsigned int nr_irqs );
253
+
254
+ static int vmd_msi_alloc (struct irq_domain * domain , unsigned int virq ,
255
+ unsigned int nr_irqs , void * arg )
256
256
{
257
- struct msi_desc * desc = arg -> desc ;
258
- struct vmd_dev * vmd = vmd_from_bus ( msi_desc_to_pci_dev ( desc ) -> bus ) ;
259
- struct vmd_irq * vmdirq = kzalloc ( sizeof ( * vmdirq ), GFP_KERNEL ) ;
257
+ struct msi_desc * desc = (( msi_alloc_info_t * ) arg ) -> desc ;
258
+ struct vmd_dev * vmd = domain -> host_data ;
259
+ struct vmd_irq * vmdirq ;
260
260
261
- if (!vmdirq )
262
- return - ENOMEM ;
261
+ for (int i = 0 ; i < nr_irqs ; ++ i ) {
262
+ vmdirq = kzalloc (sizeof (* vmdirq ), GFP_KERNEL );
263
+ if (!vmdirq ) {
264
+ vmd_msi_free (domain , virq , i );
265
+ return - ENOMEM ;
266
+ }
263
267
264
- INIT_LIST_HEAD (& vmdirq -> node );
265
- vmdirq -> irq = vmd_next_irq (vmd , desc );
266
- vmdirq -> virq = virq ;
268
+ INIT_LIST_HEAD (& vmdirq -> node );
269
+ vmdirq -> irq = vmd_next_irq (vmd , desc );
270
+ vmdirq -> virq = virq + i ;
271
+
272
+ irq_domain_set_info (domain , virq + i , vmdirq -> irq -> virq ,
273
+ & vmd_msi_controller , vmdirq ,
274
+ handle_untracked_irq , vmd , NULL );
275
+ }
267
276
268
- irq_domain_set_info (domain , virq , vmdirq -> irq -> virq , info -> chip , vmdirq ,
269
- handle_untracked_irq , vmd , NULL );
270
277
return 0 ;
271
278
}
272
279
273
- static void vmd_msi_free (struct irq_domain * domain ,
274
- struct msi_domain_info * info , unsigned int virq )
280
+ static void vmd_msi_free (struct irq_domain * domain , unsigned int virq ,
281
+ unsigned int nr_irqs )
275
282
{
276
- struct vmd_irq * vmdirq = irq_get_chip_data (virq );
283
+ struct vmd_irq * vmdirq ;
284
+
285
+ for (int i = 0 ; i < nr_irqs ; ++ i ) {
286
+ vmdirq = irq_get_chip_data (virq + i );
277
287
278
- synchronize_srcu (& vmdirq -> irq -> srcu );
288
+ synchronize_srcu (& vmdirq -> irq -> srcu );
279
289
280
- /* XXX: Potential optimization to rebalance */
281
- scoped_guard (raw_spinlock_irq , & list_lock )
282
- vmdirq -> irq -> count -- ;
290
+ /* XXX: Potential optimization to rebalance */
291
+ scoped_guard (raw_spinlock_irq , & list_lock )
292
+ vmdirq -> irq -> count -- ;
283
293
284
- kfree (vmdirq );
294
+ kfree (vmdirq );
295
+ }
285
296
}
286
297
287
- static int vmd_msi_prepare (struct irq_domain * domain , struct device * dev ,
288
- int nvec , msi_alloc_info_t * arg )
298
+ static const struct irq_domain_ops vmd_msi_domain_ops = {
299
+ .alloc = vmd_msi_alloc ,
300
+ .free = vmd_msi_free ,
301
+ };
302
+
303
+ static bool vmd_init_dev_msi_info (struct device * dev , struct irq_domain * domain ,
304
+ struct irq_domain * real_parent ,
305
+ struct msi_domain_info * info )
289
306
{
290
- struct pci_dev * pdev = to_pci_dev ( dev );
291
- struct vmd_dev * vmd = vmd_from_bus ( pdev -> bus ) ;
307
+ if ( WARN_ON_ONCE ( info -> bus_token != DOMAIN_BUS_PCI_DEVICE_MSIX ))
308
+ return false ;
292
309
293
- if (nvec > vmd -> msix_count )
294
- return vmd -> msix_count ;
310
+ if (! msi_lib_init_dev_msi_info ( dev , domain , real_parent , info ) )
311
+ return false ;
295
312
296
- memset (arg , 0 , sizeof (* arg ));
297
- return 0 ;
313
+ info -> chip -> irq_enable = vmd_pci_msi_enable ;
314
+ info -> chip -> irq_disable = vmd_pci_msi_disable ;
315
+ return true;
298
316
}
299
317
300
- static void vmd_set_desc (msi_alloc_info_t * arg , struct msi_desc * desc )
301
- {
302
- arg -> desc = desc ;
303
- }
304
-
305
- static struct msi_domain_ops vmd_msi_domain_ops = {
306
- .get_hwirq = vmd_get_hwirq ,
307
- .msi_init = vmd_msi_init ,
308
- .msi_free = vmd_msi_free ,
309
- .msi_prepare = vmd_msi_prepare ,
310
- .set_desc = vmd_set_desc ,
311
- };
318
+ #define VMD_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | MSI_FLAG_PCI_MSIX)
319
+ #define VMD_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_NO_AFFINITY)
312
320
313
- static struct msi_domain_info vmd_msi_domain_info = {
314
- .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
315
- MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX ,
316
- .ops = & vmd_msi_domain_ops ,
317
- .chip = & vmd_msi_controller ,
321
+ static const struct msi_parent_ops vmd_msi_parent_ops = {
322
+ .supported_flags = VMD_MSI_FLAGS_SUPPORTED ,
323
+ .required_flags = VMD_MSI_FLAGS_REQUIRED ,
324
+ .bus_select_token = DOMAIN_BUS_VMD_MSI ,
325
+ .bus_select_mask = MATCH_PCI_MSI ,
326
+ .prefix = "VMD-" ,
327
+ .init_dev_msi_info = vmd_init_dev_msi_info ,
318
328
};
319
329
320
- static void vmd_set_msi_remapping (struct vmd_dev * vmd , bool enable )
321
- {
322
- u16 reg ;
323
-
324
- pci_read_config_word (vmd -> dev , PCI_REG_VMCONFIG , & reg );
325
- reg = enable ? (reg & ~VMCONFIG_MSI_REMAP ) :
326
- (reg | VMCONFIG_MSI_REMAP );
327
- pci_write_config_word (vmd -> dev , PCI_REG_VMCONFIG , reg );
328
- }
329
-
330
330
static int vmd_create_irq_domain (struct vmd_dev * vmd )
331
331
{
332
- struct fwnode_handle * fn ;
332
+ struct irq_domain_info info = {
333
+ .size = vmd -> msix_count ,
334
+ .ops = & vmd_msi_domain_ops ,
335
+ .host_data = vmd ,
336
+ };
333
337
334
- fn = irq_domain_alloc_named_id_fwnode ("VMD-MSI" , vmd -> sysdata .domain );
335
- if (!fn )
338
+ info .fwnode = irq_domain_alloc_named_id_fwnode ("VMD-MSI" ,
339
+ vmd -> sysdata .domain );
340
+ if (!info .fwnode )
336
341
return - ENODEV ;
337
342
338
- vmd -> irq_domain = pci_msi_create_irq_domain (fn , & vmd_msi_domain_info , NULL );
343
+ vmd -> irq_domain = msi_create_parent_irq_domain (& info ,
344
+ & vmd_msi_parent_ops );
339
345
if (!vmd -> irq_domain ) {
340
- irq_domain_free_fwnode (fn );
346
+ irq_domain_free_fwnode (info . fwnode );
341
347
return - ENODEV ;
342
348
}
343
349
344
350
return 0 ;
345
351
}
346
352
353
+ static void vmd_set_msi_remapping (struct vmd_dev * vmd , bool enable )
354
+ {
355
+ u16 reg ;
356
+
357
+ pci_read_config_word (vmd -> dev , PCI_REG_VMCONFIG , & reg );
358
+ reg = enable ? (reg & ~VMCONFIG_MSI_REMAP ) :
359
+ (reg | VMCONFIG_MSI_REMAP );
360
+ pci_write_config_word (vmd -> dev , PCI_REG_VMCONFIG , reg );
361
+ }
362
+
347
363
static void vmd_remove_irq_domain (struct vmd_dev * vmd )
348
364
{
349
365
/*
@@ -874,12 +890,6 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
874
890
ret = vmd_create_irq_domain (vmd );
875
891
if (ret )
876
892
return ret ;
877
-
878
- /*
879
- * Override the IRQ domain bus token so the domain can be
880
- * distinguished from a regular PCI/MSI domain.
881
- */
882
- irq_domain_update_bus_token (vmd -> irq_domain , DOMAIN_BUS_VMD_MSI );
883
893
} else {
884
894
vmd_set_msi_remapping (vmd , false);
885
895
}
0 commit comments