Skip to content

Commit 43e9e70

Browse files
committed
irqdomain/msi: Allow to override msi_domain_alloc/free_irqs()
To support MSI irq domains which do not fit at all into the regular MSI irqdomain scheme, like the XEN MSI interrupt management for PV/HVM/DOM0, it's necessary to allow to override the alloc/free implementation. This is a preperatory step to switch X86 away from arch_*_msi_irqs() and store the irq domain pointer right in struct device. No functional change for existing MSI irq domain users. Aside of the evil XEN wrapper this is also useful for special MSI domains which need to do extra alloc/free work before/after calling the generic core function. Work like allocating/freeing MSI descriptors, MSI storage space etc. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20200826112333.526797548@linutronix.de
1 parent 70b5937 commit 43e9e70

2 files changed

Lines changed: 75 additions & 22 deletions

File tree

include/linux/msi.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,33 @@ struct msi_domain_info;
241241
* @msi_finish: Optional callback to finalize the allocation
242242
* @set_desc: Set the msi descriptor for an interrupt
243243
* @handle_error: Optional error handler if the allocation fails
244+
* @domain_alloc_irqs: Optional function to override the default allocation
245+
* function.
246+
* @domain_free_irqs: Optional function to override the default free
247+
* function.
244248
*
245249
* @get_hwirq, @msi_init and @msi_free are callbacks used by
246250
* msi_create_irq_domain() and related interfaces
247251
*
248252
* @msi_check, @msi_prepare, @msi_finish, @set_desc and @handle_error
249253
* are callbacks used by msi_domain_alloc_irqs() and related
250254
* interfaces which are based on msi_desc.
255+
*
256+
* @domain_alloc_irqs, @domain_free_irqs can be used to override the
257+
* default allocation/free functions (__msi_domain_alloc/free_irqs). This
258+
* is initially for a wrapper around XENs seperate MSI universe which can't
259+
* be wrapped into the regular irq domains concepts by mere mortals. This
260+
* allows to universally use msi_domain_alloc/free_irqs without having to
261+
* special case XEN all over the place.
262+
*
263+
* Contrary to other operations @domain_alloc_irqs and @domain_free_irqs
264+
* are set to the default implementation if NULL and even when
265+
* MSI_FLAG_USE_DEF_DOM_OPS is not set to avoid breaking existing users and
266+
* because these callbacks are obviously mandatory.
267+
*
268+
* This is NOT meant to be abused, but it can be useful to build wrappers
269+
* for specialized MSI irq domains which need extra work before and after
270+
* calling __msi_domain_alloc_irqs()/__msi_domain_free_irqs().
251271
*/
252272
struct msi_domain_ops {
253273
irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info,
@@ -270,6 +290,10 @@ struct msi_domain_ops {
270290
struct msi_desc *desc);
271291
int (*handle_error)(struct irq_domain *domain,
272292
struct msi_desc *desc, int error);
293+
int (*domain_alloc_irqs)(struct irq_domain *domain,
294+
struct device *dev, int nvec);
295+
void (*domain_free_irqs)(struct irq_domain *domain,
296+
struct device *dev);
273297
};
274298

275299
/**
@@ -327,8 +351,11 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
327351
struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
328352
struct msi_domain_info *info,
329353
struct irq_domain *parent);
354+
int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
355+
int nvec);
330356
int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
331357
int nvec);
358+
void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
332359
void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
333360
struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
334361

kernel/irq/msi.c

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,13 @@ static int msi_domain_ops_check(struct irq_domain *domain,
229229
}
230230

231231
static struct msi_domain_ops msi_domain_ops_default = {
232-
.get_hwirq = msi_domain_ops_get_hwirq,
233-
.msi_init = msi_domain_ops_init,
234-
.msi_check = msi_domain_ops_check,
235-
.msi_prepare = msi_domain_ops_prepare,
236-
.set_desc = msi_domain_ops_set_desc,
232+
.get_hwirq = msi_domain_ops_get_hwirq,
233+
.msi_init = msi_domain_ops_init,
234+
.msi_check = msi_domain_ops_check,
235+
.msi_prepare = msi_domain_ops_prepare,
236+
.set_desc = msi_domain_ops_set_desc,
237+
.domain_alloc_irqs = __msi_domain_alloc_irqs,
238+
.domain_free_irqs = __msi_domain_free_irqs,
237239
};
238240

239241
static void msi_domain_update_dom_ops(struct msi_domain_info *info)
@@ -245,6 +247,14 @@ static void msi_domain_update_dom_ops(struct msi_domain_info *info)
245247
return;
246248
}
247249

250+
if (ops->domain_alloc_irqs == NULL)
251+
ops->domain_alloc_irqs = msi_domain_ops_default.domain_alloc_irqs;
252+
if (ops->domain_free_irqs == NULL)
253+
ops->domain_free_irqs = msi_domain_ops_default.domain_free_irqs;
254+
255+
if (!(info->flags & MSI_FLAG_USE_DEF_DOM_OPS))
256+
return;
257+
248258
if (ops->get_hwirq == NULL)
249259
ops->get_hwirq = msi_domain_ops_default.get_hwirq;
250260
if (ops->msi_init == NULL)
@@ -278,8 +288,7 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
278288
{
279289
struct irq_domain *domain;
280290

281-
if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
282-
msi_domain_update_dom_ops(info);
291+
msi_domain_update_dom_ops(info);
283292
if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
284293
msi_domain_update_chip_ops(info);
285294

@@ -386,17 +395,8 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
386395
return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
387396
}
388397

389-
/**
390-
* msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
391-
* @domain: The domain to allocate from
392-
* @dev: Pointer to device struct of the device for which the interrupts
393-
* are allocated
394-
* @nvec: The number of interrupts to allocate
395-
*
396-
* Returns 0 on success or an error code.
397-
*/
398-
int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
399-
int nvec)
398+
int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
399+
int nvec)
400400
{
401401
struct msi_domain_info *info = domain->host_data;
402402
struct msi_domain_ops *ops = info->ops;
@@ -490,12 +490,24 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
490490
}
491491

492492
/**
493-
* msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
494-
* @domain: The domain to managing the interrupts
493+
* msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
494+
* @domain: The domain to allocate from
495495
* @dev: Pointer to device struct of the device for which the interrupts
496-
* are free
496+
* are allocated
497+
* @nvec: The number of interrupts to allocate
498+
*
499+
* Returns 0 on success or an error code.
497500
*/
498-
void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
501+
int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
502+
int nvec)
503+
{
504+
struct msi_domain_info *info = domain->host_data;
505+
struct msi_domain_ops *ops = info->ops;
506+
507+
return ops->domain_alloc_irqs(domain, dev, nvec);
508+
}
509+
510+
void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
499511
{
500512
struct msi_desc *desc;
501513

@@ -512,6 +524,20 @@ void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
512524
}
513525
}
514526

527+
/**
528+
* __msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
529+
* @domain: The domain to managing the interrupts
530+
* @dev: Pointer to device struct of the device for which the interrupts
531+
* are free
532+
*/
533+
void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
534+
{
535+
struct msi_domain_info *info = domain->host_data;
536+
struct msi_domain_ops *ops = info->ops;
537+
538+
return ops->domain_free_irqs(domain, dev);
539+
}
540+
515541
/**
516542
* msi_get_domain_info - Get the MSI interrupt domain info for @domain
517543
* @domain: The interrupt domain to retrieve data from

0 commit comments

Comments
 (0)