Refine support of non-PCI-compliant Message
cover Refine support of non-PCI-compliant Message
Some interrupt controllers, such as DMAR/HPET/HT_IRQ, work almost in the same as PCI MSI interrupt controller. And there some devices make use of PCI MSI mechanism for non-PCI devices on ARm/ARM64 platforms.
So this patches tries to split PCI MSI code into PCI dependent part and PCI independent part. The PCI independent part will be used to support other PCI MSI like interrupt controllers.
Patch 1-9 are clean ups for previous hierarchy irqdomain patchset and preparation for coming PCI MSI code reorganization. Patch 10-15 split PCI MSI code and implement common mechanism to support other MSI alike interrupt contollers.
Patch 16-17 converts HT_IRQ to use the common MSI support mechanism.
This patch set only solves the issue to manage interrupt controller, but we still need another patch set to provide pci_enable_msix_range() alike interfaces to support non-PCI devices. To achieve that, we will:
1) Move msi_list from struct pci_dev into struct device
2) Abstract common code from drivers/pci/msi.c into kernel/irq/msi.c
3) Implement msi_enable_range()/msi_disable() alike interfaces.
Apparently, we need much more time to discuss the proposal for next patch set.
Hi Thomas and Bjorn,
Could you please to review patch 10,13 and give your thoughts?
Those are the main changes. This patch set only passes compilation and boot tests.
Regards!
Gerry
Jiang Liu (17):
x86, irq: Normalize x86 irq_chip name
genirq: Introduce helper irq_domain_set_info() to reduce duplicated
code
x86, PCI/MSI: Simplify the way to deal with remapped MSI interrupts PCI/MSI: Replace msi_update_msg() with irq_chip_compose_msi_msg() PCI/MSI: Move msi_set_affinity() to PCI core
genirq: Introduce callback irq_chip.irq_write_msi_msg
x86, irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET
irq_chips
PCI/MSI: Use irq_chip.irq_write_msi_msg() to share common code x86, irq: Simplify MSI/DMAR/HPET implementation by using common code PCI, MSI: Split MSI code into PCI dependent and PCI independent parts PCI, MSI: Rename __read_msi_msg() as __pci_read_msi_msg() PCI, MSI: Rename __write_msi_msg() as __pci_write_msi_msg()
MSI: Provide irqdomain support for generic MSI
x86, PCI, MSI: Use common code to manage MSI interrupts PCI, MSI: Clean up unused irqdomain related code
x86, htirq: Kill struct ht_irq_msg by reusing struct msi_msg x86, htirq: Use common MSI code to manage Hypertransport interrupts
arch/powerpc/platforms/pseries/msi.c | 2 +- arch/x86/kernel/apic/htirq.c | 137 +++++------- arch/x86/kernel/apic/msi.c | 309 ++++++++++++--------------- arch/x86/pci/xen.c | 4 +- arch/x86/platform/uv/uv_irq.c | 5 +- drivers/infiniband/hw/ipath/ipath_iba6110.c | 2 +- drivers/pci/Kconfig | 5 +- drivers/pci/htirq.c | 20 +- drivers/pci/msi.c | 144 ++----------- include/linux/htirq.h | 15 +- include/linux/irq.h | 8 + include/linux/irqdomain.h | 4 + include/linux/msi.h | 89 +++++--- kernel/irq/Kconfig | 10 +- kernel/irq/Makefile | 1 + kernel/irq/irqdomain.c | 10 + kernel/irq/msi.c | 133 ++++++++++++ 17 files changed, 454 insertions(+), 444 deletions(-) create mode 100644 kernel/irq/msi.c
Signature · 1 line
1.7.10.4
RFC 1/17 x86, irq: Normalize x86 irq_chip name
Some irq_chip names use underscore, others use hyphen. So normalize them.
--- arch/x86/kernel/apic/msi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/msi.c +2 -2
@@ -179,7 +179,7 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, }static struct irq_chip dmar_msi_type = { - .name ="DMAR_MSI" , + .name ="DMAR-MSI" , .irq_unmask = dmar_msi_unmask, .irq_mask = dmar_msi_mask, .irq_ack = irq_chip_ack_parent,
@@ -310,7 +310,7 @@ static int hpet_msi_set_affinity(struct irq_data *data, }static struct irq_chip hpet_msi_type = { - .name ="HPET_MSI" , + .name ="HPET-MSI" , .irq_unmask = hpet_msi_unmask, .irq_mask = hpet_msi_mask, .irq_ack = irq_chip_ack_parent,
Signature · 1 line
1.7.10.4
RFC 2/17 genirq: Introduce helper irq_domain_set_info() to reduce duplicated code
In reply to Jiang LiuIntroduce helper irq_domain_set_info() to reduce duplicated code. We use "void *handler" instead of "irq_flow_handler_t handler" to solve a recursive header file inclusion issue.
--- arch/x86/kernel/apic/htirq.c | 5 ++--- arch/x86/platform/uv/uv_irq.c | 5 ++--- include/linux/irqdomain.h | 4 ++++ kernel/irq/irqdomain.c | 10 ++++++++++ 4 files changed, 18 insertions(+), 6 deletions(-)
arch/x86/kernel/apic/htirq.c +2 -3
@@ -96,9 +96,8 @@ static int htirq_domain_alloc(struct irq_domain *domain, unsigned int virq, ht_cfg->update = info->ht_update; ht_cfg->pos = info->ht_pos; ht_cfg->idx =0x10 + (info->ht_idx *2 ); -irq_domain_set_hwirq_and_chip (domain, virq, hwirq, &ht_irq_chip, - ht_cfg); -__irq_set_handler (virq, handle_edge_irq,0 ,"edge" ); +irq_domain_set_info (domain, virq, hwirq, &ht_irq_chip, ht_cfg, + handle_edge_irq,NULL ,"edge" );return 0 ; }
arch/x86/platform/uv/uv_irq.c +2 -3
@@ -102,9 +102,8 @@ static int uv_domain_alloc(struct irq_domain *domain, unsigned int virq, chip_data->pnode =uv_blade_to_pnode (info->uv_blade); chip_data->offset = info->uv_offset; -irq_domain_set_hwirq_and_chip (domain, virq, virq, - &uv_irq_chip, chip_data); -__irq_set_handler (virq, handle_percpu_irq,0 , info->uv_name); +irq_domain_set_info (domain, virq, virq, &uv_irq_chip, chip_data, + handle_percpu_irq,NULL , info->uv_name); }else {kfree (chip_data); }
include/linux/irqdomain.h +4 -0
@@ -263,6 +263,10 @@ extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain,irq_hw_number_t hwirq, struct irq_chip *chip, void *chip_data); +extern void irq_domain_set_info (struct irq_domain *domain,unsigned int virq, +irq_hw_number_t hwirq,struct irq_chip *chip, +void *chip_data,void *handler, +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);
kernel/irq/irqdomain.c +10 -0
@@ -882,6 +882,16 @@ int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, unsigned int virq,return 0 ; } +void irq_domain_set_info (struct irq_domain *domain,unsigned int virq, +irq_hw_number_t hwirq,struct irq_chip *chip, +void *chip_data,void *handler,void *handler_data, +const char *handler_name) +{ +irq_domain_set_hwirq_and_chip (domain, virq, hwirq, chip, chip_data); +__irq_set_handler (virq, handler,0 , handler_name); +irq_set_handler_data (virq, handler_data); +} +void irq_domain_reset_irq_data (struct irq_data *irq_data) { irq_data->hwirq =0 ;
Signature · 1 line
1.7.10.4
RFC 3/17 x86, PCI/MSI: Simplify the way to deal with remapped MSI interrupts
In reply to Jiang LiuSimplify the way to deal with remapped MSI interrupts, so we could kill irq_chip.irq_print_chip later.
--- arch/x86/kernel/apic/msi.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
arch/x86/kernel/apic/msi.c +13 -3
@@ -95,7 +95,6 @@ static struct irq_chip msi_chip = { .irq_ack = irq_chip_ack_parent, .irq_set_affinity = msi_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, - .irq_print_chip = irq_remapping_print_chip, .irq_compose_msi_msg = msi_compose_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
@@ -153,9 +152,19 @@ void arch_init_msi_domain(struct irq_domain *parent) }#ifdef CONFIG_IRQ_REMAP +static struct irq_chip msi_ir_chip = { + .name ="IR-PCI-MSI" , + .irq_unmask = unmask_msi_irq, + .irq_mask = mask_msi_irq, + .irq_ack = irq_chip_ack_parent, + .irq_set_affinity = msi_set_affinity, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .flags =IRQCHIP_SKIP_SET_WAKE , +}; +struct irq_domain *arch_create_msi_irq_domain (struct irq_domain *parent) { -return msi_create_irq_domain (NULL , &msi_chip, parent); +return msi_create_irq_domain (NULL , &msi_ir_chip, parent); }#endif
@@ -316,7 +325,6 @@ static struct irq_chip hpet_msi_type = { .irq_ack = irq_chip_ack_parent, .irq_set_affinity = hpet_msi_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, - .irq_print_chip = irq_remapping_print_chip, .irq_compose_msi_msg = msi_compose_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
@@ -397,6 +405,8 @@ struct irq_domain *hpet_create_irq_domain(int hpet_id) domain->parent =irq_remapping_get_ir_irq_domain (&info);if (!domain->parent) domain->parent = x86_vector_domain; +else + hpet_msi_type.name ="IR-HPET-MSI" ; }return domain;
Signature · 1 line
1.7.10.4
RFC 4/17 PCI/MSI: Replace msi_update_msg() with irq_chip_compose_msi_msg()
In reply to Jiang LiuFunction irq_chip_compose_msi_msg() can achieve the same goal as msi_update_msg(), so kill msi_update_msg().
--- arch/x86/kernel/apic/msi.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-)
arch/x86/kernel/apic/msi.c +4 -21
@@ -53,31 +53,16 @@ static void msi_compose_msg(struct irq_data *data, struct msi_msg *msg)MSI_DATA_VECTOR (cfg->vector); } -static void msi_update_msg (struct msi_msg *msg,struct irq_data *irq_data) -{ -struct irq_cfg *cfg =irqd_cfg (irq_data); - - msg->data &= ~MSI_DATA_VECTOR_MASK ; - msg->data |=MSI_DATA_VECTOR (cfg->vector); - msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK ; - msg->address_lo |=MSI_ADDR_DEST_ID (cfg->dest_apicid); -if (x2apic_enabled ()) - msg->address_hi =MSI_ADDR_BASE_HI | -MSI_ADDR_EXT_DEST_ID (cfg->dest_apicid); -} -static int msi_set_affinity (struct irq_data *data,const struct cpumask *mask,bool force) {struct irq_data *parent = data->parent_data; +struct msi_msg msg;int ret; ret = parent->chip->irq_set_affinity (parent, mask, force);if (ret >=0 && ret !=IRQ_SET_MASK_OK_DONE ) { -struct msi_msg msg; - -__get_cached_msi_msg (data->msi_desc, &msg); -msi_update_msg (&msg, data); +irq_chip_compose_msi_msg (data, &msg);__write_msi_msg (data->msi_desc, &msg); }
@@ -179,8 +164,7 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, ret = parent->chip->irq_set_affinity (parent, mask, force);if (ret >=0 ) { -dmar_msi_read (data->irq, &msg); -msi_update_msg (&msg, data); +irq_chip_compose_msi_msg (data, &msg);dmar_msi_write (data->irq, &msg); }
@@ -310,8 +294,7 @@ static int hpet_msi_set_affinity(struct irq_data *data, ret = parent->chip->irq_set_affinity (parent, mask, force);if (ret >=0 && ret !=IRQ_SET_MASK_OK_DONE ) { -hpet_msi_read (data->handler_data, &msg); -msi_update_msg (&msg, data); +irq_chip_compose_msi_msg (data, &msg);hpet_msi_write (data->handler_data, &msg); }
Signature · 1 line
1.7.10.4
RFC 5/17 PCI/MSI: Move msi_set_affinity() to PCI core
In reply to Jiang LiuMove msi_set_affinity() to PCI core, so it could be reused later.
--- arch/x86/kernel/apic/msi.c | 20 ++------------------ drivers/pci/msi.c | 16 ++++++++++++++++ include/linux/msi.h | 2 ++ 3 files changed, 20 insertions(+), 18 deletions(-)
arch/x86/kernel/apic/msi.c +2 -18
@@ -53,22 +53,6 @@ static void msi_compose_msg(struct irq_data *data, struct msi_msg *msg)MSI_DATA_VECTOR (cfg->vector); } -static int msi_set_affinity (struct irq_data *data,const struct cpumask *mask, -bool force) -{ -struct irq_data *parent = data->parent_data; -struct msi_msg msg; -int ret; - - ret = parent->chip->irq_set_affinity (parent, mask, force); -if (ret >=0 && ret !=IRQ_SET_MASK_OK_DONE ) { -irq_chip_compose_msi_msg (data, &msg); -__write_msi_msg (data->msi_desc, &msg); - } - -return ret; -} -/* * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, * which implement the MSI or MSI-X Capability Structure.
@@ -78,7 +62,7 @@ static struct irq_chip msi_chip = { .irq_unmask = unmask_msi_irq, .irq_mask = mask_msi_irq, .irq_ack = irq_chip_ack_parent, - .irq_set_affinity = msi_set_affinity, + .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = msi_compose_msg, .flags = IRQCHIP_SKIP_SET_WAKE,
@@ -142,7 +126,7 @@ static struct irq_chip msi_ir_chip = { .irq_unmask = unmask_msi_irq, .irq_mask = mask_msi_irq, .irq_ack = irq_chip_ack_parent, - .irq_set_affinity = msi_set_affinity, + .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .flags = IRQCHIP_SKIP_SET_WAKE, };
drivers/pci/msi.c +16 -0
@@ -1101,6 +1101,22 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,EXPORT_SYMBOL (pci_enable_msix_range);#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN +int msi_domain_set_affinity (struct irq_data *data,const struct cpumask *mask, +bool force) +{ +struct irq_data *parent = data->parent_data; +struct msi_msg msg; +int ret; + + ret = parent->chip->irq_set_affinity (parent, mask, force); +if (ret >=0 && ret !=IRQ_SET_MASK_OK_DONE ) { +irq_chip_compose_msi_msg (data, &msg); +__write_msi_msg (data->msi_desc, &msg); + } + +return ret; +} +/* * Generate a unique ID number for each possible MSI source, the ID number * is only used within the irqdomain.
include/linux/msi.h +2 -0
@@ -79,6 +79,8 @@ struct msi_chip {struct irq_domain ;struct irq_chip ; +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_chip *chip,struct irq_domain *parent);
Signature · 1 line
1.7.10.4
RFC 6/17 genirq: Introduce callback irq_chip.irq_write_msi_msg
In reply to Jiang LiuIntroduce callback irq_chip.irq_write_msi_msg, so we could share common code among MSI alike interrupt controllers, such as HPET and DMAR.
--- include/linux/irq.h | 8 ++++++++ 1 file changed, 8 insertions(+)
include/linux/irq.h +8 -0
@@ -326,6 +326,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)* @irq_release_resources: optional to release resources acquired with * irq_request_resources * @irq_compose_msi_msg: optional to compose message content for MSI +* @irq_write_msi_msg: optional to write message content for MSI * @flags: chip specific flags */ struct irq_chip {
@@ -363,6 +364,7 @@ struct irq_chip {void (*irq_release_resources)(struct irq_data *data);void (*irq_compose_msi_msg)(struct irq_data *data,struct msi_msg *msg); +void (*irq_write_msi_msg)(struct irq_data *data,struct msi_msg *msg);unsigned long flags; };
@@ -457,6 +459,12 @@ extern void irq_chip_ack_parent(struct irq_data *data);extern int irq_chip_retrigger_hierarchy (struct irq_data *data);#endif +static inline void irq_chip_write_msi_msg (struct irq_data *data, +struct msi_msg *msg) +{ + data->chip->irq_write_msi_msg (data, msg); +} +/* Handling of unhandled and spurious interrupts: */ extern void note_interrupt (unsigned int irq,struct irq_desc *desc,irqreturn_t action_ret);
Signature · 1 line
1.7.10.4
RFC 7/17 x86, irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips
In reply to Jiang LiuImplement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips, they will be used to share common code later.
--- arch/x86/kernel/apic/msi.c | 14 ++++++++++++++ drivers/pci/msi.c | 15 +++++++++++++-- include/linux/msi.h | 1 + 3 files changed, 28 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/msi.c +14 -0
@@ -65,6 +65,7 @@ static struct irq_chip msi_chip = { .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = msi_compose_msg, + .irq_write_msi_msg = pci_msi_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
@@ -128,6 +129,7 @@ static struct irq_chip msi_ir_chip = { .irq_ack = irq_chip_ack_parent, .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_write_msi_msg = pci_msi_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
@@ -155,6 +157,11 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,return ret; } +static void dmar_msi_write_msg (struct irq_data *data,struct msi_msg *msg) +{ +dmar_msi_write (data->irq, msg); +} +static struct irq_chip dmar_msi_type = { .name ="DMAR-MSI" , .irq_unmask = dmar_msi_unmask,
@@ -163,6 +170,7 @@ static struct irq_chip dmar_msi_type = { .irq_set_affinity = dmar_msi_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = msi_compose_msg, + .irq_write_msi_msg = dmar_msi_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
@@ -285,6 +293,11 @@ static int hpet_msi_set_affinity(struct irq_data *data,return ret; } +static void hpet_msi_write_msg (struct irq_data *data,struct msi_msg *msg) +{ +hpet_msi_write (data->handler_data, msg); +} +static struct irq_chip hpet_msi_type = { .name ="HPET-MSI" , .irq_unmask = hpet_msi_unmask,
@@ -293,6 +306,7 @@ static struct irq_chip hpet_msi_type = { .irq_set_affinity = hpet_msi_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = msi_compose_msg, + .irq_write_msi_msg = hpet_msi_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
drivers/pci/msi.c +13 -2
@@ -1117,6 +1117,18 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,return ret; } +void pci_msi_write_msg (struct irq_data *irq_data,struct msi_msg *msg) +{ +struct msi_desc *desc = irq_data->msi_desc; + +/* +* MSI-X message is written per-IRQ. +* MSI message denotes a contiguous group of IRQs, written for 0th IRQ. +*/ +if (desc->irq == irq_data->irq) +__write_msi_msg (desc, msg); +} +/* * Generate a unique ID number for each possible MSI source, the ID number * is only used within the irqdomain.
@@ -1144,8 +1156,7 @@ static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq,for (i =0 ; i < nr_irqs; i++) {irq_domain_set_hwirq_and_chip (domain, virq + i, hwirq + i, - domain->host_data, - (void *)(long )i); + domain->host_data,NULL );__irq_set_handler (virq + i, handle_edge_irq,0 ,"edge" ); }
include/linux/msi.h +1 -0
@@ -84,6 +84,7 @@ 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 irq_chip *chip,struct irq_domain *parent); +void pci_msi_write_msg (struct irq_data *irq_data,struct msi_msg *msg);int msi_irq_domain_alloc_irqs (struct irq_domain *domain,int type,struct pci_dev *dev,void *arg);
Signature · 1 line
1.7.10.4
RFC 8/17 PCI/MSI: Use irq_chip.irq_write_msi_msg() to share common code
In reply to Jiang LiuChange PCI MSI code to use irq_chip.irq_write_msi_msg() to share more common code later.
--- drivers/pci/msi.c | 24 ++++++------------------ include/linux/msi.h | 3 +++ 2 files changed, 9 insertions(+), 18 deletions(-)
drivers/pci/msi.c +6 -18
@@ -1111,7 +1111,7 @@ int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask, ret = parent->chip->irq_set_affinity (parent, mask, force);if (ret >=0 && ret !=IRQ_SET_MASK_OK_DONE ) {irq_chip_compose_msi_msg (data, &msg); -__write_msi_msg (data->msi_desc, &msg); +irq_chip_write_msi_msg (data, &msg); }return ret;
@@ -1177,32 +1177,20 @@ static void msi_domain_free(struct irq_domain *domain, unsigned int virq,irq_domain_free_irqs_top (domain, virq, nr_irqs); } -static void msi_domain_activate (struct irq_domain *domain, -struct irq_data *irq_data) +void msi_domain_activate (struct irq_domain *domain,struct irq_data *irq_data) {struct msi_msg msg; -/* -* irq_data->chip_data is MSI/MSI-X offset. -* MSI-X message is written per-IRQ, the offset is always 0. -* MSI message denotes a contiguous group of IRQs, written for 0th IRQ. -*/ -if (irq_data->chip_data) -return ; -BUG_ON (irq_chip_compose_msi_msg (irq_data, &msg)); -__write_msi_msg (irq_data->msi_desc, &msg); +irq_chip_write_msi_msg (irq_data, &msg); } -static void msi_domain_deactivate (struct irq_domain *domain, -struct irq_data *irq_data) +void msi_domain_deactivate (struct irq_domain *domain,struct irq_data *irq_data) {struct msi_msg msg; -if (!irq_data->chip_data) { -memset (&msg,0 ,sizeof (msg)); -__write_msi_msg (irq_data->msi_desc, &msg); - } +memset (&msg,0 ,sizeof (msg)); +irq_chip_write_msi_msg (irq_data, &msg); }static struct irq_domain_ops msi_domain_ops = {
include/linux/msi.h +3 -0
@@ -81,6 +81,9 @@ struct irq_chip;int msi_domain_set_affinity (struct irq_data *data,const struct cpumask *mask,bool force); +void msi_domain_activate (struct irq_domain *domain,struct irq_data *irq_data); +void msi_domain_deactivate (struct irq_domain *domain, +struct irq_data *irq_data);struct irq_domain *msi_create_irq_domain (struct device_node *of_node,struct irq_chip *chip,struct irq_domain *parent);
Signature · 1 line
1.7.10.4
RFC 9/17 x86, irq: Simplify MSI/DMAR/HPET implementation by using common code
In reply to Jiang LiuUse common code to simplify MSI/DMAR/HPET driver implementation.
--- arch/x86/kernel/apic/msi.c | 81 ++++---------------------------------------- 1 file changed, 6 insertions(+), 75 deletions(-)
arch/x86/kernel/apic/msi.c +6 -75
@@ -140,23 +140,6 @@ struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent)#endif #ifdef CONFIG_DMAR_TABLE -static int -dmar_msi_set_affinity (struct irq_data *data,const struct cpumask *mask, -bool force) -{ -struct irq_data *parent = data->parent_data; -struct msi_msg msg; -int ret; - - ret = parent->chip->irq_set_affinity (parent, mask, force); -if (ret >=0 ) { -irq_chip_compose_msi_msg (data, &msg); -dmar_msi_write (data->irq, &msg); - } - -return ret; -} -static void dmar_msi_write_msg (struct irq_data *data,struct msi_msg *msg) {dmar_msi_write (data->irq, msg);
@@ -167,7 +150,7 @@ static struct irq_chip dmar_msi_type = { .irq_unmask = dmar_msi_unmask, .irq_mask = dmar_msi_mask, .irq_ack = irq_chip_ack_parent, - .irq_set_affinity = dmar_msi_set_affinity, + .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = msi_compose_msg, .irq_write_msi_msg = dmar_msi_write_msg,
@@ -205,29 +188,11 @@ static void dmar_domain_free(struct irq_domain *domain, unsigned int virq,irq_domain_free_irqs_top (domain, virq, nr_irqs); } -static void dmar_domain_activate (struct irq_domain *domain, -struct irq_data *irq_data) -{ -struct msi_msg msg; - -BUG_ON (irq_chip_compose_msi_msg (irq_data, &msg)); -dmar_msi_write (irq_data->irq, &msg); -} - -static void dmar_domain_deactivate (struct irq_domain *domain, -struct irq_data *irq_data) -{ -struct msi_msg msg; - -memset (&msg,0 ,sizeof (msg)); -dmar_msi_write (irq_data->irq, &msg); -} -static struct irq_domain_ops dmar_domain_ops = { .alloc = dmar_domain_alloc, .free = dmar_domain_free, - .activate = dmar_domain_activate, - .deactivate = dmar_domain_deactivate, + .activate = msi_domain_activate, + .deactivate = msi_domain_deactivate, };static struct irq_domain *dmar_get_irq_domain (void )
@@ -277,22 +242,6 @@ static inline int hpet_dev_id(struct irq_domain *domain)return (int )(long )domain->host_data; } -static int hpet_msi_set_affinity (struct irq_data *data, -const struct cpumask *mask,bool force) -{ -struct irq_data *parent = data->parent_data; -struct msi_msg msg; -int ret; - - ret = parent->chip->irq_set_affinity (parent, mask, force); -if (ret >=0 && ret !=IRQ_SET_MASK_OK_DONE ) { -irq_chip_compose_msi_msg (data, &msg); -hpet_msi_write (data->handler_data, &msg); - } - -return ret; -} -static void hpet_msi_write_msg (struct irq_data *data,struct msi_msg *msg) {hpet_msi_write (data->handler_data, msg);
@@ -303,7 +252,7 @@ static struct irq_chip hpet_msi_type = { .irq_unmask = hpet_msi_unmask, .irq_mask = hpet_msi_mask, .irq_ack = irq_chip_ack_parent, - .irq_set_affinity = hpet_msi_set_affinity, + .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = msi_compose_msg, .irq_write_msi_msg = hpet_msi_write_msg,
@@ -343,29 +292,11 @@ static void hpet_domain_free(struct irq_domain *domain, unsigned int virq,irq_domain_free_irqs_top (domain, virq, nr_irqs); } -static void hpet_domain_activate (struct irq_domain *domain, -struct irq_data *irq_data) -{ -struct msi_msg msg; - -BUG_ON (irq_chip_compose_msi_msg (irq_data, &msg)); -hpet_msi_write (irq_get_handler_data (irq_data->irq), &msg); -} - -static void hpet_domain_deactivate (struct irq_domain *domain, -struct irq_data *irq_data) -{ -struct msi_msg msg; - -memset (&msg,0 ,sizeof (msg)); -hpet_msi_write (irq_get_handler_data (irq_data->irq), &msg); -} -static struct irq_domain_ops hpet_domain_ops = { .alloc = hpet_domain_alloc, .free = hpet_domain_free, - .activate = hpet_domain_activate, - .deactivate = hpet_domain_deactivate, + .activate = msi_domain_activate, + .deactivate = msi_domain_deactivate, };struct irq_domain *hpet_create_irq_domain (int hpet_id)
Signature · 1 line
1.7.10.4
RFC 10/17 PCI, MSI: Split MSI code into PCI dependent and PCI independent parts
In reply to Jiang LiuSome interrupt controllers, such as DMAR and HPET interrupt controllers, make use of the same mechanism as PCI MSI interrupt, but they are not PCI compatible. So split MSI code into PCI dependent part and PCI independent part for code reuse later.
PCI dependent part is still hosted in drivers/pci/msi.c and a new file kernel/irq/msi.c is created to host PCI independent part.
Use CONFIG_PCI_MSI to guard PCI dependent code in file include/linux/msi.h, especially guarding PCI related fields in struct msi_desc.
For backward compatibility, we choose to conditionally embedded PCI related fields in struct msi_desc instead of introducing
struct pci_msi_desc.
--- drivers/pci/Kconfig | 4 +++- drivers/pci/msi.c | 50 ---------------------------------------- include/linux/msi.h | 64 ++++++++++++++++++++++++++++++--------------------- kernel/irq/Kconfig | 10 +++++++- kernel/irq/Makefile | 1 + kernel/irq/msi.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 112 insertions(+), 78 deletions(-) create mode 100644 kernel/irq/msi.c
drivers/pci/Kconfig +3 -1
@@ -4,6 +4,7 @@ config PCI_MSI bool "Message Signaled Interrupts (MSI and MSI-X)" depends on PCI + select GENERIC_MSI_IRQ help This allows device drivers to enable MSI (Message Signaled Interrupts). Message Signaled Interrupts enable a device to
@@ -18,7 +19,8 @@ config PCI_MSI config PCI_MSI_IRQ_DOMAIN bool - depends on PCI_MSI && IRQ_DOMAIN_HIERARCHY + depends on PCI_MSI + select GENERIC_MSI_IRQ_DOMAIN config PCI_DEBUG bool "PCI Debugging"
drivers/pci/msi.c +0 -50
68 lines not on this page · raw message
include/linux/msi.h +38 -26
102 lines not on this page · raw message
kernel/irq/Kconfig +9 -1
@@ -57,7 +57,15 @@ config IRQ_DOMAIN config IRQ_DOMAIN_HIERARCHY bool - depends on IRQ_DOMAIN + select IRQ_DOMAIN + +config GENERIC_MSI_IRQ + bool + +config GENERIC_MSI_IRQ_DOMAIN + bool + select IRQ_DOMAIN_HIERARCHY + select GENERIC_MSI_IRQ config HANDLE_DOMAIN_IRQ bool
kernel/irq/Makefile +1 -0
@@ -6,3 +6,4 @@ obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o obj-$(CONFIG_PM_SLEEP) += pm.o +obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
kernel/irq/msi.c new file +61 -0
61 lines not on this page · raw message
Signature · 1 line
1.7.10.4
RFC 11/17 PCI, MSI: Rename __read_msi_msg() as __pci_read_msi_msg()
In reply to Jiang LiuRename __read_msi_msg() as __pci_read_msi_msg() and kill unused read_msi_msg(). It's a preparation to separate generic MSI code from PCI core.
--- arch/powerpc/platforms/pseries/msi.c | 2 +- arch/x86/pci/xen.c | 2 +- drivers/pci/msi.c | 9 +-------- include/linux/msi.h | 3 +-- 4 files changed, 4 insertions(+), 12 deletions(-)
arch/powerpc/platforms/pseries/msi.c +1 -1
@@ -476,7 +476,7 @@ again:irq_set_msi_desc (virq, entry);/* Read config space back so we can restore after reset */ -__read_msi_msg (entry, &msg); +__pci_read_msi_msg (entry, &msg); entry->msg = msg; }
arch/x86/pci/xen.c +1 -1
@@ -229,7 +229,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)return 1 ;list_for_each_entry (msidesc, &dev->msi_list, list) { -__read_msi_msg (msidesc, &msg); +__pci_read_msi_msg (msidesc, &msg); pirq =MSI_ADDR_EXT_DEST_ID (msg.address_hi) | ((msg.address_lo >>MSI_ADDR_DEST_ID_SHIFT ) &0xff ); if (msg.data != XEN_PIRQ_MSI_DATA ||
drivers/pci/msi.c +1 -8
@@ -243,7 +243,7 @@ void default_restore_msi_irqs(struct pci_dev *dev)default_restore_msi_irq (dev, entry->irq); } -void __read_msi_msg (struct msi_desc *entry,struct msi_msg *msg) +void __pci_read_msi_msg (struct msi_desc *entry,struct msi_msg *msg) {BUG_ON (entry->dev->current_state !=PCI_D0 );
@@ -273,13 +273,6 @@ void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) } } -void read_msi_msg (unsigned int irq,struct msi_msg *msg) -{ -struct msi_desc *entry =irq_get_msi_desc (irq); - -__read_msi_msg (entry, msg); -} -void __write_msi_msg (struct msi_desc *entry,struct msi_msg *msg) {if (entry->dev->current_state !=PCI_D0 ) {
include/linux/msi.h +1 -2
@@ -61,9 +61,8 @@ void msi_domain_deactivate(struct irq_domain *domain,#ifdef CONFIG_PCI_MSI /* Helper functions */ -void __read_msi_msg (struct msi_desc *entry,struct msi_msg *msg); +void __pci_read_msi_msg (struct msi_desc *entry,struct msi_msg *msg);void __write_msi_msg (struct msi_desc *entry,struct msi_msg *msg); -void read_msi_msg (unsigned int irq,struct msi_msg *msg);void write_msi_msg (unsigned int irq,struct msi_msg *msg);/*
Signature · 1 line
1.7.10.4
RFC 11/17 PCI, MSI: Rename __read_msi_msg() as __pci_read_msi_msg()
In reply to Jiang LiuRename __read_msi_msg() as __pci_read_msi_msg() and kill unused read_msi_msg(). It's a preparation to separate generic MSI code from PCI core.
--- arch/powerpc/platforms/pseries/msi.c | 2 +- arch/x86/pci/xen.c | 2 +- drivers/pci/msi.c | 9 +-------- include/linux/msi.h | 3 +-- 4 files changed, 4 insertions(+), 12 deletions(-)
arch/powerpc/platforms/pseries/msi.c +1 -1
@@ -476,7 +476,7 @@ again:irq_set_msi_desc (virq, entry);/* Read config space back so we can restore after reset */ -__read_msi_msg (entry, &msg); +__pci_read_msi_msg (entry, &msg); entry->msg = msg; }
arch/x86/pci/xen.c +1 -1
@@ -229,7 +229,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)return 1 ;list_for_each_entry (msidesc, &dev->msi_list, list) { -__read_msi_msg (msidesc, &msg); +__pci_read_msi_msg (msidesc, &msg); pirq =MSI_ADDR_EXT_DEST_ID (msg.address_hi) | ((msg.address_lo >>MSI_ADDR_DEST_ID_SHIFT ) &0xff ); if (msg.data != XEN_PIRQ_MSI_DATA ||
drivers/pci/msi.c +1 -8
@@ -243,7 +243,7 @@ void default_restore_msi_irqs(struct pci_dev *dev)default_restore_msi_irq (dev, entry->irq); } -void __read_msi_msg (struct msi_desc *entry,struct msi_msg *msg) +void __pci_read_msi_msg (struct msi_desc *entry,struct msi_msg *msg) {BUG_ON (entry->dev->current_state !=PCI_D0 );
@@ -273,13 +273,6 @@ void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) } } -void read_msi_msg (unsigned int irq,struct msi_msg *msg) -{ -struct msi_desc *entry =irq_get_msi_desc (irq); - -__read_msi_msg (entry, msg); -} -void __write_msi_msg (struct msi_desc *entry,struct msi_msg *msg) {if (entry->dev->current_state !=PCI_D0 ) {
include/linux/msi.h +1 -2
@@ -61,9 +61,8 @@ void msi_domain_deactivate(struct irq_domain *domain,#ifdef CONFIG_PCI_MSI /* Helper functions */ -void __read_msi_msg (struct msi_desc *entry,struct msi_msg *msg); +void __pci_read_msi_msg (struct msi_desc *entry,struct msi_msg *msg);void __write_msi_msg (struct msi_desc *entry,struct msi_msg *msg); -void read_msi_msg (unsigned int irq,struct msi_msg *msg);void write_msi_msg (unsigned int irq,struct msi_msg *msg);/*
Signature · 1 line
1.7.10.4
RFC 12/17 PCI, MSI: Rename __write_msi_msg() as __pci_write_msi_msg()
In reply to Jiang LiuRename __write_msi_msg() as __pci_write_msi_msg() to mark it as PCI specific. Also define pci_write_msi_msg() as write_msi_msg() for easy transition.
--- arch/x86/pci/xen.c | 2 +- drivers/pci/msi.c | 9 ++++----- include/linux/msi.h | 3 ++- 3 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/pci/xen.c +1 -1
@@ -240,7 +240,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) goto error; }xen_msi_compose_msg (dev, pirq, &msg); -__write_msi_msg (msidesc, &msg); +__pci_write_msi_msg (msidesc, &msg);dev_dbg (&dev->dev,"xen: msi bound to pirq=%d\n" , pirq); }else { dev_dbg(&dev->dev,
drivers/pci/msi.c +4 -5
@@ -27,7 +27,6 @@ static int pci_msi_enable = 1;#define msix_table_size (flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1) -/* Arch hooks */ int __weak arch_setup_msi_irq (struct pci_dev *dev,struct msi_desc *desc)
@@ -115,7 +114,7 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq) }if (entry) -__write_msi_msg (entry, &entry->msg); +__pci_write_msi_msg (entry, &entry->msg); }void __weak arch_restore_msi_irqs (struct pci_dev *dev)
@@ -273,7 +272,7 @@ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) } } -void __write_msi_msg (struct msi_desc *entry,struct msi_msg *msg) +void __pci_write_msi_msg (struct msi_desc *entry,struct msi_msg *msg) {if (entry->dev->current_state !=PCI_D0 ) {/* Don't touch the hardware now */
@@ -314,7 +313,7 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) {struct msi_desc *entry =irq_get_msi_desc (irq); -__write_msi_msg (entry, msg); +__pci_write_msi_msg (entry, msg); }EXPORT_SYMBOL_GPL (write_msi_msg);
@@ -1085,7 +1084,7 @@ void pci_msi_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) -__write_msi_msg (desc, msg); +__pci_write_msi_msg (desc, msg); }/*
include/linux/msi.h +2 -1
@@ -62,8 +62,9 @@ void msi_domain_deactivate(struct irq_domain *domain,#ifdef CONFIG_PCI_MSI /* Helper functions */ void __pci_read_msi_msg (struct msi_desc *entry,struct msi_msg *msg); -void __write_msi_msg (struct msi_desc *entry,struct msi_msg *msg); +void __pci_write_msi_msg (struct msi_desc *entry,struct msi_msg *msg);void write_msi_msg (unsigned int irq,struct msi_msg *msg); +#define pci_write_msi_msg write_msi_msg/* * The arch hooks to setup up msi irqs. Those functions are
Signature · 1 line
1.7.10.4
RFC 12/17 PCI, MSI: Rename __write_msi_msg() as __pci_write_msi_msg()
In reply to Jiang LiuRename __write_msi_msg() as __pci_write_msi_msg() to mark it as PCI specific. Also define pci_write_msi_msg() as write_msi_msg() for easy transition.
--- arch/x86/pci/xen.c | 2 +- drivers/pci/msi.c | 9 ++++----- include/linux/msi.h | 3 ++- 3 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/pci/xen.c +1 -1
@@ -240,7 +240,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) goto error; }xen_msi_compose_msg (dev, pirq, &msg); -__write_msi_msg (msidesc, &msg); +__pci_write_msi_msg (msidesc, &msg);dev_dbg (&dev->dev,"xen: msi bound to pirq=%d\n" , pirq); }else { dev_dbg(&dev->dev,
drivers/pci/msi.c +4 -5
@@ -27,7 +27,6 @@ static int pci_msi_enable = 1;#define msix_table_size (flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1) -/* Arch hooks */ int __weak arch_setup_msi_irq (struct pci_dev *dev,struct msi_desc *desc)
@@ -115,7 +114,7 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq) }if (entry) -__write_msi_msg (entry, &entry->msg); +__pci_write_msi_msg (entry, &entry->msg); }void __weak arch_restore_msi_irqs (struct pci_dev *dev)
@@ -273,7 +272,7 @@ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) } } -void __write_msi_msg (struct msi_desc *entry,struct msi_msg *msg) +void __pci_write_msi_msg (struct msi_desc *entry,struct msi_msg *msg) {if (entry->dev->current_state !=PCI_D0 ) {/* Don't touch the hardware now */
@@ -314,7 +313,7 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) {struct msi_desc *entry =irq_get_msi_desc (irq); -__write_msi_msg (entry, msg); +__pci_write_msi_msg (entry, msg); }EXPORT_SYMBOL_GPL (write_msi_msg);
@@ -1085,7 +1084,7 @@ void pci_msi_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) -__write_msi_msg (desc, msg); +__pci_write_msi_msg (desc, msg); }/*
include/linux/msi.h +2 -1
@@ -62,8 +62,9 @@ void msi_domain_deactivate(struct irq_domain *domain,#ifdef CONFIG_PCI_MSI /* Helper functions */ void __pci_read_msi_msg (struct msi_desc *entry,struct msi_msg *msg); -void __write_msi_msg (struct msi_desc *entry,struct msi_msg *msg); +void __pci_write_msi_msg (struct msi_desc *entry,struct msi_msg *msg);void write_msi_msg (unsigned int irq,struct msi_msg *msg); +#define pci_write_msi_msg write_msi_msg/* * The arch hooks to setup up msi irqs. Those functions are
Signature · 1 line
1.7.10.4
RFC 13/17 MSI: Provide irqdomain support for generic MSI
In reply to Jiang LiuEnhance generic MSI code to support hierarchy irqdomain.
--- arch/x86/kernel/apic/msi.c | 4 +-- drivers/pci/msi.c | 6 ++-- include/linux/msi.h | 29 ++++++++++++++++-- kernel/irq/msi.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 8 deletions(-)
arch/x86/kernel/apic/msi.c +2 -2
@@ -116,7 +116,7 @@ void arch_init_msi_domain(struct irq_domain *parent)if (disable_apic)return ; - msi_default_domain =msi_create_irq_domain (NULL , &msi_chip, parent); + msi_default_domain =pci_msi_create_irq_domain (NULL , &msi_chip, parent);if (!msi_default_domain)pr_warn ("failed to initialize irqdomain for MSI/MSI-x.\n" ); }
@@ -135,7 +135,7 @@ static struct irq_chip msi_ir_chip = {struct irq_domain *arch_create_msi_irq_domain (struct irq_domain *parent) { -return msi_create_irq_domain (NULL , &msi_ir_chip, parent); +return pci_msi_create_irq_domain (NULL , &msi_ir_chip, parent); }#endif
drivers/pci/msi.c +3 -3
@@ -1142,9 +1142,9 @@ static struct irq_domain_ops msi_domain_ops = { .deactivate = msi_domain_deactivate, }; -struct irq_domain *msi_create_irq_domain (struct device_node *of_node, -struct irq_chip *chip, -struct irq_domain *parent) +struct irq_domain *pci_msi_create_irq_domain (struct device_node *of_node, +struct irq_chip *chip, +struct irq_domain *parent) {struct irq_domain *domain;
include/linux/msi.h +26 -3
@@ -8,6 +8,7 @@ struct irq_data;struct irq_chip ;struct irq_domain ;struct device_node ; +struct irq_domain ;struct msi_msg {u32 address_lo;/* low 32 bits of msi message address */
@@ -52,11 +53,33 @@ void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);void get_cached_msi_msg (unsigned int irq,struct msi_msg *msg);#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN +struct msi_domain_info ; + +struct msi_domain_ops { +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); +int (*msi_init)(struct irq_domain *domain,struct msi_domain_info *info, +unsigned int virq,irq_hw_number_t hwirq,void *arg); +void (*msi_free)(struct irq_domain *domain, +struct msi_domain_info *info,unsigned int virq); +}; + +struct msi_domain_info { +struct msi_domain_ops *ops; +struct irq_chip *chip; +void *data; +}; +int msi_domain_set_affinity (struct irq_data *data,const struct cpumask *mask,bool force);void msi_domain_activate (struct irq_domain *domain,struct irq_data *irq_data);void msi_domain_deactivate (struct irq_domain *domain,struct irq_data *irq_data); +struct irq_domain *msi_create_irq_domain (struct device_node *of_node, +struct msi_domain_info *info, +struct irq_domain *parent); +struct msi_domain_info *msi_get_domain_info (struct irq_domain *domain);#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */ #ifdef CONFIG_PCI_MSI
@@ -94,9 +117,9 @@ struct msi_chip { };#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN -struct irq_domain *msi_create_irq_domain (struct device_node *of_node, -struct irq_chip *chip, -struct irq_domain *parent); +struct irq_domain *pci_msi_create_irq_domain (struct device_node *of_node, +struct irq_chip *chip, +struct irq_domain *parent);void pci_msi_write_msg (struct irq_data *irq_data,struct msi_msg *msg);int msi_irq_domain_alloc_irqs (struct irq_domain *domain,int type,struct pci_dev *dev,void *arg);
kernel/irq/msi.c +70 -0
74 lines not on this page · raw message
Signature · 1 line
1.7.10.4
RFC 14/17 x86, PCI, MSI: Use common code to manage MSI interrupts
In reply to Jiang LiuConvert x86 PCI MSI interrupt driver to use common MSI code.
--- arch/x86/kernel/apic/msi.c | 200 ++++++++++++++++++++++++++------------------ drivers/pci/msi.c | 7 +- include/linux/msi.h | 1 + 3 files changed, 124 insertions(+), 84 deletions(-)
arch/x86/kernel/apic/msi.c +119 -81
@@ -57,7 +57,7 @@ static void msi_compose_msg(struct irq_data *data, struct msi_msg *msg)* IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, * which implement the MSI or MSI-X Capability Structure. */ -static struct irq_chip msi_chip = { +static struct irq_chip pci_msi_type = { .name ="PCI-MSI" , .irq_unmask = unmask_msi_irq, .irq_mask = mask_msi_irq,
@@ -104,25 +104,65 @@ irq_hw_number_t arch_msi_irq_domain_get_hwirq(void *arg)return info->msi_hwirq; } -void arch_msi_irq_domain_set_hwirq (void *arg,irq_hw_number_t hwirq) +static void pci_msi_generate_hwirq (struct msi_domain_info *minfo,void *arg, +struct msi_desc *desc) {struct irq_alloc_info *info = arg; - info->msi_hwirq = hwirq; + info->msi_hwirq =pci_msi_calc_hwirq (info->msi_dev, desc); } +static irq_hw_number_t pci_msi_get_hwirq (struct msi_domain_info *minfo, +void *arg) +{ +struct irq_alloc_info *info = arg; + +return info->msi_hwirq; +} + +static int pci_msi_init (struct irq_domain *domain, +struct msi_domain_info *minfo,unsigned int virq, +irq_hw_number_t hwirq,void *arg) +{ +irq_domain_set_info (domain, virq, hwirq, minfo->chip,NULL , + handle_edge_irq,NULL ,"edge" ); + +return 0 ; +} + +static void pci_msi_free (struct irq_domain *domain, +struct msi_domain_info *info,unsigned int virq) +{ +struct msi_desc *desc =irq_get_msi_desc (virq); + +if (desc) + desc->irq =0 ; +} + +static struct msi_domain_ops pci_msi_ops = { + .calc_hwirq = pci_msi_generate_hwirq, + .get_hwirq = pci_msi_get_hwirq, + .msi_init = pci_msi_init, + .msi_free = pci_msi_free, +}; + +static struct msi_domain_info pci_msi_info = { + .ops = &pci_msi_ops, + .chip = &pci_msi_type, +}; +void arch_init_msi_domain (struct irq_domain *parent) {if (disable_apic)return ; - msi_default_domain =pci_msi_create_irq_domain (NULL , &msi_chip, parent); + msi_default_domain =msi_create_irq_domain (NULL , &pci_msi_info, parent);if (!msi_default_domain)pr_warn ("failed to initialize irqdomain for MSI/MSI-x.\n" ); }#ifdef CONFIG_IRQ_REMAP -static struct irq_chip msi_ir_chip = { +static struct irq_chip pci_msi_ir_chip = { .name ="IR-PCI-MSI" , .irq_unmask = unmask_msi_irq, .irq_mask = mask_msi_irq,
@@ -133,9 +173,14 @@ static struct irq_chip msi_ir_chip = { .flags = IRQCHIP_SKIP_SET_WAKE, }; +static struct msi_domain_info pci_msi_ir_info = { + .ops = &pci_msi_ops, + .chip = &pci_msi_ir_chip, +}; +struct irq_domain *arch_create_msi_irq_domain (struct irq_domain *parent) { -return pci_msi_create_irq_domain (NULL , &msi_ir_chip, parent); +return msi_create_irq_domain (NULL , &pci_msi_ir_info, parent); }#endif
@@ -157,42 +202,34 @@ static struct irq_chip dmar_msi_type = { .flags = IRQCHIP_SKIP_SET_WAKE, }; -static int dmar_domain_alloc (struct irq_domain *domain,unsigned int virq, -unsigned int nr_irqs,void *arg) +static irq_hw_number_t dmar_msi_get_hwirq (struct msi_domain_info *minfo, +void *arg) {struct irq_alloc_info *info = arg; -int ret; -if (nr_irqs >1 || !info || info->type !=X86_IRQ_ALLOC_TYPE_DMAR ) -return -EINVAL ; -if (irq_find_mapping (domain, info->dmar_id)) { -pr_warn ("IRQ for DMAR%d already exists.\n" , info->dmar_id); -return -EEXIST ; - } - - ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); -if (ret >=0 ) { -irq_domain_set_hwirq_and_chip (domain, virq, info->dmar_id, - &dmar_msi_type,NULL ); -irq_set_handler_data (virq, info->dmar_data); -__irq_set_handler (virq, handle_edge_irq,0 ,"edge" ); - } - -return ret; +return info->dmar_id; } -static void dmar_domain_free (struct irq_domain *domain,unsigned int virq, -unsigned int nr_irqs) +static int dmar_msi_init (struct irq_domain *domain, +struct msi_domain_info *minfo,unsigned int virq, +irq_hw_number_t hwirq,void *arg) { -BUG_ON (nr_irqs >1 ); -irq_domain_free_irqs_top (domain, virq, nr_irqs); +struct irq_alloc_info *info = arg; + +irq_domain_set_info (domain, virq, hwirq, minfo->chip,NULL , + handle_edge_irq, info->dmar_data,"edge" ); + +return 0 ; } -static struct irq_domain_ops dmar_domain_ops = { - .alloc = dmar_domain_alloc, - .free = dmar_domain_free, - .activate = msi_domain_activate, - .deactivate = msi_domain_deactivate, +static struct msi_domain_ops dmar_msi_ops = { + .get_hwirq = dmar_msi_get_hwirq, + .msi_init = dmar_msi_init, +}; + +static struct msi_domain_info dmar_msi_info = { + .ops = &dmar_msi_ops, + .chip = &dmar_msi_type, };static struct irq_domain *dmar_get_irq_domain (void )
@@ -200,11 +237,13 @@ static struct irq_domain *dmar_get_irq_domain(void)static struct irq_domain *dmar_domain;static DEFINE_MUTEX (dmar_lock); +if (x86_vector_domain ==NULL ) +return NULL ; +mutex_lock (&dmar_lock);if (dmar_domain ==NULL ) { - dmar_domain =irq_domain_add_tree (NULL , &dmar_domain_ops,NULL ); -if (dmar_domain) - dmar_domain->parent = x86_vector_domain; + dmar_domain =msi_create_irq_domain (NULL , &dmar_msi_info, + x86_vector_domain); }mutex_unlock (&dmar_lock);
@@ -237,11 +276,6 @@ void dmar_free_hwirq(int irq)* MSI message composition */ #ifdef CONFIG_HPET_TIMER -static inline int hpet_dev_id (struct irq_domain *domain) -{ -return (int )(long )domain->host_data; -} -static void hpet_msi_write_msg (struct irq_data *data,struct msi_msg *msg) {hpet_msi_write (data->handler_data, msg);
@@ -259,69 +293,73 @@ static struct irq_chip hpet_msi_type = { .flags = IRQCHIP_SKIP_SET_WAKE, }; -static int hpet_domain_alloc (struct irq_domain *domain,unsigned int virq, -unsigned int nr_irqs,void *arg) +static inline int hpet_dev_id (struct irq_domain *domain) +{ +struct msi_domain_info *minfo =msi_get_domain_info (domain); + +return (int )(long )minfo->data; +} + +static irq_hw_number_t hpet_msi_get_hwirq (struct msi_domain_info *minfo, +void *arg) {struct irq_alloc_info *info = arg; -int ret; -if (nr_irqs >1 || !info || info->type !=X86_IRQ_ALLOC_TYPE_HPET ) -return -EINVAL ; -if (irq_find_mapping (domain, info->hpet_index)) { -pr_warn ("IRQ for HPET%d already exists.\n" , info->hpet_index); -return -EEXIST ; - } +return info->hpet_index; +} - ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); -if (ret >=0 ) { -irq_set_status_flags (virq,IRQ_MOVE_PCNTXT ); -irq_domain_set_hwirq_and_chip (domain, virq, info->hpet_index, - &hpet_msi_type,NULL ); -irq_set_handler_data (virq, info->hpet_data); -__irq_set_handler (virq, handle_edge_irq,0 ,"edge" ); - } +static int hpet_msi_init (struct irq_domain *domain, +struct msi_domain_info *minfo,unsigned int virq, +irq_hw_number_t hwirq,void *arg) +{ +struct irq_alloc_info *info = arg; + +irq_set_status_flags (virq,IRQ_MOVE_PCNTXT ); +irq_domain_set_info (domain, virq, hwirq, minfo->chip,NULL , + handle_edge_irq, info->hpet_data,"edge" ); -return ret; +return 0 ; } -static void hpet_domain_free (struct irq_domain *domain,unsigned int virq, -unsigned int nr_irqs) +static void hpet_msi_free (struct irq_domain *domain, +struct msi_domain_info *info,unsigned int virq) { -BUG_ON (nr_irqs >1 );irq_clear_status_flags (virq,IRQ_MOVE_PCNTXT ); -irq_domain_free_irqs_top (domain, virq, nr_irqs); } -static struct irq_domain_ops hpet_domain_ops = { - .alloc = hpet_domain_alloc, - .free = hpet_domain_free, - .activate = msi_domain_activate, - .deactivate = msi_domain_deactivate, +static struct msi_domain_ops hpet_msi_ops = { + .get_hwirq = hpet_msi_get_hwirq, + .msi_init = hpet_msi_init, + .msi_free = hpet_msi_free, };struct irq_domain *hpet_create_irq_domain (int hpet_id) { -struct irq_domain *domain; +struct irq_domain *parent; +struct msi_domain_info *minfo;struct irq_alloc_info info;if (x86_vector_domain ==NULL )return NULL ; + minfo =kzalloc (sizeof (*minfo),GFP_KERNEL ); +if (minfo ==NULL ) +return NULL ; + + minfo->ops = &hpet_msi_ops; + minfo->chip = &hpet_msi_type; + minfo->data = (void *)(long )hpet_id; +init_irq_alloc_info (&info,NULL ); info.type =X86_IRQ_ALLOC_TYPE_HPET ; info.hpet_id = hpet_id; + parent =irq_remapping_get_ir_irq_domain (&info); +if (parent) + hpet_msi_type.name ="IR-HPET-MSI" ; +else + parent = x86_vector_domain; - domain =irq_domain_add_tree (NULL , &hpet_domain_ops, - (void *)(long )hpet_id); -if (domain) { - domain->parent =irq_remapping_get_ir_irq_domain (&info); -if (!domain->parent) - domain->parent = x86_vector_domain; -else - hpet_msi_type.name ="IR-HPET-MSI" ; - } - -return domain; +return msi_create_irq_domain (NULL , minfo, parent); } int hpet_assign_irq(struct irq_domain *domain, struct hpet_dev *dev,
drivers/pci/msi.c +4 -3
@@ -1091,8 +1091,7 @@ void pci_msi_write_msg(struct irq_data *irq_data, struct msi_msg *msg)* Generate a unique ID number for each possible MSI source, the ID number * is only used within the irqdomain. */ -static inline irq_hw_number_t -msi_get_hwirq (struct pci_dev *dev,struct msi_desc *desc) +irq_hw_number_t pci_msi_calc_hwirq (struct pci_dev *dev,struct msi_desc *desc) {return (irq_hw_number_t )desc->msi_attrib.entry_nr | PCI_DEVID(dev->bus->number, dev->devfn) << 11 |
@@ -1163,9 +1162,11 @@ int msi_irq_domain_alloc_irqs(struct irq_domain *domain, int type,int i, virq;struct msi_desc *desc;int node =dev_to_node (&dev->dev); +struct msi_domain_info *info = domain->host_data;list_for_each_entry (desc, &dev->msi_list, list) { -arch_msi_irq_domain_set_hwirq (arg,msi_get_hwirq (dev, desc)); +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 ) {
include/linux/msi.h +1 -0
@@ -123,6 +123,7 @@ struct irq_domain *pci_msi_create_irq_domain(struct device_node *of_node,void pci_msi_write_msg (struct irq_data *irq_data,struct msi_msg *msg);int msi_irq_domain_alloc_irqs (struct irq_domain *domain,int type,struct pci_dev *dev,void *arg); +irq_hw_number_t pci_msi_calc_hwirq (struct pci_dev *dev,struct msi_desc *desc);irq_hw_number_t arch_msi_irq_domain_get_hwirq (void *arg);void arch_msi_irq_domain_set_hwirq (void *arg,irq_hw_number_t hwirq);
Signature · 1 line
1.7.10.4
RFC 15/17 PCI, MSI: Clean up unused irqdomain related code
In reply to Jiang LiuPCI MSI has been converted to use common MSI code, so kill unsued code.
--- arch/x86/kernel/apic/msi.c | 9 +------ drivers/pci/msi.c | 62 ++------------------------------------------ include/linux/msi.h | 13 ++-------- kernel/irq/msi.c | 6 +++-- 4 files changed, 9 insertions(+), 81 deletions(-)
arch/x86/kernel/apic/msi.c +1 -8
@@ -89,7 +89,7 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)if (domain ==NULL )return -ENOSYS ; -return msi_irq_domain_alloc_irqs (domain, type, dev, &info); +return pci_msi_irq_domain_alloc_irqs (domain, type, dev, &info); }void native_teardown_msi_irq (unsigned int irq)
@@ -97,13 +97,6 @@ void native_teardown_msi_irq(unsigned int irq)irq_domain_free_irqs (irq,1 ); } -irq_hw_number_t arch_msi_irq_domain_get_hwirq (void *arg) -{ -struct irq_alloc_info *info = arg; - -return info->msi_hwirq; -} -static void pci_msi_generate_hwirq (struct msi_domain_info *minfo,void *arg,struct msi_desc *desc) {
drivers/pci/msi.c +2 -60
68 lines not on this page · raw message
include/linux/msi.h +2 -11
@@ -73,9 +73,6 @@ struct msi_domain_info {int msi_domain_set_affinity (struct irq_data *data,const struct cpumask *mask,bool force); -void msi_domain_activate (struct irq_domain *domain,struct irq_data *irq_data); -void msi_domain_deactivate (struct irq_domain *domain, -struct irq_data *irq_data);struct irq_domain *msi_create_irq_domain (struct device_node *of_node,struct msi_domain_info *info,struct irq_domain *parent);
@@ -117,16 +114,10 @@ struct msi_chip { };#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN -struct irq_domain *pci_msi_create_irq_domain (struct device_node *of_node, -struct irq_chip *chip, -struct irq_domain *parent);void pci_msi_write_msg (struct irq_data *irq_data,struct msi_msg *msg); -int msi_irq_domain_alloc_irqs (struct irq_domain *domain,int type, -struct pci_dev *dev,void *arg); +int pci_msi_irq_domain_alloc_irqs (struct irq_domain *domain,int type, +struct pci_dev *dev,void *arg);irq_hw_number_t pci_msi_calc_hwirq (struct pci_dev *dev,struct msi_desc *desc); - -irq_hw_number_t arch_msi_irq_domain_get_hwirq (void *arg); -void arch_msi_irq_domain_set_hwirq (void *arg,irq_hw_number_t hwirq);#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */ #endif /* CONFIG_PCI_MSI */
kernel/irq/msi.c +4 -2
@@ -43,7 +43,8 @@ int msi_domain_set_affinity(struct irq_data *irq_data,return ret; } -void msi_domain_activate (struct irq_domain *domain,struct irq_data *irq_data) +static void msi_domain_activate (struct irq_domain *domain, +struct irq_data *irq_data) {struct msi_msg msg;
@@ -51,7 +52,8 @@ void msi_domain_activate(struct irq_domain *domain, struct irq_data *irq_data)irq_chip_write_msi_msg (irq_data, &msg); } -void msi_domain_deactivate (struct irq_domain *domain,struct irq_data *irq_data) +static void msi_domain_deactivate (struct irq_domain *domain, +struct irq_data *irq_data) {struct msi_msg msg;
Signature · 1 line
1.7.10.4
RFC 16/17 x86, htirq: Kill struct ht_irq_msg by reusing struct msi_msg
In reply to Jiang LiuReuse struct msi_msg for HT interrupts, so we could use common MSI code to manage HT interrupts later.
--- arch/x86/kernel/apic/htirq.c | 6 +++--- drivers/infiniband/hw/ipath/ipath_iba6110.c | 2 +- drivers/pci/htirq.c | 8 ++++---- include/linux/htirq.h | 14 +++++--------- 4 files changed, 13 insertions(+), 17 deletions(-)
arch/x86/kernel/apic/htirq.c +3 -3
@@ -34,7 +34,7 @@ ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) ret = parent->chip->irq_set_affinity (parent, mask, force);if (ret >=0 ) { -struct ht_irq_msg msg; +struct msi_msg msg;struct irq_cfg *cfg =irqd_cfg (data);fetch_ht_irq_msg (data->irq, &msg);
@@ -115,7 +115,7 @@ static void htirq_domain_free(struct irq_domain *domain, unsigned int virq,static void htirq_domain_activate (struct irq_domain *domain,struct irq_data *irq_data) { -struct ht_irq_msg msg; +struct msi_msg msg;struct irq_cfg *cfg =irqd_cfg (irq_data); msg.address_hi =HT_IRQ_HIGH_DEST_ID (cfg->dest_apicid);
@@ -137,7 +137,7 @@ static void htirq_domain_activate(struct irq_domain *domain,static void htirq_domain_deactivate (struct irq_domain *domain,struct irq_data *irq_data) { -struct ht_irq_msg msg; +struct msi_msg msg;memset (&msg,0 ,sizeof (msg));write_ht_irq_msg (irq_data->irq, &msg);
drivers/infiniband/hw/ipath/ipath_iba6110.c +1 -1
@@ -986,7 +986,7 @@ static int ipath_ht_intconfig(struct ipath_devdata *dd) }static void ipath_ht_irq_update (struct pci_dev *dev,int irq, -struct ht_irq_msg *msg) +struct msi_msg *msg) {struct ipath_devdata *dd =pci_get_drvdata (dev);u64 prev_intconfig = dd->ipath_intconfig;
drivers/pci/htirq.c +4 -4
@@ -23,7 +23,7 @@*/ static DEFINE_SPINLOCK (ht_irq_lock); -void write_ht_irq_msg (unsigned int irq,struct ht_irq_msg *msg) +void write_ht_irq_msg (unsigned int irq,struct msi_msg *msg) {struct ht_irq_cfg *cfg =irq_get_handler_data (irq);unsigned long flags;
@@ -43,7 +43,7 @@ void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) cfg->msg = *msg; } -void fetch_ht_irq_msg (unsigned int irq,struct ht_irq_msg *msg) +void fetch_ht_irq_msg (unsigned int irq,struct msi_msg *msg) {struct ht_irq_cfg *cfg =irq_get_handler_data (irq);
@@ -53,7 +53,7 @@ void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)void mask_ht_irq (struct irq_data *data) {struct ht_irq_cfg *cfg =irq_data_get_irq_handler_data (data); -struct ht_irq_msg msg = cfg->msg; +struct msi_msg msg = cfg->msg; msg.address_lo |=1 ;write_ht_irq_msg (data->irq, &msg);
@@ -62,7 +62,7 @@ void mask_ht_irq(struct irq_data *data)void unmask_ht_irq (struct irq_data *data) {struct ht_irq_cfg *cfg =irq_data_get_irq_handler_data (data); -struct ht_irq_msg msg = cfg->msg; +struct msi_msg msg = cfg->msg; msg.address_lo &= ~1 ;write_ht_irq_msg (data->irq, &msg);
include/linux/htirq.h +5 -9
@@ -1,16 +1,12 @@ #ifndef LINUX_HTIRQ_H #define LINUX_HTIRQ_H +#include <linux/msi.h> struct pci_dev; struct irq_data; -struct ht_irq_msg { - u32 address_lo; /* low 32 bits of the ht irq message */ - u32 address_hi; /* high 32 bits of the it irq message */ -}; - typedef void (ht_irq_update_t)(struct pci_dev *dev, int irq, - struct ht_irq_msg *msg); + struct msi_msg *msg); struct ht_irq_cfg { struct pci_dev *dev;
@@ -18,12 +14,12 @@ struct ht_irq_cfg {ht_irq_update_t *update;unsigned pos;unsigned idx; -struct ht_irq_msg msg; +struct msi_msg msg; };/* Helper functions.. */ -void fetch_ht_irq_msg (unsigned int irq,struct ht_irq_msg *msg); -void write_ht_irq_msg (unsigned int irq,struct ht_irq_msg *msg); +void fetch_ht_irq_msg (unsigned int irq,struct msi_msg *msg); +void write_ht_irq_msg (unsigned int irq,struct msi_msg *msg);void mask_ht_irq (struct irq_data *data);void unmask_ht_irq (struct irq_data *data);
Signature · 1 line
1.7.10.4
RFC 17/17 x86, htirq: Use common MSI code to manage Hypertransport interrupts
In reply to Jiang LiuHypertransport interrupt is a type of "Message Signalled Interrupt", so use common MSI code to manage it.
--- arch/x86/kernel/apic/htirq.c | 134 +++++++++++++++--------------------------- drivers/pci/Kconfig | 1 + drivers/pci/htirq.c | 16 ++--- include/linux/htirq.h | 5 +- 4 files changed, 60 insertions(+), 96 deletions(-)
arch/x86/kernel/apic/htirq.c +47 -87
@@ -17,37 +17,33 @@#include <linux/pci.h> #include <linux/htirq.h> #include <linux/irqdomain.h> +#include <linux/msi.h> #include <asm/hw_irq.h> #include <asm/apic.h> #include <asm/hypertransport.h> static struct irq_domain *htirq_domain; -/* -* Hypertransport interrupt support -*/ -static int -ht_set_affinity (struct irq_data *data,const struct cpumask *mask,bool force) +static void ht_irq_compose_msg (struct irq_data *data,struct msi_msg *msg) { -struct irq_data *parent = data->parent_data; -int ret; - - ret = parent->chip->irq_set_affinity (parent, mask, force); -if (ret >=0 ) { -struct msi_msg msg; -struct irq_cfg *cfg =irqd_cfg (data); - -fetch_ht_irq_msg (data->irq, &msg); - msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | -HT_IRQ_LOW_DEST_ID_MASK ); - msg.address_lo |=HT_IRQ_LOW_VECTOR (cfg->vector) | -HT_IRQ_LOW_DEST_ID (cfg->dest_apicid); - msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK ); - msg.address_hi |=HT_IRQ_HIGH_DEST_ID (cfg->dest_apicid); -write_ht_irq_msg (data->irq, &msg); - } - -return ret; +struct irq_cfg *cfg =irqd_cfg (data); +struct ht_irq_cfg *ht_cfg = data->chip_data; + + msg->address_hi =HT_IRQ_HIGH_DEST_ID (cfg->dest_apicid); + msg->address_lo =HT_IRQ_LOW_BASE | +HT_IRQ_LOW_DEST_ID (cfg->dest_apicid) | +HT_IRQ_LOW_VECTOR (cfg->vector) | +HT_IRQ_LOW_RQEOI_EDGE ; +if (ht_cfg->masked) + msg->address_lo |=HT_IRQ_LOW_IRQ_MASKED ; +if (apic->irq_dest_mode) + msg->address_lo |=HT_IRQ_LOW_DM_LOGICAL ; +else + msg->address_lo |=HT_IRQ_LOW_DM_PHYSICAL ; +if (apic->irq_delivery_mode == dest_LowestPrio) + msg->address_lo |=HT_IRQ_LOW_MT_ARBITRATED ; +else + msg->address_lo |=HT_IRQ_LOW_MT_FIXED ; }static struct irq_chip ht_irq_chip = {
@@ -55,40 +51,34 @@ static struct irq_chip ht_irq_chip = { .irq_mask = mask_ht_irq, .irq_unmask = unmask_ht_irq, .irq_ack = irq_chip_ack_parent, - .irq_set_affinity = ht_set_affinity, + .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_compose_msi_msg = ht_irq_compose_msg, + .irq_write_msi_msg = write_ht_irq_msg, .flags = IRQCHIP_SKIP_SET_WAKE, }; -static int htirq_domain_alloc (struct irq_domain *domain,unsigned int virq, -unsigned int nr_irqs,void *arg) +static irq_hw_number_t ht_irq_get_hwirq (struct msi_domain_info *minfo, +void *arg) { -struct ht_irq_cfg *ht_cfg;struct irq_alloc_info *info = arg; -struct pci_dev *dev; -irq_hw_number_t hwirq; -int ret; +struct pci_dev *dev = info->ht_dev; -if (nr_irqs >1 || !info) -return -EINVAL ; - - dev = info->ht_dev; - hwirq = (info->ht_idx &0xFF ) | +return (info->ht_idx &0xFF ) |PCI_DEVID (dev->bus->number, dev->devfn) <<8 | (pci_domain_nr (dev->bus) &0xFFFFFFFF ) <<24 ; -if (irq_find_mapping (domain, hwirq) >0 ) -return -EEXIST ; +} + +static int ht_irq_init (struct irq_domain *domain,struct msi_domain_info *minfo, +unsigned int virq,irq_hw_number_t hwirq,void *arg) +{ +struct ht_irq_cfg *ht_cfg; +struct irq_alloc_info *info = arg; ht_cfg =kmalloc (sizeof (*ht_cfg),GFP_KERNEL );if (!ht_cfg)return -ENOMEM ; - ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, info); -if (ret <0 ) { -kfree (ht_cfg); -return ret; - } -/* Initialize msg to a value that will never match the first write. */ ht_cfg->msg.address_lo =0xffffffff ; ht_cfg->msg.address_hi =0xffffffff ;
@@ -96,58 +86,30 @@ static int htirq_domain_alloc(struct irq_domain *domain, unsigned int virq, ht_cfg->update = info->ht_update; ht_cfg->pos = info->ht_pos; ht_cfg->idx =0x10 + (info->ht_idx *2 ); -irq_domain_set_info (domain, virq, hwirq, &ht_irq_chip, ht_cfg, + ht_cfg->masked = true; +irq_domain_set_info (domain, virq, hwirq, minfo->chip, ht_cfg, handle_edge_irq,NULL ,"edge" );return 0 ; } -static void htirq_domain_free (struct irq_domain *domain,unsigned int virq, -unsigned int nr_irqs) +static void ht_irq_free (struct irq_domain *domain,struct msi_domain_info *info, +unsigned int virq) {struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); -BUG_ON (nr_irqs !=1 );kfree (irq_data->chip_data); -irq_domain_free_irqs_top (domain, virq, nr_irqs); -} - -static void htirq_domain_activate (struct irq_domain *domain, -struct irq_data *irq_data) -{ -struct msi_msg msg; -struct irq_cfg *cfg =irqd_cfg (irq_data); - - msg.address_hi =HT_IRQ_HIGH_DEST_ID (cfg->dest_apicid); - msg.address_lo = -HT_IRQ_LOW_BASE | -HT_IRQ_LOW_DEST_ID (cfg->dest_apicid) | -HT_IRQ_LOW_VECTOR (cfg->vector) | - ((apic->irq_dest_mode ==0 ) ? -HT_IRQ_LOW_DM_PHYSICAL : -HT_IRQ_LOW_DM_LOGICAL ) | -HT_IRQ_LOW_RQEOI_EDGE | - ((apic->irq_delivery_mode != dest_LowestPrio) ? -HT_IRQ_LOW_MT_FIXED : -HT_IRQ_LOW_MT_ARBITRATED ) | -HT_IRQ_LOW_IRQ_MASKED ; -write_ht_irq_msg (irq_data->irq, &msg); } -static void htirq_domain_deactivate (struct irq_domain *domain, -struct irq_data *irq_data) -{ -struct msi_msg msg; - -memset (&msg,0 ,sizeof (msg)); -write_ht_irq_msg (irq_data->irq, &msg); -} +static struct msi_domain_ops ht_irq_domain_ops = { + .get_hwirq = ht_irq_get_hwirq, + .msi_init = ht_irq_init, + .msi_free = ht_irq_free, +}; -static struct irq_domain_ops htirq_domain_ops = { - .alloc = htirq_domain_alloc, - .free = htirq_domain_free, - .activate = htirq_domain_activate, - .deactivate = htirq_domain_deactivate, +static struct msi_domain_info ht_irq_domain_info = { + .ops = &ht_irq_domain_ops, + .chip = &ht_irq_chip, };void arch_init_htirq_domain (struct irq_domain *parent)
@@ -155,11 +117,9 @@ void arch_init_htirq_domain(struct irq_domain *parent)if (disable_apic)return ; - htirq_domain =irq_domain_add_tree (NULL , &htirq_domain_ops,NULL ); + htirq_domain =msi_create_irq_domain (NULL , &ht_irq_domain_info, parent);if (!htirq_domain)pr_warn ("failed to initialize irqdomain for HTIRQ.\n" ); -else - htirq_domain->parent = parent; } int arch_setup_ht_irq(int idx, int pos, struct pci_dev *dev,
drivers/pci/Kconfig +1 -0
@@ -68,6 +68,7 @@ config HT_IRQ bool "Interrupts on hypertransport devices" default y depends on PCI && X86_LOCAL_APIC + select GENERIC_MSI_IRQ_DOMAIN help This allows native hypertransport devices to use interrupts.
drivers/pci/htirq.c +9 -7
@@ -23,9 +23,9 @@*/ static DEFINE_SPINLOCK (ht_irq_lock); -void write_ht_irq_msg (unsigned int irq,struct msi_msg *msg) +void write_ht_irq_msg (struct irq_data *data,struct msi_msg *msg) { -struct ht_irq_cfg *cfg =irq_get_handler_data (irq); +struct ht_irq_cfg *cfg = data->chip_data;unsigned long flags;spin_lock_irqsave (&ht_irq_lock, flags);
@@ -38,14 +38,14 @@ void write_ht_irq_msg(unsigned int irq, struct msi_msg *msg)pci_write_config_dword (cfg->dev, cfg->pos +4 , msg->address_hi); }if (cfg->update) - cfg->update (cfg->dev, irq, msg); + cfg->update (cfg->dev, data->irq, msg);spin_unlock_irqrestore (&ht_irq_lock, flags); cfg->msg = *msg; } -void fetch_ht_irq_msg (unsigned int irq,struct msi_msg *msg) +void fetch_ht_irq_msg (struct irq_data *data,struct msi_msg *msg) { -struct ht_irq_cfg *cfg =irq_get_handler_data (irq); +struct ht_irq_cfg *cfg = data->chip_data; *msg = cfg->msg; }
@@ -56,7 +56,8 @@ void mask_ht_irq(struct irq_data *data)struct msi_msg msg = cfg->msg; msg.address_lo |=1 ; -write_ht_irq_msg (data->irq, &msg); +write_ht_irq_msg (data, &msg); + cfg->masked = true; }void unmask_ht_irq (struct irq_data *data)
@@ -65,7 +66,8 @@ void unmask_ht_irq(struct irq_data *data)struct msi_msg msg = cfg->msg; msg.address_lo &= ~1 ; -write_ht_irq_msg (data->irq, &msg); +write_ht_irq_msg (data, &msg); + cfg->masked = false; }/**
include/linux/htirq.h +3 -2
@@ -14,12 +14,13 @@ struct ht_irq_cfg {ht_irq_update_t *update;unsigned pos;unsigned idx; +bool masked;struct msi_msg msg; };/* Helper functions.. */ -void fetch_ht_irq_msg (unsigned int irq,struct msi_msg *msg); -void write_ht_irq_msg (unsigned int irq,struct msi_msg *msg); +void fetch_ht_irq_msg (struct irq_data *data,struct msi_msg *msg); +void write_ht_irq_msg (struct irq_data *data,struct msi_msg *msg);void mask_ht_irq (struct irq_data *data);void unmask_ht_irq (struct irq_data *data);
Signature · 1 line
1.7.10.4
Hi Jiang,
Quoted 8 lines · Jiang Liu
Some interrupt controllers, such as DMAR/HPET/HT_IRQ, work almost in the same as PCI MSI interrupt controller. And there some devices make use of PCI MSI mechanism for non-PCI devices on ARm/ARM64 platforms.
So this patches tries to split PCI MSI code into PCI dependent part and PCI independent part. The PCI independent part will be used to support other PCI MSI like interrupt controllers.
Quoted 5 lines
Patch 1-9 are clean ups for previous hierarchy irqdomain patchset and preparation for coming PCI MSI code reorganization. Patch 10-15 split PCI MSI code and implement common mechanism to support other MSI alike interrupt contollers.
Patch 16-17 convertsHT_IRQto use the common MSI support mechanism.
[...]
I used this patch series (or rather the v2 in your git tree) to rework the GICv3 ITS patch series. So far, the API seems cleaner (fewer global functions, increased flexibility), at the expense of a bit more complexity.
One thing is still missing though: the way the MSI stacked domain works at the moment prevents the use of the msi_chip infrastructure (you need to override arch_setup_msi_irqs, which in turn prevents the use of msi_chips using setup_irq/teardown_irq callbacks. On arm/arm64, most MSI controllers are using the latter, while it is likely that the newer ones will be using the stacked domains.
My solution to this is to slightly extend the msi_chip framework so that we can hock into the MSI domain framework on a per-msi-chip basis (see patch below). With this in place, I can completely get rid of any arm64-specific code (the msi_chip framework becomes good enough for us):
Quoted 1 line
From
5e9157ee7879953f89652d6ad9f296fc0ce6cb87Mon Sep 17 00:00:00 2001
From: Marc Zyngier <[email protected]>
Date: Wed, 12 Nov 2014 10:32:46 +0000
Subject: [PATCH v2 02/14] PCI/MSI: Allow an msi_chip to be associated to an
irq domain
The new MSI stacked domain has the interesting effect that it is quite hard to use if the architecture doesn't provide its own arch_setup_msi_irqs() function to override the default.
This inhibates the msi_chip infrastructure introduced in 0cbdcfcf427b (PCI: Introduce new MSI chip infrastructure), as it is not possible to use it as an indirection between the core MSI code and the MSI driver (useful when having multiple MSI controllers that do not share the same requirements). The setup_irq and teardown_irq are rendered useless, as their role is now taken over by the alloc/free functions in the irq domain code.
This patch introduces two optionnal fields to the msi_chip structure:
- a pointer to an irq domain, describing the MSI domain associated with this msi_chip. To be populated with msi_create_irq_domain.
- a domain_alloc_irqs() callback that has the same purpose as arch_setup_msi_irqs(), with the above domain as an additional parameter.
If both of these fields are non-NULL, then domain_alloc_irqs() is called, bypassing the setup_irq callback. This allows the MSI driver to use the domain stacking feature without mandating core support in the architecture.
Tested on arm64 with the GICv3 ITS.
--- drivers/pci/msi.c | 9 ++++++++- include/linux/msi.h | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-)
drivers/pci/msi.c +8 -1
@@ -63,8 +63,15 @@ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)/* * If an architecture wants to support multiple MSI, it needs to -* override arch_setup_msi_irqs() +* override arch_setup_msi_irqs(), or provide a way out on a per +* domain basis. */ +#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN +struct msi_chip *chip = dev->bus->msi; + +if (chip->domain && chip->domain_alloc_irqs) +return chip->domain_alloc_irqs (chip->domain, dev, nvec, type); +#endif if (type ==PCI_CAP_ID_MSI && nvec >1 )return 1 ;
include/linux/msi.h +5 -0
@@ -110,7 +110,12 @@ struct msi_chip {struct device *dev;struct device_node *of_node;struct list_head list; +#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN +struct irq_domain *domain; +int (*domain_alloc_irqs)(struct irq_domain *domain, +struct pci_dev *pdev,int nvec,int type); +#endif int (*setup_irq)(struct msi_chip *chip,struct pci_dev *dev,struct msi_desc *desc);void (*teardown_irq)(struct msi_chip *chip,unsigned int irq);
Signature · 9 lines
2.0.4 Thoughts? I'll post the full patch series later today. Thanks, M. -- Jazz is not dead. It just smells funny...
Quoted 11 lines · Marc Zyngier
This patch introduces two optionnal fields to the
msi_chipstructure:
- a pointer to an irq domain, describing the MSI domain associated with thismsi_chip. To be populated withmsi_create_irq_domain.
- adomain_alloc_irqs()callback that has the same purpose asarch_setup_msi_irqs(), with the above domain as an additional parameter.If both of these fields are non-NULL, then
domain_alloc_irqs()is called, bypassing thesetup_irqcallback. This allows the MSI driver to use the domain stacking feature without mandating core support in the architecture.
I'd rather have the callback in the irqdomain itself. Along with a callback to free the interrupts.
AFAICT is msi_chip more or less a wrapper around the actual MSI irq domain. So we rather move towards assigning irqdomain to the pci bus and get rid of msi_chip instead of adding another level of obscure indirection through msi_chip.
Thanks,
tglx
Quoted 13 lines · Thomas Gleixner
Quoted 11 lines · Marc Zyngier
This patch introduces two optionnal fields to the
msi_chipstructure:
- a pointer to an irq domain, describing the MSI domain associated with thismsi_chip. To be populated withmsi_create_irq_domain.
- adomain_alloc_irqs()callback that has the same purpose asarch_setup_msi_irqs(), with the above domain as an additional parameter.If both of these fields are non-NULL, then
domain_alloc_irqs()is called, bypassing thesetup_irqcallback. This allows the MSI driver to use the domain stacking feature without mandating core support in the architecture.
Quoted 7 lines
I'd rather have the callback in the irqdomain itself. Along with a callback to free the interrupts.
AFAICT is
msi_chipmore or less a wrapper around the actual MSI irq domain. So we rather move towards assigning irqdomain to the pci bus and get rid ofmsi_chipinstead of adding another level of obscure indirection throughmsi_chip.
Hi Thomas and Marc,
I'm trying to replace all weak functions , such as arch_setup_msi_irqs()/arch_setup_msi_irq(), in drivers/pci/msi.c.
The framework core changes are almost ready, but it does take time to convert current arch_setup_msi_irqs() implementations to new irqdomain interfaces.
Not sure whether it's the right direction to go:(
Regards!
Gerry
Quoted 5 lines
Thanks,
tglx
Hi Thomas,
Quoted 13 lines · Thomas Gleixner
Quoted 11 lines · Marc Zyngier
This patch introduces two optionnal fields to the
msi_chipstructure:
- a pointer to an irq domain, describing the MSI domain associated with thismsi_chip. To be populated withmsi_create_irq_domain.
- adomain_alloc_irqs()callback that has the same purpose asarch_setup_msi_irqs(), with the above domain as an additional parameter.If both of these fields are non-NULL, then
domain_alloc_irqs()is called, bypassing thesetup_irqcallback. This allows the MSI driver to use the domain stacking feature without mandating core support in the architecture.
Quoted 7 lines
I'd rather have the callback in the irqdomain itself. Along with a callback to free the interrupts.
AFAICT is
msi_chipmore or less a wrapper around the actual MSI irq domain. So we rather move towards assigning irqdomain to the pci bus and get rid ofmsi_chipinstead of adding another level of obscure indirection throughmsi_chip.
I can see that putting the irq domain at the bus level makes a lot of sense (assuming nobody tries to have multiple MSI controllers per bus...).
So I'm starting with something like this:
include/linux/irqdomain.h +5 -0
@@ -41,6 +41,7 @@ struct irq_domain;struct of_device_id ;struct irq_chip ;struct irq_data ; +struct device ;/* Number of irqs reserved for a legacy isa controller */ #define NUM_ISA_INTERRUPTS 16
@@ -76,6 +77,10 @@ struct irq_domain_ops { unsigned int nr_irqs);void (*activate)(struct irq_domain *d,struct irq_data *irq_data);void (*deactivate)(struct irq_domain *d,struct irq_data *irq_data); +int (*prepare_alloc_irqs)(struct irq_domain *d,struct device *dev, +unsigned int nr_irqs,int type); +int (*cleanup_free_irqs)(struct irq_domain *d,struct device *dev, +unsigned int virq,unsigned int nr_irqs);#endif };
How do you see this behaving? At the moment, I have the "prepare" callback directly calling into pci_msi_domain_alloc_irqs() so that the irqs get created, but I have the nagging feeling that it's not what you want... ;-) The main issue I can see is that if more than one domain in the stack implements that, who gets to call pci_msi_domain_alloc_irqs?
If we try to decouple those two, there is a problem with the creation of the intermediate structure (the irq_alloc_info that's in Jiang's patches), as this is a arch/driver/whatever specific structure.
For reference, I've pushed out my current branch (very much a work in progress):
http://git.kernel.org/cgit/linux/kernel/git/maz/arm-platforms.git/log/?h=irq/branch-from-hell
The commits related to this discussion are:
http://git.kernel.org/cgit/linux/kernel/git/maz/arm-platforms.git/commit/?h=irq/branch-from-hell&id=56ea48e6389fe461cb3ddf01e19afcdcd8f12f66
and
http://git.kernel.org/cgit/linux/kernel/git/maz/arm-platforms.git/commit/?h=irq/branch-from-hell&id=855ab8b937967854dd070de2d0aaa07639e19526
as well as the code making use of that:
http://git.kernel.org/cgit/linux/kernel/git/maz/arm-platforms.git/tree/drivers/irqchip/irq-gic-v3-its.c?h=irq/branch-from-hell&id=9f8ed988c2411831b7512006642e484c151e9a7a#n1184
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
Quoted 17 lines · Marc Zyngier
Quoted 16 lines · Thomas Gleixner
Quoted 11 lines · Marc Zyngier
This patch introduces two optionnal fields to the
msi_chipstructure:
- a pointer to an irq domain, describing the MSI domain associated with thismsi_chip. To be populated withmsi_create_irq_domain.
- adomain_alloc_irqs()callback that has the same purpose asarch_setup_msi_irqs(), with the above domain as an additional parameter.If both of these fields are non-NULL, then
domain_alloc_irqs()is called, bypassing thesetup_irqcallback. This allows the MSI driver to use the domain stacking feature without mandating core support in the architecture.I'd rather have the callback in the irqdomain itself. Along with a callback to free the interrupts.
Quoted 7 lines
Quoted 4 lines
AFAICT is
msi_chipmore or less a wrapper around the actual MSI irq domain. So we rather move towards assigning irqdomain to the pci bus and get rid ofmsi_chipinstead of adding another level of obscure indirection throughmsi_chip.I can see that putting the irq domain at the bus level makes a lot of sense (assuming nobody tries to have multiple MSI controllers per bus...).
That would be interesting :)
Quoted 31 lines
So I'm starting with something like this:
include/linux/irqdomain.h +5
-0@@ -41,6 +41,7 @@ struct irq_domain;struct of_device_id ;struct irq_chip ;struct irq_data ; +struct device ;/* Number of irqs reserved for a legacy isa controller */ #define NUM_ISA_INTERRUPTS 16@@ -76,6 +77,10 @@ struct irq_domain_ops { unsigned int nr_irqs);void (*activate)(struct irq_domain *d,struct irq_data *irq_data);void (*deactivate)(struct irq_domain *d,struct irq_data *irq_data); +int (*prepare_alloc_irqs)(struct irq_domain *d,struct device *dev, +unsigned int nr_irqs,int type); +int (*cleanup_free_irqs)(struct irq_domain *d,struct device *dev, +unsigned int virq,unsigned int nr_irqs);#endif };How do you see this behaving? At the moment, I have the "prepare" callback directly calling into
pci_msi_domain_alloc_irqs()so that the irqs get created, but I have the nagging feeling that it's not what you want... ;-) The main issue I can see is that if more than one domain in the stack implements that, who gets to callpci_msi_domain_alloc_irqs?
Quoted 3 lines
If we try to decouple those two, there is a problem with the creation of the intermediate structure (the
irq_alloc_infothat's in Jiang's patches), as this is aarch/driver/whateverspecific structure.
Hard to tell. I just saw Jiangs new series arrive and I want to look at that first before muttering nonsense.
Thanks,
tglx