Skip to content

Commit 0f62d94

Browse files
committed
genirq/msi: Provide msi_domain_alloc/free_irqs_descs_locked()
Usage sites which do allocations of the MSI descriptors before invoking msi_domain_alloc_irqs() require to lock the MSI decriptors accross the operation. Provide entry points which can be called with the MSI mutex held and lock the mutex in the existing entry points. Signed-off-by: Thomas Gleixner <[email protected]> Tested-by: Michael Kelley <[email protected]> Tested-by: Nishanth Menon <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b5f687f commit 0f62d94

File tree

2 files changed

+61
-16
lines changed

2 files changed

+61
-16
lines changed

include/linux/msi.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,9 +383,12 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
383383
struct irq_domain *parent);
384384
int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
385385
int nvec);
386+
int msi_domain_alloc_irqs_descs_locked(struct irq_domain *domain, struct device *dev,
387+
int nvec);
386388
int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
387389
int nvec);
388390
void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
391+
void msi_domain_free_irqs_descs_locked(struct irq_domain *domain, struct device *dev);
389392
void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
390393
struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
391394

kernel/irq/msi.c

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -672,10 +672,8 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
672672
virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
673673
dev_to_node(dev), &arg, false,
674674
desc->affinity);
675-
if (virq < 0) {
676-
ret = msi_handle_pci_fail(domain, desc, allocated);
677-
goto cleanup;
678-
}
675+
if (virq < 0)
676+
return msi_handle_pci_fail(domain, desc, allocated);
679677

680678
for (i = 0; i < desc->nvec_used; i++) {
681679
irq_set_msi_desc_off(virq, i, desc);
@@ -709,7 +707,7 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
709707
}
710708
ret = irq_domain_activate_irq(irq_data, can_reserve);
711709
if (ret)
712-
goto cleanup;
710+
return ret;
713711
}
714712

715713
skip_activate:
@@ -724,38 +722,63 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
724722
}
725723
}
726724
return 0;
727-
728-
cleanup:
729-
msi_domain_free_irqs(domain, dev);
730-
return ret;
731725
}
732726

733727
/**
734-
* msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
728+
* msi_domain_alloc_irqs_descs_locked - Allocate interrupts from a MSI interrupt domain
735729
* @domain: The domain to allocate from
736730
* @dev: Pointer to device struct of the device for which the interrupts
737731
* are allocated
738732
* @nvec: The number of interrupts to allocate
739733
*
734+
* Must be invoked from within a msi_lock_descs() / msi_unlock_descs()
735+
* pair. Use this for MSI irqdomains which implement their own vector
736+
* allocation/free.
737+
*
740738
* Return: %0 on success or an error code.
741739
*/
742-
int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
743-
int nvec)
740+
int msi_domain_alloc_irqs_descs_locked(struct irq_domain *domain, struct device *dev,
741+
int nvec)
744742
{
745743
struct msi_domain_info *info = domain->host_data;
746744
struct msi_domain_ops *ops = info->ops;
747745
int ret;
748746

747+
lockdep_assert_held(&dev->msi.data->mutex);
748+
749749
ret = ops->domain_alloc_irqs(domain, dev, nvec);
750750
if (ret)
751-
return ret;
751+
goto cleanup;
752752

753753
if (!(info->flags & MSI_FLAG_DEV_SYSFS))
754754
return 0;
755755

756756
ret = msi_device_populate_sysfs(dev);
757757
if (ret)
758-
msi_domain_free_irqs(domain, dev);
758+
goto cleanup;
759+
return 0;
760+
761+
cleanup:
762+
msi_domain_free_irqs_descs_locked(domain, dev);
763+
return ret;
764+
}
765+
766+
/**
767+
* msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
768+
* @domain: The domain to allocate from
769+
* @dev: Pointer to device struct of the device for which the interrupts
770+
* are allocated
771+
* @nvec: The number of interrupts to allocate
772+
*
773+
* Return: %0 on success or an error code.
774+
*/
775+
int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, int nvec)
776+
{
777+
int ret;
778+
779+
msi_lock_descs(dev);
780+
ret = msi_domain_alloc_irqs_descs_locked(domain, dev, nvec);
781+
msi_unlock_descs(dev);
759782
return ret;
760783
}
761784

@@ -785,21 +808,40 @@ void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
785808
}
786809

787810
/**
788-
* msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated to @dev
811+
* msi_domain_free_irqs_descs_locked - Free interrupts from a MSI interrupt @domain associated to @dev
789812
* @domain: The domain to managing the interrupts
790813
* @dev: Pointer to device struct of the device for which the interrupts
791814
* are free
815+
*
816+
* Must be invoked from within a msi_lock_descs() / msi_unlock_descs()
817+
* pair. Use this for MSI irqdomains which implement their own vector
818+
* allocation.
792819
*/
793-
void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
820+
void msi_domain_free_irqs_descs_locked(struct irq_domain *domain, struct device *dev)
794821
{
795822
struct msi_domain_info *info = domain->host_data;
796823
struct msi_domain_ops *ops = info->ops;
797824

825+
lockdep_assert_held(&dev->msi.data->mutex);
826+
798827
if (info->flags & MSI_FLAG_DEV_SYSFS)
799828
msi_device_destroy_sysfs(dev);
800829
ops->domain_free_irqs(domain, dev);
801830
}
802831

832+
/**
833+
* msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated to @dev
834+
* @domain: The domain to managing the interrupts
835+
* @dev: Pointer to device struct of the device for which the interrupts
836+
* are free
837+
*/
838+
void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
839+
{
840+
msi_lock_descs(dev);
841+
msi_domain_free_irqs_descs_locked(domain, dev);
842+
msi_unlock_descs(dev);
843+
}
844+
803845
/**
804846
* msi_get_domain_info - Get the MSI interrupt domain info for @domain
805847
* @domain: The interrupt domain to retrieve data from

0 commit comments

Comments
 (0)