Refine generic/PCI MSI irqodmian interfaces
Subsystems (3)
v3 cover Refine generic/PCI MSI irqodmian interfaces
This patch set is based on tip/irq/irqdomain and tries to refine interfaces to support irqdomain for generic MSI and PCI MSI.
Patch 1 is just minor fixes for tip/irq/irqdomain.
Patch 2-4 introduce mechanisms to help reduce irqdomain users' code size. When converting XEN to use hierarchy irqdomain, I found the code size increases about 100 lines. So we still need helpers to reduce code size.
Patch 5 introduces some helpers to hide struct msi_desc implementation details, so later we could move msi_list from struct pci_dev into struct device to enable generic MSI support.
Patch 6 introduces msi_domain_{alloc|free}_irqs() which generalize pci_msi_domain_alloc_irqs() to support generic MSI.
Patch 7 introduces default data structures and callback implementations to support msi_domain_alloc_irqs(), so reduce burden on generic MSI users.
Patch 8 converts PCI MSI to use generic MSI interfaces, and also implement default callbacks for PCI MSI.
Patch 9 introduces a mechanism to replace arch_setup_msi_irq()/ arch_setup_msi_irqs()/arch_teardown_msi_irq()/arch_teardown_msi_irqs().
With this patch set applied, the generic MSI and PCI MSI interfaces are much easier to use. For extreme case, you only need to define a "struct msi_domain_info" and don't need to implement any callbacks, just using the default callbacks is OK:)
This patch set is also a preparation for:
1) Kill all weak functions in drivers/pci/msi.c
2) Implement support for non-PCI-compliant MSI device
It has been tested on x86 platforms, comments are welcomed!
V2->V3:
1) Refine msi_domain_ops.set_desc() and msi_domain_ops.handle_error() interfaces.V1->V2:
1) Fix bugs reported by Marc
2) Rename MSI_FLAG_USE_DEF_OPS as MSI_FLAG_USE_DEF_DOM_OPS
3) Add support of MSI_FLAG_USE_DEF_CHIP_OPS
4) Include linxu/irqhandler.h to use irq_flow_handler_t instead of "void *"
5) Change iterfaces to pass in "nvect" to msi_domain_ops.msi_prepare()
6) Add new interfaces/flags to help reduce irqdomain users' code size Jiang Liu (8):
PCI, MSI: Fix errors caused by commit e5f1a59c4e12
irqdomain: Implement a method to automatically call parent domain's
alloc/free
irqdomain: Introduce helper function irq_domain_add_hierarchy() PCI, MSI: Introduce helpers to hide struct msi_desc implementation
details
genirq: Introduce msi_domain_{alloc|free}_irqs()
genirq: Provide default callbacks for msi_domain_ops
PCI, MSI: Refine irqdomain interfaces to simplify its usage PCI, MSI: Provide mechanism to alloc/free MSI/MSIX interrupt from
irqdomain
Yingjoe Chen (1):
irqdomain: Use consistent prototype for irq_domain_free_irqs_*
drivers/pci/msi.c | 183 ++++++++++++++++++++++++++++++++++++--------- include/linux/irqdomain.h | 33 ++++---- include/linux/msi.h | 99 +++++++++++++++++++++--- kernel/irq/irqdomain.c | 93 +++++++++++++++++++++-- kernel/irq/msi.c | 175 +++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 510 insertions(+), 73 deletions(-)
Signature · 1 line
1.7.10.4
PATCH v3 1/9 PCI, MSI: Fix errors caused by commit e5f1a59c4e12
Better to fold into commit e5f1a59c4e12 ("PCI/MSI: Rename write_msi_msg() to pci_write_msi_msg()").
--- drivers/pci/msi.c | 2 +- include/linux/msi.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-)
drivers/pci/msi.c +1 -1
@@ -1084,7 +1084,7 @@ void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)* MSI message denotes a contiguous group of IRQs, written for 0th IRQ. */ if (desc->irq == irq_data->irq) -pci_write_msi_msg (desc, msg); +__pci_write_msi_msg (desc, msg); }/*
include/linux/msi.h +0 -2
@@ -44,11 +44,9 @@ struct msi_desc {struct msi_msg msg; }; -#ifdef CONFIG_PCI_MSI void __pci_read_msi_msg (struct msi_desc *entry,struct msi_msg *msg);void __pci_write_msi_msg (struct msi_desc *entry,struct msi_msg *msg);void pci_write_msi_msg (unsigned int irq,struct msi_msg *msg); -#endif /* * The arch hooks to setup up msi irqs. Those functions are
Signature · 1 line
1.7.10.4
PATCH v3 2/9 irqdomain: Use consistent prototype for irq_domain_free_irqs_*
In reply to Jiang LiuFrom: Yingjoe Chen <[email protected]>
When using irq_domain_free_irqs_top() directly in irq_domain_ops, gcc generate the following warnings:
../drivers/irqchip/irq-gic.c:879:2: warning: initialization from incompatible pointer type [enabled by default] ../drivers/irqchip/irq-gic.c:879:2: warning: (near initialization for 'gic_irq_domain_hierarchy_ops.free') [enabled by default]
Change to use consistent prototype for all irq_domain_free_irqs*
Better to fold this into "irqdomain: Introduce new interfaces to support hierarchy irqdomains".
--- include/linux/irqdomain.h | 9 +++++---- kernel/irq/irqdomain.c | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-)
include/linux/irqdomain.h +5 -4
@@ -270,12 +270,13 @@ extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq, void *handler_data, const char *handler_name);extern void irq_domain_reset_irq_data (struct irq_data *irq_data);extern void irq_domain_free_irqs_common (struct irq_domain *domain, -int virq,int nr_irqs); +unsigned int virq, +unsigned int nr_irqs);extern void irq_domain_free_irqs_top (struct irq_domain *domain, -int virq,int nr_irqs); +unsigned int virq,unsigned int nr_irqs);static inline int irq_domain_alloc_irqs_parent (struct irq_domain *domain, -int irq_base,unsigned int nr_irqs,void *arg) +unsigned int irq_base,unsigned int nr_irqs,void *arg) {if (domain->parent && domain->parent->ops->alloc) return domain->parent->ops->alloc(domain->parent, irq_base,
@@ -284,7 +285,7 @@ static inline int irq_domain_alloc_irqs_parent(struct irq_domain *domain, }static inline void irq_domain_free_irqs_parent (struct irq_domain *domain, -int irq_base,unsigned int nr_irqs) +unsigned int irq_base,unsigned int nr_irqs) {if (domain->parent && domain->parent->ops->free) domain->parent->ops->free (domain->parent, irq_base, nr_irqs);
kernel/irq/irqdomain.c +4 -4
@@ -899,8 +899,8 @@ void irq_domain_reset_irq_data(struct irq_data *irq_data) irq_data->chip_data =NULL ; } -void irq_domain_free_irqs_common (struct irq_domain *domain,int virq, -int nr_irqs) +void irq_domain_free_irqs_common (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs) {int i;struct irq_data *irq_data;
@@ -913,8 +913,8 @@ void irq_domain_free_irqs_common(struct irq_domain *domain, int virq,irq_domain_free_irqs_parent (domain, virq, nr_irqs); } -void irq_domain_free_irqs_top (struct irq_domain *domain,int virq, -int nr_irqs) +void irq_domain_free_irqs_top (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs) {int i;
Signature · 1 line
1.7.10.4
PATCH v3 3/9 irqdomain: Implement a method to automatically call parent domain's alloc/free
In reply to Jiang LiuAdd a flags to irq_domain.flags to control whether the irqdomain core should automatically call parent irqdomain's alloc/free callbacks. It help to reduce hierarchy irqdomains users' code size.
--- include/linux/irqdomain.h | 24 ++++++----------- kernel/irq/irqdomain.c | 66 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 18 deletions(-)
include/linux/irqdomain.h +8 -16
@@ -130,6 +130,8 @@ struct irq_domain { };#define IRQ_DOMAIN_FLAG_HIERARCHY 0x1 +/* Framework automatically calls parent domain's alloc()/free() */ +#define IRQ_DOMAIN_FLAG_AUTO_RECURSIVE 0x2#define IRQ_DOMAIN_FLAG_ARCH1 0x10000#ifdef CONFIG_IRQ_DOMAIN
@@ -274,22 +276,12 @@ extern void irq_domain_free_irqs_common(struct irq_domain *domain, unsigned int nr_irqs);extern void irq_domain_free_irqs_top (struct irq_domain *domain,unsigned int virq,unsigned int nr_irqs); - -static inline int irq_domain_alloc_irqs_parent (struct irq_domain *domain, -unsigned int irq_base,unsigned int nr_irqs,void *arg) -{ -if (domain->parent && domain->parent->ops->alloc) -return domain->parent->ops->alloc (domain->parent, irq_base, - nr_irqs, arg); -return -ENOSYS ; -} - -static inline void irq_domain_free_irqs_parent (struct irq_domain *domain, -unsigned int irq_base,unsigned int nr_irqs) -{ -if (domain->parent && domain->parent->ops->free) - domain->parent->ops->free (domain->parent, irq_base, nr_irqs); -} +extern int irq_domain_alloc_irqs_parent (struct irq_domain *domain, +unsigned int irq_base, +unsigned int nr_irqs,void *arg); +extern void irq_domain_free_irqs_parent (struct irq_domain *domain, +unsigned int irq_base, +unsigned int nr_irqs);static inline bool irq_domain_is_hierarchy (struct irq_domain *domain) {
kernel/irq/irqdomain.c +64 -2
90 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v3 4/9 irqdomain: Introduce helper function irq_domain_add_hierarchy()
In reply to Jiang LiuIntroduce helper function irq_domain_add_hierarchy(), which creates a linear irqdomain if parameter 'size' is not zero, otherwise creates a tree irqdomain.
--- include/linux/irqdomain.h | 4 ++++ kernel/irq/irqdomain.c | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+)
include/linux/irqdomain.h +4 -0
@@ -248,6 +248,10 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr,extern struct irq_data *irq_domain_get_irq_data (struct irq_domain *domain,unsigned int virq);#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +extern struct irq_domain *irq_domain_add_hierarchy (struct irq_domain *parent, +unsigned int flags,unsigned int size, +struct device_node *node, +const struct irq_domain_ops *ops,void *host_data);extern int __irq_domain_alloc_irqs (struct irq_domain *domain,int irq_base,unsigned int nr_irqs,int node,void *arg,bool realloc);
kernel/irq/irqdomain.c +19 -0
@@ -742,6 +742,25 @@ static int irq_domain_alloc_descs(int virq, unsigned int cnt, }#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +struct irq_domain *irq_domain_add_hierarchy (struct irq_domain *parent, +unsigned int flags,unsigned int size, +struct device_node *node, +const struct irq_domain_ops *ops,void *host_data) +{ +struct irq_domain *domain; + +if (size) + domain =irq_domain_add_linear (node, size, ops, host_data); +else + domain =irq_domain_add_tree (node, ops, host_data); +if (domain) { + domain->parent = parent; + domain->flags |= flags; + } + +return domain; +} +static void irq_domain_insert_irq (int virq) {struct irq_data *data;
Signature · 1 line
1.7.10.4
PATCH v3 5/9 PCI, MSI: Introduce helpers to hide struct msi_desc implementation details
In reply to Jiang LiuIntroduce helpers to hide struct msi_desc implementation details, so we could easily support non-PCI-compliant MSI devices later by moving msi_list into struct device.
--- include/linux/msi.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
include/linux/msi.h +19 -0
@@ -44,6 +44,25 @@ struct msi_desc {struct msi_msg msg; }; +/* Helpers to hide struct msi_desc implementation details */ +#define msi_desc_to_dev (desc) (&(desc)->dev.dev) +#define dev_to_msi_list (dev) (&to_pci_dev((dev))->msi_list) +#define first_msi_entry (dev) \ + list_first_entry(dev_to_msi_list((dev)), struct msi_desc, list) +#define for_each_msi_entry (desc, dev) \ + list_for_each_entry((desc), dev_to_msi_list((dev)), list) + +#ifdef CONFIG_PCI_MSI +#define first_pci_msi_entry (pdev) first_msi_entry(&(pdev)->dev) +#define for_each_pci_msi_entry (desc, pdev) \ + for_each_msi_entry((desc), &(pdev)->dev) + +static inline struct pci_dev *msi_desc_to_pci_dev (struct msi_desc *desc) +{ +return desc->dev; +} +#endif /* CONFIG_PCI_MSI */ +void __pci_read_msi_msg (struct msi_desc *entry,struct msi_msg *msg);void __pci_write_msi_msg (struct msi_desc *entry,struct msi_msg *msg);void pci_write_msi_msg (unsigned int irq,struct msi_msg *msg);
Signature · 1 line
1.7.10.4
PATCH v3 6/9 genirq: Introduce msi_domain_{alloc|free}_irqs()
In reply to Jiang LiuIntroduce msi_domain_{alloc|free}_irqs() to alloc/free interrupts from generic MSI irqdomain.
--- include/linux/msi.h | 39 +++++++++++++++++++++++++++++++ kernel/irq/msi.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+)
include/linux/msi.h +39 -0
@@ -3,6 +3,7 @@#include <linux/kobject.h> #include <linux/list.h> +#include <asm/hw_irq.h> /* for msi_alloc_info_t */ struct msi_msg {u32 address_lo;/* low 32 bits of msi message address */
@@ -100,7 +101,29 @@ struct irq_chip;struct device_node ;struct msi_domain_info ; +#ifndef NUM_MSI_ALLOC_SCRATCHPAD_REGS +#define NUM_MSI_ALLOC_SCRATCHPAD_REGS 2 +#endif + +/* +* Default structure for MSI interrupt allocation. +* Arch may overwrite it by defining msi_alloc_info_t. +*/ +struct msi_alloc_info { +struct msi_desc *desc; +irq_hw_number_t hwirq; +union { +unsigned long ul; +void *ptr; + } scratchpad[NUM_MSI_ALLOC_SCRATCHPAD_REGS ]; +}; + +#ifndef msi_alloc_info_t +typedef struct msi_alloc_info msi_alloc_info_t ; +#endif +struct msi_domain_ops { +/* Callbacks for msi_create_irq_domain() */ void (*calc_hwirq)(struct msi_domain_info *info,void *arg,struct msi_desc *desc);irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info,void *arg);
@@ -111,6 +134,19 @@ struct msi_domain_ops {void (*msi_free)(struct irq_domain *domain,struct msi_domain_info *info,unsigned int virq); + +/* Callbacks for msi_irq_domain_alloc_irqs() based on msi_descs */ +int (*msi_check)(struct irq_domain *domain, +struct msi_domain_info *info, +struct device *dev); +int (*msi_prepare)(struct irq_domain *domain, +struct device *dev,int nvec, +msi_alloc_info_t *arg); +void (*msi_finish)(msi_alloc_info_t *arg,int retval); +int (*set_desc)(msi_alloc_info_t *arg, +struct msi_desc *desc); +int (*handle_error)(msi_alloc_info_t *arg, +struct msi_desc *desc,int error); };struct msi_domain_info {
@@ -125,6 +161,9 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,struct irq_domain *msi_create_irq_domain (struct device_node *of_node,struct msi_domain_info *info,struct irq_domain *parent); +int msi_domain_alloc_irqs (struct irq_domain *domain,struct device *dev, +int nvec); +void msi_domain_free_irqs (struct irq_domain *domain,struct device *dev);struct msi_domain_info *msi_get_domain_info (struct irq_domain *domain);#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
kernel/irq/msi.c +63 -0
75 lines not on this page · raw message
Signature · 1 line
1.7.10.4
Re: [Patch V3 6/9] genirq: Introduce msi_domain_{alloc|free}_irqs()
Quoted 7 lines · Jiang Liu
include/linux/msi.h +7
-0+ +/* +* Default structure for MSI interrupt allocation. +* Arch may overwrite it by defining msi_alloc_info_t. +*/ +struct msi_alloc_info { +struct msi_desc *desc;
include/linux/msi.h struct irq_chip; · line 123
Quoted 10 lines
include/linux/msi.h +10
-0+irq_hw_number_t hwirq; +union { +unsigned long ul; +void *ptr; + } scratchpad[NUM_MSI_ALLOC_SCRATCHPAD_REGS ]; +}; + +#ifndef msi_alloc_info_t +typedef struct msi_alloc_info msi_alloc_info_t ; +#endif
Hmm. Do we really need that?
Thanks,
tglx
Re: [Patch V3 6/9] genirq: Introduce msi_domain_{alloc|free}_irqs()
Quoted 12 lines · Thomas Gleixner
Quoted 11 lines · Jiang Liu
include/linux/msi.h +11
-0+ +/* +* Default structure for MSI interrupt allocation. +* Arch may overwrite it by defining msi_alloc_info_t. +*/ +struct msi_alloc_info { +struct msi_desc *desc; +irq_hw_number_t hwirq; +union { +unsigned long ul; +void *ptr;
Quoted 8 lines
include/linux/msi.h struct irq_chip; · line 123
Quoted 6 lines
include/linux/msi.h +6
-0+ } scratchpad[NUM_MSI_ALLOC_SCRATCHPAD_REGS ]; +}; + +#ifndef msi_alloc_info_t +typedef struct msi_alloc_info msi_alloc_info_t ; +#endif Hmm. Do we really need that?
Hi Thomas,
Do you mean msi_alloc_info_t? It acts as a flag
to use common struct msi_alloc_info or architecture specific data structures. For most architecture, they will use the default struct msi_alloc_info. But for x86, it will use struct irq_alloc_info. Regards!
Gerry
PATCH v3 7/9 genirq: Provide default callbacks for msi_domain_ops
In reply to Jiang LiuExtend struct msi_domain_info and provide default callbacks for msi_domain_ops.
--- include/linux/msi.h | 29 ++++++++++--- kernel/irq/msi.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 132 insertions(+), 13 deletions(-)
include/linux/msi.h +24 -5
@@ -3,6 +3,7 @@#include <linux/kobject.h> #include <linux/list.h> +#include <linux/irqhandler.h> #include <asm/hw_irq.h> /* for msi_alloc_info_t */ struct msi_msg {
@@ -124,13 +125,15 @@ typedef struct msi_alloc_info msi_alloc_info_t;struct msi_domain_ops {/* Callbacks for msi_create_irq_domain() */ -void (*calc_hwirq)(struct msi_domain_info *info,void *arg, +void (*calc_hwirq)(struct msi_domain_info *info, +msi_alloc_info_t *arg,struct msi_desc *desc); -irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info,void *arg); +irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info, +msi_alloc_info_t *arg);int (*msi_init)(struct irq_domain *domain,struct msi_domain_info *info,unsigned int virq,irq_hw_number_t hwirq, -void *arg); +msi_alloc_info_t *arg);void (*msi_free)(struct irq_domain *domain,struct msi_domain_info *info,unsigned int virq);
@@ -150,15 +153,31 @@ struct msi_domain_ops { };struct msi_domain_info { +u32 flags;struct msi_domain_ops *ops;struct irq_chip *chip; -void *data; +void *chip_data;/* optional chip data */ +irq_flow_handler_t handler;/* optional flow handler */ +void *handler_data;/* optional handler data */ +const char *handler_name;/* optional handler name */ +void *data;/* optional private data */ }; +/* Use default MSI domain ops if possible */ +#define MSI_FLAG_USE_DEF_DOM_OPS 0x1 +/* Use default MSI chip ops if possible */ +#define MSI_FLAG_USE_DEF_CHIP_OPS 0x2 +/* Build identity map between hwirq and irq */ +#define MSI_FLAG_IDENTITY_MAP 0x10 +/* Support multiple PCI MSI interrupts */ +#define MSI_FLAG_MULTI_PCI_MSI 0x100 +/* Support PCI MSIX interrupts */ +#define MSI_FLAG_PCI_MSIX 0x200 +int msi_domain_set_affinity (struct irq_data *data,const struct cpumask *mask,bool force); -struct irq_domain *msi_create_irq_domain (struct device_node *of_node, +struct irq_domain *msi_create_irq_domain (struct device_node *node,struct msi_domain_info *info,struct irq_domain *parent); int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
kernel/irq/msi.c +108 -8
138 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v3 8/9 PCI, MSI: Refine irqdomain interfaces to simplify its usage
In reply to Jiang LiuRefine irqdomain interfaces to simplify its usage.
--- drivers/pci/msi.c | 121 +++++++++++++++++++++++++++++++++++++++------------ include/linux/msi.h | 13 +++--- 2 files changed, 100 insertions(+), 34 deletions(-)
drivers/pci/msi.c +92 -29
@@ -1099,38 +1099,101 @@ irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev, (pci_domain_nr (dev->bus) &0xFFFFFFFF ) <<27 ; } -int pci_msi_domain_alloc_irqs (struct irq_domain *domain,int type, -struct pci_dev *dev,void *arg) +static inline bool pci_msi_desc_is_multi_msi (struct msi_desc *desc) { -struct msi_domain_info *info = domain->host_data; -int node =dev_to_node (&dev->dev); -struct msi_desc *desc; -int i, virq; - -list_for_each_entry (desc, &dev->msi_list, list) { -if (info->ops->calc_hwirq) - info->ops->calc_hwirq (info, arg, desc); - - virq =irq_domain_alloc_irqs (domain, desc->nvec_used, - node, arg); -if (virq <0 ) { -/* Special handling for pci_enable_msi_range(). */ -if (type ==PCI_CAP_ID_MSI && desc->nvec_used >1 ) -return 1 ; -else -return -ENOSPC ; - } -for (i =0 ; i < desc->nvec_used; i++) -irq_set_msi_desc_off (virq, i, desc); - } +return !desc->msi_attrib.is_msix && desc->nvec_used >1 ; +} + +int pci_msi_domain_check_cap (struct irq_domain *domain, +struct msi_domain_info *info,struct device *dev) +{ +struct msi_desc *desc =first_pci_msi_entry (to_pci_dev (dev)); + +/* Special handling to support pci_enable_msi_range() */ +if (pci_msi_desc_is_multi_msi (desc) && + !(info->flags &MSI_FLAG_MULTI_PCI_MSI )) +return 1 ; +else if (desc->msi_attrib.is_msix && !(info->flags &MSI_FLAG_PCI_MSIX )) +return -ENOTSUPP ; -list_for_each_entry (desc, &dev->msi_list, list) -if (desc->nvec_used ==1 ) -dev_dbg (&dev->dev,"irq %d for MSI/MSI-X\n" , virq); -else -dev_dbg (&dev->dev,"irq [%d-%d] for MSI/MSI-X\n" , - virq, virq + desc->nvec_used -1 ); +return 0 ; +} + +static int pci_msi_domain_handle_error (msi_alloc_info_t *arg, +struct msi_desc *desc,int error) +{ +/* Special handling to support pci_enable_msi_range() */ +if (pci_msi_desc_is_multi_msi (desc) && error == -ENOSPC ) +return 1 ; + +return error; +} + +#ifndef msi_alloc_info_t +static int pci_msi_domain_set_desc (struct msi_alloc_info *arg, +struct msi_desc *desc) +{ + arg->desc = desc; + arg->hwirq =pci_msi_domain_calc_hwirq (msi_desc_to_pci_dev (desc), + desc);return 0 ; } +#else +#define pci_msi_domain_set_desc NULL +#endif + +static struct msi_domain_ops pci_msi_domain_ops_default = { + .set_desc = pci_msi_domain_set_desc, + .msi_check = pci_msi_domain_check_cap, + .handle_error = pci_msi_domain_handle_error, +}; + +static void pci_msi_domain_update_dom_ops (struct msi_domain_info *info) +{ +struct msi_domain_ops *ops = info->ops; + +if (ops ==NULL ) { + info->ops = &pci_msi_domain_ops_default; + }else { +if (ops->set_desc ==NULL ) + ops->set_desc = pci_msi_domain_set_desc; +if (ops->msi_check ==NULL ) + ops->msi_check = pci_msi_domain_check_cap; +if (ops->handle_error ==NULL ) + ops->handle_error = pci_msi_domain_handle_error; + } +} + +static void pci_msi_domain_update_chip_ops (struct msi_domain_info *info) +{ +struct irq_chip *chip = info->chip; + +BUG_ON (!chip); +if (!chip->irq_write_msi_msg) + chip->irq_write_msi_msg = pci_msi_domain_write_msg; +} + +struct irq_domain *pci_msi_create_irq_domain (struct device_node *node, +struct msi_domain_info *info, +struct irq_domain *parent) +{ +if (info->flags &MSI_FLAG_USE_DEF_DOM_OPS ) +pci_msi_domain_update_dom_ops (info); +if (info->flags &MSI_FLAG_USE_DEF_CHIP_OPS ) +pci_msi_domain_update_chip_ops (info); + +return msi_create_irq_domain (node, info, parent); +} + +int pci_msi_domain_alloc_irqs (struct irq_domain *domain,struct pci_dev *dev, +int nvec,int type) +{ +return msi_domain_alloc_irqs (domain, &dev->dev, nvec); +} + +void pci_msi_domain_free_irqs (struct irq_domain *domain,struct pci_dev *dev) +{ +msi_domain_free_irqs (domain, &dev->dev); +}#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
include/linux/msi.h +8 -5
@@ -125,9 +125,6 @@ typedef struct msi_alloc_info msi_alloc_info_t;struct msi_domain_ops {/* Callbacks for msi_create_irq_domain() */ -void (*calc_hwirq)(struct msi_domain_info *info, -msi_alloc_info_t *arg, -struct msi_desc *desc);irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info,msi_alloc_info_t *arg); int (*msi_init)(struct irq_domain *domain,
@@ -189,10 +186,16 @@ struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN void pci_msi_domain_write_msg (struct irq_data *irq_data,struct msi_msg *msg); -int pci_msi_domain_alloc_irqs (struct irq_domain *domain,int type, -struct pci_dev *dev,void *arg); +struct irq_domain *pci_msi_create_irq_domain (struct device_node *node, +struct msi_domain_info *info, +struct irq_domain *parent); +int pci_msi_domain_alloc_irqs (struct irq_domain *domain,struct pci_dev *dev, +int nvec,int type); +void pci_msi_domain_free_irqs (struct irq_domain *domain,struct pci_dev *dev);irq_hw_number_t pci_msi_domain_calc_hwirq (struct pci_dev *dev,struct msi_desc *desc); +int pci_msi_domain_check_cap (struct irq_domain *domain, +struct msi_domain_info *info,struct device *dev);#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */ #endif /* LINUX_MSI_H */
Signature · 1 line
1.7.10.4
PATCH v3 9/9 PCI, MSI: Provide mechanism to alloc/free MSI/MSIX interrupt from irqdomain
In reply to Jiang LiuProvide mechanism to directly alloc/free MSI/MSIX interrupt from irqdomain, which will be used to replace arch_setup_msi_irq()/ arch_setup_msi_irqs()/arch_teardown_msi_irq()/arch_teardown_msi_irqs().
To kill weak functions, this patch introduce a new weak function arch_get_pci_msi_domain(), which is to retrieve the MSI irqdomain for a PCI device. This weak function could be killed once we get a common way to associate MSI domain with PCI device.
--- drivers/pci/msi.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++---- include/linux/msi.h | 3 +++ 2 files changed, 59 insertions(+), 4 deletions(-)
drivers/pci/msi.c +56 -4
@@ -27,8 +27,41 @@ static int pci_msi_enable = 1;#define msix_table_size (flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1) -/* Arch hooks */ +#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN +static struct irq_domain *pci_msi_default_domain; + +struct irq_domain *__weak arch_get_pci_msi_domain (struct pci_dev *dev) +{ +return pci_msi_default_domain; +} + +static int pci_msi_setup_msi_irqs (struct pci_dev *dev,int nvec,int type) +{ +struct irq_domain *domain; + domain =arch_get_pci_msi_domain (dev); +if (domain) +return pci_msi_domain_alloc_irqs (domain, dev, nvec, type); + +return arch_setup_msi_irqs (dev, nvec, type); +} + +static void pci_msi_teardown_msi_irqs (struct pci_dev *dev) +{ +struct irq_domain *domain; + + domain =arch_get_pci_msi_domain (dev); +if (domain) +pci_msi_domain_free_irqs (domain, dev); +else +arch_teardown_msi_irqs (dev); +} +#else +#define pci_msi_setup_msi_irqs arch_setup_msi_irqs +#define pci_msi_teardown_msi_irqs arch_teardown_msi_irqs +#endif + +/* Arch hooks */ int __weak arch_setup_msi_irq (struct pci_dev *dev,struct msi_desc *desc) {struct msi_chip *chip = dev->bus->msi;
@@ -329,7 +362,7 @@ static void free_msi_irqs(struct pci_dev *dev)for (i =0 ; i < entry->nvec_used; i++)BUG_ON (irq_has_action (entry->irq + i)); -arch_teardown_msi_irqs (dev); +pci_msi_teardown_msi_irqs (dev);list_for_each_entry_safe (entry, tmp, &dev->msi_list, list) {if (entry->msi_attrib.is_msix) {
@@ -581,7 +614,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)list_add_tail (&entry->list, &dev->msi_list);/* Configure MSI capability structure */ - ret =arch_setup_msi_irqs (dev, nvec,PCI_CAP_ID_MSI ); + ret =pci_msi_setup_msi_irqs (dev, nvec,PCI_CAP_ID_MSI );if (ret) {msi_mask_irq (entry, mask, ~mask);free_msi_irqs (dev);
@@ -696,7 +729,7 @@ static int msix_capability_init(struct pci_dev *dev,if (ret)return ret; - ret =arch_setup_msi_irqs (dev, nvec,PCI_CAP_ID_MSIX ); + ret =pci_msi_setup_msi_irqs (dev, nvec,PCI_CAP_ID_MSIX );if (ret) goto out_avail;
@@ -1196,4 +1229,23 @@ void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev) {msi_domain_free_irqs (domain, &dev->dev); } + +struct irq_domain *pci_msi_create_default_irq_domain (struct device_node *node, +struct msi_domain_info *info,struct irq_domain *parent) +{ +struct irq_domain *domain; +static DEFINE_MUTEX (pci_msi_domain_lock); + +mutex_lock (&pci_msi_domain_lock); +if (pci_msi_default_domain) { +pr_err ("PCI: default irq domain for PCI MSI has already been created.\n" ); + domain =NULL ; + }else { + domain =pci_msi_create_irq_domain (node, info, parent); + pci_msi_default_domain = domain; + } +mutex_unlock (&pci_msi_domain_lock); + +return domain; +}#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
include/linux/msi.h +3 -0
@@ -192,6 +192,9 @@ struct irq_domain *pci_msi_create_irq_domain(struct device_node *node,int pci_msi_domain_alloc_irqs (struct irq_domain *domain,struct pci_dev *dev,int nvec,int type);void pci_msi_domain_free_irqs (struct irq_domain *domain,struct pci_dev *dev); +struct irq_domain *pci_msi_create_default_irq_domain (struct device_node *node, +struct msi_domain_info *info,struct irq_domain *parent); +irq_hw_number_t pci_msi_domain_calc_hwirq (struct pci_dev *dev,struct msi_desc *desc); int pci_msi_domain_check_cap(struct irq_domain *domain,
Signature · 1 line
1.7.10.4
Quoted 2 lines · Jiang Liu
This patch set is based on tip/irq/irqdomain and tries to refine interfaces to support irqdomain for generic MSI and PCI MSI.
So to make progress on that matter I picked that up along with a few other patches which affect the core code (more stacked irq callbacks and Marcs workaround for the handler assignment issue).
I rebased the whole lot on Bjorns pci/msi branch as discussed in this
thread: https://lkml.org/lkml/2014/11/16/292
After that I spent quite some time to reorder and fold back patches so we have no obvious wreckage, but at the same time preserve at least some of the development process for this.
Finally I added docbook comments where missing (please provide them next time yourself).
Marc ran an initial smoketest on an early iteration which did not fall into bits and pieces right away.
The only major change is that I got rid of the ugly
#ifndef msi_alloc_info_t
trickery by moving the generic version into include/asm-generic/msi.h
So if you want to use the generic version, you need to create your arch/xxx/include/asm/msi.h file which includes asm-generic/msi.h.
For the ones who want to override it, create arch/xxx/include/asm/msi.h, include whatever it takes and provide the proper typedef.
I'll send that patch (7bde31a7969f) out tomorrow morning as I want to have Arnds blessing for that.
That all is available in
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain
Note, that the branch has been rebased and is still not considered to be immutable.
So while I sorted out the pci related process with Bjorn, here is the process for this and the depending arch/xxx bits and pieces:
1) If the current content of the irq/irqdomain branch in tip does not raise eyebrows and does not require any conceptual fixups within 24 hrs from now, then I'm going to declare it immutable, merge it into next and let the arch folks depend on it.
2) If after that any updates to the core irq/pci/msi code are required they need to go through that branch first unless they are agreed on to be arch/xxx specific and can go through a different tree which is the only one which requires that.
I really rely on your cooperation here, as I don't want to end up with an unexplainable mess when the stuff hits Linus tree and he starts rumaging for his diving harpune ....
Find below the commit list based on commit c167caf8d174: PCI/MSI:
Remove useless bus->msi assignment in Bjorns pci/msi branch.
Thanks,
tglx
---2d294376193f: PCI/MSI: Allow an msi_chip to be associated to an irq domain 4888af47f51a: PCI/MSI: Provide mechanism to alloc/free MSI/MSIX interrupt from irqdomainf15c6d33c218: PCI/MSI: Enhance core to support hierarchy irqdomain 1a91b4fb79a2: PCI/MSI: Move cached entry functions to irq corec0b4a8942b6c: genirq: Provide default callbacks for msi_domain_ops 473e759918d2: genirq: Introduce msi_domain_alloc/free_irqs()7bde31a7969f: asm-generic: Add msi.h8c507b885ec3: genirq: Add generic msi irq domain supportf49d8e21319f: genirq: Introduce callback irq_chip.irq_write_msi_msg 0ac68de4f9c7: genirq: Work around __irq_set_handler vs stacked domains ordering issues 153a2674ebe9: irqdomain: Introduce helper function irq_domain_add_hierarchy() 5b15d50cfaa8: irqdomain: Implement a method to automatically call parent domains alloc/freede81049f177d: genirq: Introduce helper irq_domain_set_info() to reduce duplicated code 5447cf75ebba: genirq: Split out flow handler typedefs into seperate header file 5d7a3e203c54: genirq: Add IRQ_SET_MASK_OK_DONE to support stacked irqchipfb3577cf30b4: genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip 61454f3977d2: genirq: Add more helper functions to support stacked irq_chip 79d4a9783265: genirq: Introduce helper functions to support stacked irq_chipdf333db2e20a: irqdomain: Do irq_find_mapping and set_type for hierarchy irqdomain in case OF 3f4cac0a4ea8: irqdomain: Introduce new interfaces to support hierarchy irqdomainsf9e2d8740075: PCI/MSI: Introduce helpers to hide struct msi_desc implementation details 33190dab3a59: PCI/MSI: Rename write_msi_msg() to pci_write_msi_msg() 1da7e00b1f73: PCI/MSI: Rename __read_msi_msg() to __pci_read_msi_msg()b9191cbef61f: PCI/MSI: Kill redundant call of irq_set_msi_desc() for MSI-X interruptsdbcb4c926ece: PCI/MSI: Simplify PCI MSI code by initializing msi_desc.nvec_used earlier 6cf585318fde: PCI/MSI: Remove unnecessary braces around single statements
Quoted 11 lines · Thomas Gleixner
Quoted 2 lines · Jiang Liu
This patch set is based on tip/irq/irqdomain and tries to refine interfaces to support irqdomain for generic MSI and PCI MSI.
So to make progress on that matter I picked that up along with a few other patches which affect the core code (more stacked irq callbacks and Marcs workaround for the handler assignment issue).
I rebased the whole lot on Bjorns pci/msi branch as discussed in this
thread: https://lkml.org/lkml/2014/11/16/292
Quoted 6 lines
After that I spent quite some time to reorder and fold back patches so we have no obvious wreckage, but at the same time preserve at least some of the development process for this.
Finally I added docbook comments where missing (please provide them next time yourself).
Sure, need improvements on docs.
Quoted 8 lines
Marc ran an initial smoketest on an early iteration which did not fall into bits and pieces right away.
The only major change is that I got rid of the ugly
#ifndef
msi_alloc_info_t
Quoted 8 lines
trickery by moving the generic version into
include/asm-generic/msi.hSo if you want to use the generic version, you need to create your
arch/xxx/include/asm/msi.hfile which includesasm-generic/msi.h.For the ones who want to override it, create
arch/xxx/include/asm/msi.h, include whatever it takes and provide the proper typedef.
Two issues are solved by adding new header files, a good technique to improve code quality:)
Quoted 4 lines
I'll send that patch (
7bde31a7969f) out tomorrow morning as I want to have Arnds blessing for that.
<snip>
Quoted 3 lines
I really rely on your cooperation here, as I don't want to end up with an unexplainable mess when the stuff hits Linus tree and he starts rumaging for his diving harpune ....
I have rebased x86 changes onto tip/irq/irqdomain, it works perfectly:)
Regards!
Gerry