diff options
-rw-r--r-- | include/linux/msi.h | 19 | ||||
-rw-r--r-- | kernel/irq/msi.c | 58 |
2 files changed, 65 insertions, 12 deletions
diff --git a/include/linux/msi.h b/include/linux/msi.h index 35e9d0050ca1..23172d6354ca 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -301,10 +301,25 @@ static inline int msi_insert_msi_desc(struct device *dev, struct msi_desc *init_ return msi_domain_insert_msi_desc(dev, MSI_DEFAULT_DOMAIN, init_desc); } -void msi_free_msi_descs_range(struct device *dev, unsigned int first_index, unsigned int last_index); +void msi_domain_free_msi_descs_range(struct device *dev, unsigned int domid, + unsigned int first, unsigned int last); /** - * msi_free_msi_descs - Free MSI descriptors of a device + * msi_free_msi_descs_range - Free a range of MSI descriptors of a device + * in the default irqdomain + * + * @dev: Device for which to free the descriptors + * @first: Index to start freeing from (inclusive) + * @last: Last index to be freed (inclusive) + */ +static inline void msi_free_msi_descs_range(struct device *dev, unsigned int first, + unsigned int last) +{ + msi_domain_free_msi_descs_range(dev, MSI_DEFAULT_DOMAIN, first, last); +} + +/** + * msi_free_msi_descs - Free all MSI descriptors of a device in the default irqdomain * @dev: Device to free the descriptors */ static inline void msi_free_msi_descs(struct device *dev) diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index e75b07fffbcd..33ababf8645d 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -19,6 +19,18 @@ #include "internals.h" +/** + * struct msi_ctrl - MSI internal management control structure + * @domid: ID of the domain on which management operations should be done + * @first: First (hardware) slot index to operate on + * @last: Last (hardware) slot index to operate on + */ +struct msi_ctrl { + unsigned int domid; + unsigned int first; + unsigned int last; +}; + /* Invalid Xarray index which is outside of any searchable range */ #define MSI_XA_MAX_INDEX (ULONG_MAX - 1) /* The maximum domain size */ @@ -151,22 +163,29 @@ static bool msi_desc_match(struct msi_desc *desc, enum msi_desc_filter filter) return false; } -/** - * msi_free_msi_descs_range - Free MSI descriptors of a device - * @dev: Device to free the descriptors - * @first_index: Index to start freeing from - * @last_index: Last index to be freed - */ -void msi_free_msi_descs_range(struct device *dev, unsigned int first_index, - unsigned int last_index) +static bool msi_ctrl_valid(struct device *dev, struct msi_ctrl *ctrl) +{ + if (WARN_ON_ONCE(ctrl->domid >= MSI_MAX_DEVICE_IRQDOMAINS || + ctrl->first > ctrl->last || + ctrl->first > MSI_MAX_INDEX || + ctrl->last > MSI_MAX_INDEX)) + return false; + return true; +} + +static void msi_domain_free_descs(struct device *dev, struct msi_ctrl *ctrl) { - struct xarray *xa = &dev->msi.data->__domains[MSI_DEFAULT_DOMAIN].store; struct msi_desc *desc; + struct xarray *xa; unsigned long idx; lockdep_assert_held(&dev->msi.data->mutex); - xa_for_each_range(xa, idx, desc, first_index, last_index) { + if (!msi_ctrl_valid(dev, ctrl)) + return; + + xa = &dev->msi.data->__domains[ctrl->domid].store; + xa_for_each_range(xa, idx, desc, ctrl->first, ctrl->last) { xa_erase(xa, idx); /* Leak the descriptor when it is still referenced */ @@ -176,6 +195,25 @@ void msi_free_msi_descs_range(struct device *dev, unsigned int first_index, } } +/** + * msi_domain_free_msi_descs_range - Free a range of MSI descriptors of a device in an irqdomain + * @dev: Device for which to free the descriptors + * @domid: Id of the domain to operate on + * @first: Index to start freeing from (inclusive) + * @last: Last index to be freed (inclusive) + */ +void msi_domain_free_msi_descs_range(struct device *dev, unsigned int domid, + unsigned int first, unsigned int last) +{ + struct msi_ctrl ctrl = { + .domid = domid, + .first = first, + .last = last, + }; + + msi_domain_free_descs(dev, &ctrl); +} + void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { *msg = entry->msg; |