77#include <linux/device.h>
88#include <linux/interrupt.h>
99#include <linux/irq.h>
10+ #include <linux/irqchip/irq-msi-lib.h>
1011#include <linux/kernel.h>
1112#include <linux/module.h>
1213#include <linux/msi.h>
@@ -174,9 +175,6 @@ static void vmd_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
174175 msg -> arch_addr_lo .destid_0_7 = index_from_irqs (vmd , irq );
175176}
176177
177- /*
178- * We rely on MSI_FLAG_USE_DEF_CHIP_OPS to set the IRQ mask/unmask ops.
179- */
180178static void vmd_irq_enable (struct irq_data * data )
181179{
182180 struct vmd_irq * vmdirq = data -> chip_data ;
@@ -186,16 +184,18 @@ static void vmd_irq_enable(struct irq_data *data)
186184 list_add_tail_rcu (& vmdirq -> node , & vmdirq -> irq -> irq_list );
187185 vmdirq -> enabled = true;
188186 }
187+ }
189188
189+ static void vmd_pci_msi_enable (struct irq_data * data )
190+ {
191+ vmd_irq_enable (data -> parent_data );
190192 data -> chip -> irq_unmask (data );
191193}
192194
193195static void vmd_irq_disable (struct irq_data * data )
194196{
195197 struct vmd_irq * vmdirq = data -> chip_data ;
196198
197- data -> chip -> irq_mask (data );
198-
199199 scoped_guard (raw_spinlock_irqsave , & list_lock ) {
200200 if (vmdirq -> enabled ) {
201201 list_del_rcu (& vmdirq -> node );
@@ -204,19 +204,17 @@ static void vmd_irq_disable(struct irq_data *data)
204204 }
205205}
206206
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+
207213static struct irq_chip vmd_msi_controller = {
208214 .name = "VMD-MSI" ,
209- .irq_enable = vmd_irq_enable ,
210- .irq_disable = vmd_irq_disable ,
211215 .irq_compose_msi_msg = vmd_compose_msi_msg ,
212216};
213217
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-
220218/*
221219 * XXX: We can be even smarter selecting the best IRQ once we solve the
222220 * affinity problem.
@@ -250,100 +248,118 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d
250248 return & vmd -> irqs [best ];
251249}
252250
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 )
256256{
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 ;
260260
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+ }
263267
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+ }
267276
268- irq_domain_set_info (domain , virq , vmdirq -> irq -> virq , info -> chip , vmdirq ,
269- handle_untracked_irq , vmd , NULL );
270277 return 0 ;
271278}
272279
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 )
275282{
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 );
277287
278- synchronize_srcu (& vmdirq -> irq -> srcu );
288+ synchronize_srcu (& vmdirq -> irq -> srcu );
279289
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 -- ;
283293
284- kfree (vmdirq );
294+ kfree (vmdirq );
295+ }
285296}
286297
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 )
289306{
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 ;
292309
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 ;
295312
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;
298316}
299317
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)
312320
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 ,
318328};
319329
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-
330330static int vmd_create_irq_domain (struct vmd_dev * vmd )
331331{
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+ };
333337
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 )
336341 return - ENODEV ;
337342
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 );
339345 if (!vmd -> irq_domain ) {
340- irq_domain_free_fwnode (fn );
346+ irq_domain_free_fwnode (info . fwnode );
341347 return - ENODEV ;
342348 }
343349
344350 return 0 ;
345351}
346352
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+
347363static void vmd_remove_irq_domain (struct vmd_dev * vmd )
348364{
349365 /*
@@ -874,12 +890,6 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
874890 ret = vmd_create_irq_domain (vmd );
875891 if (ret )
876892 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 );
883893 } else {
884894 vmd_set_msi_remapping (vmd , false);
885895 }
0 commit comments