Skip to content

Commit b78780d

Browse files
committed
genirq/msi: Provide struct msi_parent_ops
MSI parent domains must have some control over the MSI domains which are built on top. On domain creation they need to fill in e.g. architecture specific chip callbacks or msi domain ops to make the outermost domain parent agnostic which is obviously required for architecture independence etc. The structure contains: 1) A bitfield which exposes the supported functional features. This allows to check for features and is also used in the initialization callback to mask out unsupported features when the actual domain implementation requests a broader range, e.g. on x86 PCI multi-MSI is only supported by remapping domains but not by the underlying vector domain. The PCI/MSI code can then always request multi-MSI support, but the resulting feature set after creation might not have it set. 2) An optional string prefix which is put in front of domain and chip names during creation of the MSI domain. That allows to keep the naming schemes e.g. on x86 where PCI-MSI domains have a IR- prefix when interrupt remapping is enabled. 3) An initialization callback to sanity check the domain info of the to be created MSI domain, to restrict features and to apply changes in MSI ops and interrupt chip callbacks to accomodate to the particular MSI parent implementation and/or the underlying hierarchy. Add a conveniance function to delegate the initialization from the MSI parent domain to an underlying domain in the hierarchy. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Acked-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221124232325.382485843@linutronix.de
1 parent 2d958b0 commit b78780d

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed

include/linux/irqdomain.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ struct irq_desc;
4646
struct cpumask;
4747
struct seq_file;
4848
struct irq_affinity_desc;
49+
struct msi_parent_ops;
4950

5051
#define IRQ_DOMAIN_IRQ_SPEC_PARAMS 16
5152

@@ -134,6 +135,7 @@ struct irq_domain_chip_generic;
134135
* @pm_dev: Pointer to a device that can be utilized for power management
135136
* purposes related to the irq domain.
136137
* @parent: Pointer to parent irq_domain to support hierarchy irq_domains
138+
* @msi_parent_ops: Pointer to MSI parent domain methods for per device domain init
137139
*
138140
* Revmap data, used internally by the irq domain code:
139141
* @revmap_size: Size of the linear map table @revmap[]
@@ -157,6 +159,9 @@ struct irq_domain {
157159
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
158160
struct irq_domain *parent;
159161
#endif
162+
#ifdef CONFIG_GENERIC_MSI_IRQ
163+
const struct msi_parent_ops *msi_parent_ops;
164+
#endif
160165

161166
/* reverse map data. The linear map gets appended to the irq_domain */
162167
irq_hw_number_t hwirq_max;

include/linux/msi.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,27 @@ enum {
500500

501501
};
502502

503+
/**
504+
* struct msi_parent_ops - MSI parent domain callbacks and configuration info
505+
*
506+
* @supported_flags: Required: The supported MSI flags of the parent domain
507+
* @prefix: Optional: Prefix for the domain and chip name
508+
* @init_dev_msi_info: Required: Callback for MSI parent domains to setup parent
509+
* domain specific domain flags, domain ops and interrupt chip
510+
* callbacks when a per device domain is created.
511+
*/
512+
struct msi_parent_ops {
513+
u32 supported_flags;
514+
const char *prefix;
515+
bool (*init_dev_msi_info)(struct device *dev, struct irq_domain *domain,
516+
struct irq_domain *msi_parent_domain,
517+
struct msi_domain_info *msi_child_info);
518+
};
519+
520+
bool msi_parent_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
521+
struct irq_domain *msi_parent_domain,
522+
struct msi_domain_info *msi_child_info);
523+
503524
int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
504525
bool force);
505526

kernel/irq/msi.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,47 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
788788
return domain;
789789
}
790790

791+
/**
792+
* msi_parent_init_dev_msi_info - Delegate initialization of device MSI info down
793+
* in the domain hierarchy
794+
* @dev: The device for which the domain should be created
795+
* @domain: The domain in the hierarchy this op is being called on
796+
* @msi_parent_domain: The IRQ_DOMAIN_FLAG_MSI_PARENT domain for the child to
797+
* be created
798+
* @msi_child_info: The MSI domain info of the IRQ_DOMAIN_FLAG_MSI_DEVICE
799+
* domain to be created
800+
*
801+
* Return: true on success, false otherwise
802+
*
803+
* This is the most complex problem of per device MSI domains and the
804+
* underlying interrupt domain hierarchy:
805+
*
806+
* The device domain to be initialized requests the broadest feature set
807+
* possible and the underlying domain hierarchy puts restrictions on it.
808+
*
809+
* That's trivial for a simple parent->child relationship, but it gets
810+
* interesting with an intermediate domain: root->parent->child. The
811+
* intermediate 'parent' can expand the capabilities which the 'root'
812+
* domain is providing. So that creates a classic hen and egg problem:
813+
* Which entity is doing the restrictions/expansions?
814+
*
815+
* One solution is to let the root domain handle the initialization that's
816+
* why there is the @domain and the @msi_parent_domain pointer.
817+
*/
818+
bool msi_parent_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
819+
struct irq_domain *msi_parent_domain,
820+
struct msi_domain_info *msi_child_info)
821+
{
822+
struct irq_domain *parent = domain->parent;
823+
824+
if (WARN_ON_ONCE(!parent || !parent->msi_parent_ops ||
825+
!parent->msi_parent_ops->init_dev_msi_info))
826+
return false;
827+
828+
return parent->msi_parent_ops->init_dev_msi_info(dev, parent, msi_parent_domain,
829+
msi_child_info);
830+
}
831+
791832
int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
792833
int nvec, msi_alloc_info_t *arg)
793834
{

0 commit comments

Comments
 (0)