* [RFC Part4 v1 01/17] x86, irq: Normalize x86 irq_chip name
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 02/17] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code Jiang Liu
` (16 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Some irq_chip names use underscore, others use hyphen. So normalize them.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
arch/x86/kernel/apic/msi.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index a220abbe842e..adc76eba59bd 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -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,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 02/17] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 01/17] x86, irq: Normalize x86 irq_chip name Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 03/17] x86, PCI/MSI: Simplify the way to deal with remapped MSI interrupts Jiang Liu
` (15 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Introduce 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.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
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(-)
diff --git a/arch/x86/kernel/apic/htirq.c b/arch/x86/kernel/apic/htirq.c
index 900f1401a452..1448df3f9e9f 100644
--- a/arch/x86/kernel/apic/htirq.c
+++ b/arch/x86/kernel/apic/htirq.c
@@ -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;
}
diff --git a/arch/x86/platform/uv/uv_irq.c b/arch/x86/platform/uv/uv_irq.c
index 66d531e71c9a..b242e0aada19 100644
--- a/arch/x86/platform/uv/uv_irq.c
+++ b/arch/x86/platform/uv/uv_irq.c
@@ -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);
}
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 50931e936149..fb7af45f9425 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -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);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 4811bee1b8a7..1da30ae88665 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -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;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 03/17] x86, PCI/MSI: Simplify the way to deal with remapped MSI interrupts
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 01/17] x86, irq: Normalize x86 irq_chip name Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 02/17] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 04/17] PCI/MSI: Replace msi_update_msg() with irq_chip_compose_msi_msg() Jiang Liu
` (14 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Simplify the way to deal with remapped MSI interrupts, so we could
kill irq_chip.irq_print_chip later.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
arch/x86/kernel/apic/msi.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index adc76eba59bd..12919b3c6cf4 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -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;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 04/17] PCI/MSI: Replace msi_update_msg() with irq_chip_compose_msi_msg()
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (2 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 03/17] x86, PCI/MSI: Simplify the way to deal with remapped MSI interrupts Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 05/17] PCI/MSI: Move msi_set_affinity() to PCI core Jiang Liu
` (13 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Function irq_chip_compose_msi_msg() can achieve the same goal as
msi_update_msg(), so kill msi_update_msg().
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
arch/x86/kernel/apic/msi.c | 25 ++++---------------------
1 file changed, 4 insertions(+), 21 deletions(-)
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 12919b3c6cf4..727e4254f124 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -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);
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 05/17] PCI/MSI: Move msi_set_affinity() to PCI core
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (3 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 04/17] PCI/MSI: Replace msi_update_msg() with irq_chip_compose_msi_msg() Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 06/17] genirq: Introduce callback irq_chip.irq_write_msi_msg Jiang Liu
` (12 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Move msi_set_affinity() to PCI core, so it could be reused later.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
arch/x86/kernel/apic/msi.c | 20 ++------------------
drivers/pci/msi.c | 16 ++++++++++++++++
include/linux/msi.h | 2 ++
3 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 727e4254f124..0b2261fe6adf 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -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,
};
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 8de7c8774fd2..49a8bd37189d 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -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.
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 662c628fc2fa..daea96489a39 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -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);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 06/17] genirq: Introduce callback irq_chip.irq_write_msi_msg
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (4 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 05/17] PCI/MSI: Move msi_set_affinity() to PCI core Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 07/17] x86, irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips Jiang Liu
` (11 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Introduce callback irq_chip.irq_write_msi_msg, so we could share common
code among MSI alike interrupt controllers, such as HPET and DMAR.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
include/linux/irq.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 041edd6dc409..99aea9925b21 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -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);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 07/17] x86, irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (5 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 06/17] genirq: Introduce callback irq_chip.irq_write_msi_msg Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 08/17] PCI/MSI: Use irq_chip.irq_write_msi_msg() to share common code Jiang Liu
` (10 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips, they
will be used to share common code later.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
arch/x86/kernel/apic/msi.c | 14 ++++++++++++++
drivers/pci/msi.c | 15 +++++++++++++--
include/linux/msi.h | 1 +
3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 0b2261fe6adf..842d71699912 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -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,
};
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 49a8bd37189d..b811739b43c5 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -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");
}
diff --git a/include/linux/msi.h b/include/linux/msi.h
index daea96489a39..312197f64070 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -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);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 08/17] PCI/MSI: Use irq_chip.irq_write_msi_msg() to share common code
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (6 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 07/17] x86, irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 09/17] x86, irq: Simplify MSI/DMAR/HPET implementation by using " Jiang Liu
` (9 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Change PCI MSI code to use irq_chip.irq_write_msi_msg() to share more
common code later.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
drivers/pci/msi.c | 24 ++++++------------------
include/linux/msi.h | 3 +++
2 files changed, 9 insertions(+), 18 deletions(-)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index b811739b43c5..cc6207e3b6bc 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -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 = {
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 312197f64070..bd0f9d8c6fe1 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -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);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 09/17] x86, irq: Simplify MSI/DMAR/HPET implementation by using common code
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (7 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 08/17] PCI/MSI: Use irq_chip.irq_write_msi_msg() to share common code Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 10/17] PCI, MSI: Split MSI code into PCI dependent and PCI independent parts Jiang Liu
` (8 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Use common code to simplify MSI/DMAR/HPET driver implementation.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
arch/x86/kernel/apic/msi.c | 81 ++++----------------------------------------
1 file changed, 6 insertions(+), 75 deletions(-)
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 842d71699912..f625c2f21377 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -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)
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 10/17] PCI, MSI: Split MSI code into PCI dependent and PCI independent parts
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (8 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 09/17] x86, irq: Simplify MSI/DMAR/HPET implementation by using " Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 11/17] PCI, MSI: Rename __read_msi_msg() as __pci_read_msi_msg() Jiang Liu
` (7 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Some 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.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
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
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 022e89745f86..7a8f1c5e65af 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -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"
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index cc6207e3b6bc..e1814f4be4b9 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -280,24 +280,6 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
__read_msi_msg(entry, msg);
}
-void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
-{
- /* Assert that the cache is valid, assuming that
- * valid messages are not all-zeroes. */
- BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo |
- entry->msg.data));
-
- *msg = entry->msg;
-}
-
-void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
-{
- struct msi_desc *entry = irq_get_msi_desc(irq);
-
- __get_cached_msi_msg(entry, msg);
-}
-EXPORT_SYMBOL_GPL(get_cached_msi_msg);
-
void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
if (entry->dev->current_state != PCI_D0) {
@@ -1101,22 +1083,6 @@ 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);
- irq_chip_write_msi_msg(data, &msg);
- }
-
- return ret;
-}
-
void pci_msi_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
{
struct msi_desc *desc = irq_data->msi_desc;
@@ -1177,22 +1143,6 @@ static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
irq_domain_free_irqs_top(domain, virq, nr_irqs);
}
-void msi_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));
- irq_chip_write_msi_msg(irq_data, &msg);
-}
-
-void msi_domain_deactivate(struct irq_domain *domain, struct irq_data *irq_data)
-{
- struct msi_msg msg;
-
- memset(&msg, 0, sizeof(msg));
- irq_chip_write_msi_msg(irq_data, &msg);
-}
-
static struct irq_domain_ops msi_domain_ops = {
.alloc = msi_domain_alloc,
.free = msi_domain_free,
diff --git a/include/linux/msi.h b/include/linux/msi.h
index bd0f9d8c6fe1..19502186a64d 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -4,25 +4,24 @@
#include <linux/kobject.h>
#include <linux/list.h>
+struct irq_data;
+struct irq_chip;
+struct irq_domain;
+struct device_node;
+
struct msi_msg {
u32 address_lo; /* low 32 bits of msi message address */
u32 address_hi; /* high 32 bits of msi message address */
u32 data; /* 16 bits of msi message data */
};
-/* Helper functions */
-struct irq_data;
-struct msi_desc;
-void mask_msi_irq(struct irq_data *data);
-void unmask_msi_irq(struct irq_data *data);
-void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-void __get_cached_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 get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
-void write_msi_msg(unsigned int irq, struct msi_msg *msg);
-
struct msi_desc {
+ struct list_head list;
+ unsigned int irq;
+ unsigned int nvec_used; /* number of messages */
+ struct msi_msg msg; /* Last set MSI message */
+
+#ifdef CONFIG_PCI_MSI
struct {
__u8 is_msix : 1;
__u8 multiple: 3; /* log2 num of messages allocated */
@@ -34,21 +33,40 @@ struct msi_desc {
} msi_attrib;
u32 masked; /* mask bits */
- unsigned int irq;
- unsigned int nvec_used; /* number of messages */
- struct list_head list;
union {
void __iomem *mask_base;
u8 mask_pos;
};
struct pci_dev *dev;
-
- /* Last set MSI message */
- struct msi_msg msg;
+#endif
};
/*
+ * Some drivers unconditionally reference {mask|unmask}_msi_irq(),
+ * so can't guard them with CONFIG_PCI_MSI
+ */
+void mask_msi_irq(struct irq_data *data);
+void unmask_msi_irq(struct irq_data *data);
+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
+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);
+#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
+
+#ifdef CONFIG_PCI_MSI
+/* Helper functions */
+void __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);
+
+/*
* The arch hooks to setup up msi irqs. Those functions are
* implemented as weak symbols so that they /can/ be overriden by
* architecture specific code if needed.
@@ -76,14 +94,6 @@ struct msi_chip {
};
#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
-struct irq_domain;
-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);
@@ -95,4 +105,6 @@ 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 */
+
#endif /* LINUX_MSI_H */
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index e9b580eccc01..9c4c5d4d58e9 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -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
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
index fff17381f0af..d12123526e2b 100644
--- a/kernel/irq/Makefile
+++ b/kernel/irq/Makefile
@@ -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
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
new file mode 100644
index 000000000000..6ae0bd7ee204
--- /dev/null
+++ b/kernel/irq/msi.c
@@ -0,0 +1,61 @@
+/*
+ * linux/kernel/irq/msi.c
+ *
+ * Copyright (C) 2014 Intel Corp.
+ * Author: Jiang Liu <jiang.liu@linux.intel.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file contains common code to support Message Signalled Interrupt for
+ * PCI compatible and non PCI compatible devices.
+ */
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/msi.h>
+
+void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+{
+ *msg = entry->msg;
+}
+
+void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+ struct msi_desc *entry = irq_get_msi_desc(irq);
+
+ __get_cached_msi_msg(entry, msg);
+}
+EXPORT_SYMBOL_GPL(get_cached_msi_msg);
+
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+int msi_domain_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
+{
+ struct irq_data *parent = irq_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) {
+ BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
+ irq_chip_write_msi_msg(irq_data, &msg);
+ }
+
+ return ret;
+}
+
+void msi_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));
+ irq_chip_write_msi_msg(irq_data, &msg);
+}
+
+void msi_domain_deactivate(struct irq_domain *domain, struct irq_data *irq_data)
+{
+ struct msi_msg msg;
+
+ memset(&msg, 0, sizeof(msg));
+ irq_chip_write_msi_msg(irq_data, &msg);
+}
+#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 11/17] PCI, MSI: Rename __read_msi_msg() as __pci_read_msi_msg()
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (9 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 10/17] PCI, MSI: Split MSI code into PCI dependent and PCI independent parts Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 12/17] PCI, MSI: Rename __write_msi_msg() as __pci_write_msi_msg() Jiang Liu
` (6 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Rename __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.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
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(-)
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
index 8ab5add4ac82..90f756d0f58f 100644
--- a/arch/powerpc/platforms/pseries/msi.c
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -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;
}
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index 093f5f4272d3..a48ca2f8b93e 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -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 ||
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index e1814f4be4b9..6011dfb475a1 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -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) {
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 19502186a64d..4b0d070ff481 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -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);
/*
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 12/17] PCI, MSI: Rename __write_msi_msg() as __pci_write_msi_msg()
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (10 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 11/17] PCI, MSI: Rename __read_msi_msg() as __pci_read_msi_msg() Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 13/17] MSI: Provide irqdomain support for generic MSI Jiang Liu
` (5 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Rename __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.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
arch/x86/pci/xen.c | 2 +-
drivers/pci/msi.c | 9 ++++-----
include/linux/msi.h | 3 ++-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index a48ca2f8b93e..1cfbe32c4b1c 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -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,
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 6011dfb475a1..80be534df522 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -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);
}
/*
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 4b0d070ff481..5639970db71d 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -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
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 13/17] MSI: Provide irqdomain support for generic MSI
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (11 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 12/17] PCI, MSI: Rename __write_msi_msg() as __pci_write_msi_msg() Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 14/17] x86, PCI, MSI: Use common code to manage MSI interrupts Jiang Liu
` (4 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Enhance generic MSI code to support hierarchy irqdomain.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
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(-)
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index f625c2f21377..9774092012b8 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -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
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 80be534df522..17343cb4d756 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -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;
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 5639970db71d..43c0a7ae0df7 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -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);
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 6ae0bd7ee204..85a50254d815 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -58,4 +58,74 @@ void msi_domain_deactivate(struct irq_domain *domain, struct irq_data *irq_data)
memset(&msg, 0, sizeof(msg));
irq_chip_write_msi_msg(irq_data, &msg);
}
+
+static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ int i, ret;
+ struct msi_domain_info *info = domain->host_data;
+ struct msi_domain_ops *ops = info->ops;
+ irq_hw_number_t hwirq = ops->get_hwirq(info, arg);
+
+ if (irq_find_mapping(domain, hwirq) > 0)
+ return -EEXIST;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < nr_irqs; i++) {
+ ret = ops->msi_init(domain, info, virq + i, hwirq + i, arg);
+ if (ret < 0) {
+ if (ops->msi_free) {
+ for (i--; i > 0; i--)
+ ops->msi_free(domain, info, virq + i);
+ }
+ irq_domain_free_irqs_top(domain, virq, nr_irqs);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ int i;
+ struct msi_domain_info *info = domain->host_data;
+
+ if (info->ops->msi_free) {
+ for (i = 0; i < nr_irqs; i++)
+ info->ops->msi_free(domain, info, virq + i);
+ }
+ irq_domain_free_irqs_top(domain, virq, nr_irqs);
+}
+
+static struct irq_domain_ops msi_domain_ops = {
+ .alloc = msi_domain_alloc,
+ .free = msi_domain_free,
+ .activate = msi_domain_activate,
+ .deactivate = msi_domain_deactivate,
+};
+
+struct irq_domain *msi_create_irq_domain(struct device_node *of_node,
+ struct msi_domain_info *info,
+ struct irq_domain *parent)
+{
+ struct irq_domain *domain;
+
+ domain = irq_domain_add_tree(of_node, &msi_domain_ops, info);
+ if (!domain)
+ return NULL;
+
+ domain->parent = parent;
+
+ return domain;
+}
+
+struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain)
+{
+ return (struct msi_domain_info *)domain->host_data;
+}
#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 14/17] x86, PCI, MSI: Use common code to manage MSI interrupts
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (12 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 13/17] MSI: Provide irqdomain support for generic MSI Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 15/17] PCI, MSI: Clean up unused irqdomain related code Jiang Liu
` (3 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Convert x86 PCI MSI interrupt driver to use common MSI code.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
arch/x86/kernel/apic/msi.c | 200 ++++++++++++++++++++++++++------------------
drivers/pci/msi.c | 7 +-
include/linux/msi.h | 1 +
3 files changed, 124 insertions(+), 84 deletions(-)
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 9774092012b8..6bd339ed59f5 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -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,
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 17343cb4d756..adfabc9add24 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -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) {
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 43c0a7ae0df7..7b102148c4c6 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -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);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 15/17] PCI, MSI: Clean up unused irqdomain related code
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (13 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 14/17] x86, PCI, MSI: Use common code to manage MSI interrupts Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 16/17] x86, htirq: Kill struct ht_irq_msg by reusing struct msi_msg Jiang Liu
` (2 subsequent siblings)
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
PCI MSI has been converted to use common MSI code, so kill unsued code.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
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(-)
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 6bd339ed59f5..15168893fcc3 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -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)
{
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index adfabc9add24..1c5c7720b74c 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -1098,66 +1098,8 @@ irq_hw_number_t pci_msi_calc_hwirq(struct pci_dev *dev, struct msi_desc *desc)
(pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
}
-static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
- unsigned int nr_irqs, void *arg)
-{
- int i, ret;
- irq_hw_number_t hwirq = arch_msi_irq_domain_get_hwirq(arg);
-
- if (irq_find_mapping(domain, hwirq) > 0)
- return -EEXIST;
-
- ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
- if (ret < 0)
- return ret;
-
- for (i = 0; i < nr_irqs; i++) {
- irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
- domain->host_data, NULL);
- __irq_set_handler(virq + i, handle_edge_irq, 0, "edge");
- }
-
- return ret;
-}
-
-static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
- unsigned int nr_irqs)
-{
- int i;
-
- for (i = 0; i < nr_irqs; i++) {
- struct msi_desc *desc = irq_get_msi_desc(virq);
-
- if (desc)
- desc->irq = 0;
- }
- irq_domain_free_irqs_top(domain, virq, nr_irqs);
-}
-
-static struct irq_domain_ops msi_domain_ops = {
- .alloc = msi_domain_alloc,
- .free = msi_domain_free,
- .activate = msi_domain_activate,
- .deactivate = msi_domain_deactivate,
-};
-
-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;
-
- domain = irq_domain_add_tree(of_node, &msi_domain_ops, chip);
- if (!domain)
- return NULL;
-
- domain->parent = parent;
-
- return domain;
-}
-
-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)
{
int i, virq;
struct msi_desc *desc;
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 7b102148c4c6..0c1446e48572 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -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 */
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 85a50254d815..4f9f56e75804 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -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;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 16/17] x86, htirq: Kill struct ht_irq_msg by reusing struct msi_msg
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (14 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 15/17] PCI, MSI: Clean up unused irqdomain related code Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-09 15:10 ` [RFC Part4 v1 17/17] x86, htirq: Use common MSI code to manage Hypertransport interrupts Jiang Liu
2014-11-12 13:47 ` [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Marc Zyngier
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Reuse struct msi_msg for HT interrupts, so we could use common MSI code
to manage HT interrupts later.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
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(-)
diff --git a/arch/x86/kernel/apic/htirq.c b/arch/x86/kernel/apic/htirq.c
index 1448df3f9e9f..b6503510f1af 100644
--- a/arch/x86/kernel/apic/htirq.c
+++ b/arch/x86/kernel/apic/htirq.c
@@ -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);
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index 7cc305488a3d..b49ce8942b57 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -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;
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
index 7eb4109a3df4..3bbbc5cdcb9b 100644
--- a/drivers/pci/htirq.c
+++ b/drivers/pci/htirq.c
@@ -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);
diff --git a/include/linux/htirq.h b/include/linux/htirq.h
index d4a527e58434..98e432f7f9b1 100644
--- a/include/linux/htirq.h
+++ b/include/linux/htirq.h
@@ -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);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 17/17] x86, htirq: Use common MSI code to manage Hypertransport interrupts
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (15 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 16/17] x86, htirq: Kill struct ht_irq_msg by reusing struct msi_msg Jiang Liu
@ 2014-11-09 15:10 ` Jiang Liu
2014-11-12 13:47 ` [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Marc Zyngier
17 siblings, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-09 15:10 UTC (permalink / raw)
To: linux-arm-kernel
Hypertransport interrupt is a type of "Message Signalled Interrupt",
so use common MSI code to manage it.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
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(-)
diff --git a/arch/x86/kernel/apic/htirq.c b/arch/x86/kernel/apic/htirq.c
index b6503510f1af..230e37ab3948 100644
--- a/arch/x86/kernel/apic/htirq.c
+++ b/arch/x86/kernel/apic/htirq.c
@@ -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,
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 7a8f1c5e65af..22f948f9738a 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -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.
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
index 3bbbc5cdcb9b..27b09b266bb6 100644
--- a/drivers/pci/htirq.c
+++ b/drivers/pci/htirq.c
@@ -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;
}
/**
diff --git a/include/linux/htirq.h b/include/linux/htirq.h
index 98e432f7f9b1..c5d03a81809c 100644
--- a/include/linux/htirq.h
+++ b/include/linux/htirq.h
@@ -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);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message
2014-11-09 15:10 [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Jiang Liu
` (16 preceding siblings ...)
2014-11-09 15:10 ` [RFC Part4 v1 17/17] x86, htirq: Use common MSI code to manage Hypertransport interrupts Jiang Liu
@ 2014-11-12 13:47 ` Marc Zyngier
2014-11-12 14:46 ` Thomas Gleixner
17 siblings, 1 reply; 23+ messages in thread
From: Marc Zyngier @ 2014-11-12 13:47 UTC (permalink / raw)
To: linux-arm-kernel
Hi Jiang,
On 09/11/14 15:10, Jiang Liu wrote:
> 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.
[...]
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):
>From 5e9157ee7879953f89652d6ad9f296fc0ce6cb87 Mon Sep 17 00:00:00 2001
From: Marc Zyngier <marc.zyngier@arm.com>
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.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
drivers/pci/msi.c | 9 ++++++++-
include/linux/msi.h | 5 +++++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 6c38306..baefc21 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -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;
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 0789a4d..7170eea 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -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);
--
2.0.4
Thoughts? I'll post the full patch series later today.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message
2014-11-12 13:47 ` [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message Marc Zyngier
@ 2014-11-12 14:46 ` Thomas Gleixner
2014-11-12 14:52 ` Jiang Liu
2014-11-13 11:27 ` Marc Zyngier
0 siblings, 2 replies; 23+ messages in thread
From: Thomas Gleixner @ 2014-11-12 14:46 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, 12 Nov 2014, Marc Zyngier wrote:
> 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.
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
^ permalink raw reply [flat|nested] 23+ messages in thread
* [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message
2014-11-12 14:46 ` Thomas Gleixner
@ 2014-11-12 14:52 ` Jiang Liu
2014-11-13 11:27 ` Marc Zyngier
1 sibling, 0 replies; 23+ messages in thread
From: Jiang Liu @ 2014-11-12 14:52 UTC (permalink / raw)
To: linux-arm-kernel
On 2014/11/12 22:46, Thomas Gleixner wrote:
> On Wed, 12 Nov 2014, Marc Zyngier wrote:
>> 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.
>
> 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.
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
>
> Thanks,
>
> tglx
>
^ permalink raw reply [flat|nested] 23+ messages in thread
* [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message
2014-11-12 14:46 ` Thomas Gleixner
2014-11-12 14:52 ` Jiang Liu
@ 2014-11-13 11:27 ` Marc Zyngier
2014-11-13 13:27 ` Thomas Gleixner
1 sibling, 1 reply; 23+ messages in thread
From: Marc Zyngier @ 2014-11-13 11:27 UTC (permalink / raw)
To: linux-arm-kernel
Hi Thomas,
On 12/11/14 14:46, Thomas Gleixner wrote:
> On Wed, 12 Nov 2014, Marc Zyngier wrote:
>> 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.
>
> 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.
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:
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 640a1ec..07e50fc 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -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.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC Part4 v1 00/17] Refine support of non-PCI-compliant Message
2014-11-13 11:27 ` Marc Zyngier
@ 2014-11-13 13:27 ` Thomas Gleixner
0 siblings, 0 replies; 23+ messages in thread
From: Thomas Gleixner @ 2014-11-13 13:27 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, 13 Nov 2014, Marc Zyngier wrote:
> On 12/11/14 14:46, Thomas Gleixner wrote:
> > On Wed, 12 Nov 2014, Marc Zyngier wrote:
> >> 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.
> >
> > 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.
>
> 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 :)
> So I'm starting with something like this:
>
> diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
> index 640a1ec..07e50fc 100644
> --- a/include/linux/irqdomain.h
> +++ b/include/linux/irqdomain.h
> @@ -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.
Hard to tell. I just saw Jiangs new series arrive and I want to look
at that first before muttering nonsense.
Thanks,
tglx
^ permalink raw reply [flat|nested] 23+ messages in thread