Skip to content

Commit

Permalink
genirq/msi: Provide domain flags to allocate/free MSI descriptors aut…
Browse files Browse the repository at this point in the history
…omatically

Provide domain info flags which tell the core to allocate simple
descriptors or to free descriptors when the interrupts are freed and
implement the required functionality.

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]
  • Loading branch information
KAGA-KOKO committed Dec 16, 2021
1 parent 6029052 commit 645474e
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
17 changes: 17 additions & 0 deletions include/linux/msi.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ struct pci_msi_desc {
};
};

#define MSI_MAX_INDEX ((unsigned int)USHRT_MAX)

/**
* struct msi_desc - Descriptor structure for MSI based interrupts
* @list: List head for management
Expand Down Expand Up @@ -248,6 +250,17 @@ static inline void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
#endif /* CONFIG_PCI_MSI */

int msi_add_msi_desc(struct device *dev, struct msi_desc *init_desc);
void msi_free_msi_descs_range(struct device *dev, enum msi_desc_filter filter,
unsigned int first_index, unsigned int last_index);

/**
* msi_free_msi_descs - Free MSI descriptors of a device
* @dev: Device to free the descriptors
*/
static inline void msi_free_msi_descs(struct device *dev)
{
msi_free_msi_descs_range(dev, MSI_DESC_ALL, 0, MSI_MAX_INDEX);
}

struct msi_desc *alloc_msi_entry(struct device *dev, int nvec,
const struct irq_affinity_desc *affinity);
Expand Down Expand Up @@ -408,6 +421,10 @@ enum {
MSI_FLAG_DEV_SYSFS = (1 << 7),
/* MSI-X entries must be contiguous */
MSI_FLAG_MSIX_CONTIGUOUS = (1 << 8),
/* Allocate simple MSI descriptors */
MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS = (1 << 9),
/* Free MSI descriptors */
MSI_FLAG_FREE_MSI_DESCS = (1 << 10),
};

int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
Expand Down
48 changes: 48 additions & 0 deletions kernel/irq/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,32 @@ static int msi_add_simple_msi_descs(struct device *dev, unsigned int index, unsi
return -ENOMEM;
}

/**
* msi_free_msi_descs_range - Free MSI descriptors of a device
* @dev: Device to free the descriptors
* @filter: Descriptor state filter
* @first_index: Index to start freeing from
* @last_index: Last index to be freed
*/
void msi_free_msi_descs_range(struct device *dev, enum msi_desc_filter filter,
unsigned int first_index, unsigned int last_index)
{
struct msi_desc *desc;

lockdep_assert_held(&dev->msi.data->mutex);

msi_for_each_desc(desc, dev, filter) {
/*
* Stupid for now to handle MSI device domain until the
* storage is switched over to an xarray.
*/
if (desc->msi_index < first_index || desc->msi_index > last_index)
continue;
list_del(&desc->list);
free_msi_entry(desc);
}
}

void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
*msg = entry->msg;
Expand Down Expand Up @@ -879,6 +905,16 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
return 0;
}

static int msi_domain_add_simple_msi_descs(struct msi_domain_info *info,
struct device *dev,
unsigned int num_descs)
{
if (!(info->flags & MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS))
return 0;

return msi_add_simple_msi_descs(dev, 0, num_descs);
}

/**
* msi_domain_alloc_irqs_descs_locked - Allocate interrupts from a MSI interrupt domain
* @domain: The domain to allocate from
Expand All @@ -901,6 +937,10 @@ int msi_domain_alloc_irqs_descs_locked(struct irq_domain *domain, struct device

lockdep_assert_held(&dev->msi.data->mutex);

ret = msi_domain_add_simple_msi_descs(info, dev, nvec);
if (ret)
return ret;

ret = ops->domain_alloc_irqs(domain, dev, nvec);
if (ret)
goto cleanup;
Expand Down Expand Up @@ -962,6 +1002,13 @@ void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
}
}

static void msi_domain_free_msi_descs(struct msi_domain_info *info,
struct device *dev)
{
if (info->flags & MSI_FLAG_FREE_MSI_DESCS)
msi_free_msi_descs(dev);
}

/**
* msi_domain_free_irqs_descs_locked - Free interrupts from a MSI interrupt @domain associated to @dev
* @domain: The domain to managing the interrupts
Expand All @@ -982,6 +1029,7 @@ void msi_domain_free_irqs_descs_locked(struct irq_domain *domain, struct device
if (info->flags & MSI_FLAG_DEV_SYSFS)
msi_device_destroy_sysfs(dev);
ops->domain_free_irqs(domain, dev);
msi_domain_free_msi_descs(info, dev);
}

/**
Expand Down

0 comments on commit 645474e

Please sign in to comment.