Commit e4ae4c8e authored by Thomas Gleixner's avatar Thomas Gleixner

Merge branch 'irq/core' into x86/apic

Pick up the dependencies for the vector management rework series.
parents ae41a2a4 ec0f7cd2
...@@ -41,8 +41,8 @@ extern int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, ...@@ -41,8 +41,8 @@ extern int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg); unsigned int nr_irqs, void *arg);
extern void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq, extern void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs); unsigned int nr_irqs);
extern void mp_irqdomain_activate(struct irq_domain *domain, extern int mp_irqdomain_activate(struct irq_domain *domain,
struct irq_data *irq_data); struct irq_data *irq_data, bool early);
extern void mp_irqdomain_deactivate(struct irq_domain *domain, extern void mp_irqdomain_deactivate(struct irq_domain *domain,
struct irq_data *irq_data); struct irq_data *irq_data);
extern int mp_irqdomain_ioapic_idx(struct irq_domain *domain); extern int mp_irqdomain_ioapic_idx(struct irq_domain *domain);
......
...@@ -112,8 +112,8 @@ static void htirq_domain_free(struct irq_domain *domain, unsigned int virq, ...@@ -112,8 +112,8 @@ static void htirq_domain_free(struct irq_domain *domain, unsigned int virq,
irq_domain_free_irqs_top(domain, virq, nr_irqs); irq_domain_free_irqs_top(domain, virq, nr_irqs);
} }
static void htirq_domain_activate(struct irq_domain *domain, static int htirq_domain_activate(struct irq_domain *domain,
struct irq_data *irq_data) struct irq_data *irq_data, bool early)
{ {
struct ht_irq_msg msg; struct ht_irq_msg msg;
struct irq_cfg *cfg = irqd_cfg(irq_data); struct irq_cfg *cfg = irqd_cfg(irq_data);
...@@ -132,6 +132,7 @@ static void htirq_domain_activate(struct irq_domain *domain, ...@@ -132,6 +132,7 @@ static void htirq_domain_activate(struct irq_domain *domain,
HT_IRQ_LOW_MT_ARBITRATED) | HT_IRQ_LOW_MT_ARBITRATED) |
HT_IRQ_LOW_IRQ_MASKED; HT_IRQ_LOW_IRQ_MASKED;
write_ht_irq_msg(irq_data->irq, &msg); write_ht_irq_msg(irq_data->irq, &msg);
return 0;
} }
static void htirq_domain_deactivate(struct irq_domain *domain, static void htirq_domain_deactivate(struct irq_domain *domain,
......
...@@ -2137,7 +2137,7 @@ static inline void __init check_timer(void) ...@@ -2137,7 +2137,7 @@ static inline void __init check_timer(void)
unmask_ioapic_irq(irq_get_irq_data(0)); unmask_ioapic_irq(irq_get_irq_data(0));
} }
irq_domain_deactivate_irq(irq_data); irq_domain_deactivate_irq(irq_data);
irq_domain_activate_irq(irq_data); irq_domain_activate_irq(irq_data, false);
if (timer_irq_works()) { if (timer_irq_works()) {
if (disable_timer_pin_1 > 0) if (disable_timer_pin_1 > 0)
clear_IO_APIC_pin(0, pin1); clear_IO_APIC_pin(0, pin1);
...@@ -2159,7 +2159,7 @@ static inline void __init check_timer(void) ...@@ -2159,7 +2159,7 @@ static inline void __init check_timer(void)
*/ */
replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2); replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2);
irq_domain_deactivate_irq(irq_data); irq_domain_deactivate_irq(irq_data);
irq_domain_activate_irq(irq_data); irq_domain_activate_irq(irq_data, false);
legacy_pic->unmask(0); legacy_pic->unmask(0);
if (timer_irq_works()) { if (timer_irq_works()) {
apic_printk(APIC_QUIET, KERN_INFO "....... works.\n"); apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
...@@ -3018,8 +3018,8 @@ void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq, ...@@ -3018,8 +3018,8 @@ void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
irq_domain_free_irqs_top(domain, virq, nr_irqs); irq_domain_free_irqs_top(domain, virq, nr_irqs);
} }
void mp_irqdomain_activate(struct irq_domain *domain, int mp_irqdomain_activate(struct irq_domain *domain,
struct irq_data *irq_data) struct irq_data *irq_data, bool early)
{ {
unsigned long flags; unsigned long flags;
struct irq_pin_list *entry; struct irq_pin_list *entry;
...@@ -3029,6 +3029,7 @@ void mp_irqdomain_activate(struct irq_domain *domain, ...@@ -3029,6 +3029,7 @@ void mp_irqdomain_activate(struct irq_domain *domain,
for_each_irq_pin(entry, data->irq_2_pin) for_each_irq_pin(entry, data->irq_2_pin)
__ioapic_write_entry(entry->apic, entry->pin, data->entry); __ioapic_write_entry(entry->apic, entry->pin, data->entry);
raw_spin_unlock_irqrestore(&ioapic_lock, flags); raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return 0;
} }
void mp_irqdomain_deactivate(struct irq_domain *domain, void mp_irqdomain_deactivate(struct irq_domain *domain,
......
...@@ -127,10 +127,11 @@ static void uv_domain_free(struct irq_domain *domain, unsigned int virq, ...@@ -127,10 +127,11 @@ static void uv_domain_free(struct irq_domain *domain, unsigned int virq,
* Re-target the irq to the specified CPU and enable the specified MMR located * Re-target the irq to the specified CPU and enable the specified MMR located
* on the specified blade to allow the sending of MSIs to the specified CPU. * on the specified blade to allow the sending of MSIs to the specified CPU.
*/ */
static void uv_domain_activate(struct irq_domain *domain, static int uv_domain_activate(struct irq_domain *domain,
struct irq_data *irq_data) struct irq_data *irq_data, bool early)
{ {
uv_program_mmr(irqd_cfg(irq_data), irq_data->chip_data); uv_program_mmr(irqd_cfg(irq_data), irq_data->chip_data);
return 0;
} }
/* /*
......
...@@ -140,8 +140,9 @@ static int xgene_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio) ...@@ -140,8 +140,9 @@ static int xgene_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio)
return irq_create_fwspec_mapping(&fwspec); return irq_create_fwspec_mapping(&fwspec);
} }
static void xgene_gpio_sb_domain_activate(struct irq_domain *d, static int xgene_gpio_sb_domain_activate(struct irq_domain *d,
struct irq_data *irq_data) struct irq_data *irq_data,
bool early)
{ {
struct xgene_gpio_sb *priv = d->host_data; struct xgene_gpio_sb *priv = d->host_data;
u32 gpio = HWIRQ_TO_GPIO(priv, irq_data->hwirq); u32 gpio = HWIRQ_TO_GPIO(priv, irq_data->hwirq);
...@@ -150,11 +151,12 @@ static void xgene_gpio_sb_domain_activate(struct irq_domain *d, ...@@ -150,11 +151,12 @@ static void xgene_gpio_sb_domain_activate(struct irq_domain *d,
dev_err(priv->gc.parent, dev_err(priv->gc.parent,
"Unable to configure XGene GPIO standby pin %d as IRQ\n", "Unable to configure XGene GPIO standby pin %d as IRQ\n",
gpio); gpio);
return; return -ENOSPC;
} }
xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_SEL_LO, xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_SEL_LO,
gpio * 2, 1); gpio * 2, 1);
return 0;
} }
static void xgene_gpio_sb_domain_deactivate(struct irq_domain *d, static void xgene_gpio_sb_domain_deactivate(struct irq_domain *d,
......
...@@ -4170,8 +4170,8 @@ static void irq_remapping_free(struct irq_domain *domain, unsigned int virq, ...@@ -4170,8 +4170,8 @@ static void irq_remapping_free(struct irq_domain *domain, unsigned int virq,
irq_domain_free_irqs_common(domain, virq, nr_irqs); irq_domain_free_irqs_common(domain, virq, nr_irqs);
} }
static void irq_remapping_activate(struct irq_domain *domain, static int irq_remapping_activate(struct irq_domain *domain,
struct irq_data *irq_data) struct irq_data *irq_data, bool early)
{ {
struct amd_ir_data *data = irq_data->chip_data; struct amd_ir_data *data = irq_data->chip_data;
struct irq_2_irte *irte_info = &data->irq_2_irte; struct irq_2_irte *irte_info = &data->irq_2_irte;
...@@ -4180,6 +4180,7 @@ static void irq_remapping_activate(struct irq_domain *domain, ...@@ -4180,6 +4180,7 @@ static void irq_remapping_activate(struct irq_domain *domain,
if (iommu) if (iommu)
iommu->irte_ops->activate(data->entry, irte_info->devid, iommu->irte_ops->activate(data->entry, irte_info->devid,
irte_info->index); irte_info->index);
return 0;
} }
static void irq_remapping_deactivate(struct irq_domain *domain, static void irq_remapping_deactivate(struct irq_domain *domain,
......
...@@ -1389,12 +1389,13 @@ static void intel_irq_remapping_free(struct irq_domain *domain, ...@@ -1389,12 +1389,13 @@ static void intel_irq_remapping_free(struct irq_domain *domain,
irq_domain_free_irqs_common(domain, virq, nr_irqs); irq_domain_free_irqs_common(domain, virq, nr_irqs);
} }
static void intel_irq_remapping_activate(struct irq_domain *domain, static int intel_irq_remapping_activate(struct irq_domain *domain,
struct irq_data *irq_data) struct irq_data *irq_data, bool early)
{ {
struct intel_ir_data *data = irq_data->chip_data; struct intel_ir_data *data = irq_data->chip_data;
modify_irte(&data->irq_2_iommu, &data->irte_entry); modify_irte(&data->irq_2_iommu, &data->irte_entry);
return 0;
} }
static void intel_irq_remapping_deactivate(struct irq_domain *domain, static void intel_irq_remapping_deactivate(struct irq_domain *domain,
......
...@@ -2186,8 +2186,8 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, ...@@ -2186,8 +2186,8 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
return 0; return 0;
} }
static void its_irq_domain_activate(struct irq_domain *domain, static int its_irq_domain_activate(struct irq_domain *domain,
struct irq_data *d) struct irq_data *d, bool early)
{ {
struct its_device *its_dev = irq_data_get_irq_chip_data(d); struct its_device *its_dev = irq_data_get_irq_chip_data(d);
u32 event = its_get_event_id(d); u32 event = its_get_event_id(d);
...@@ -2205,6 +2205,7 @@ static void its_irq_domain_activate(struct irq_domain *domain, ...@@ -2205,6 +2205,7 @@ static void its_irq_domain_activate(struct irq_domain *domain,
/* Map the GIC IRQ and event to the device */ /* Map the GIC IRQ and event to the device */
its_send_mapti(its_dev, d->hwirq, event); its_send_mapti(its_dev, d->hwirq, event);
return 0;
} }
static void its_irq_domain_deactivate(struct irq_domain *domain, static void its_irq_domain_deactivate(struct irq_domain *domain,
...@@ -2678,8 +2679,8 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq ...@@ -2678,8 +2679,8 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq
return err; return err;
} }
static void its_vpe_irq_domain_activate(struct irq_domain *domain, static int its_vpe_irq_domain_activate(struct irq_domain *domain,
struct irq_data *d) struct irq_data *d, bool early)
{ {
struct its_vpe *vpe = irq_data_get_irq_chip_data(d); struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
...@@ -2687,6 +2688,7 @@ static void its_vpe_irq_domain_activate(struct irq_domain *domain, ...@@ -2687,6 +2688,7 @@ static void its_vpe_irq_domain_activate(struct irq_domain *domain,
vpe->col_idx = cpumask_first(cpu_online_mask); vpe->col_idx = cpumask_first(cpu_online_mask);
its_send_vmapp(vpe, true); its_send_vmapp(vpe, true);
its_send_vinvall(vpe); its_send_vinvall(vpe);
return 0;
} }
static void its_vpe_irq_domain_deactivate(struct irq_domain *domain, static void its_vpe_irq_domain_deactivate(struct irq_domain *domain,
......
...@@ -289,13 +289,14 @@ static int stm32_gpio_domain_translate(struct irq_domain *d, ...@@ -289,13 +289,14 @@ static int stm32_gpio_domain_translate(struct irq_domain *d,
return 0; return 0;
} }
static void stm32_gpio_domain_activate(struct irq_domain *d, static int stm32_gpio_domain_activate(struct irq_domain *d,
struct irq_data *irq_data) struct irq_data *irq_data, bool early)
{ {
struct stm32_gpio_bank *bank = d->host_data; struct stm32_gpio_bank *bank = d->host_data;
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_nr); regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_nr);
return 0;
} }
static int stm32_gpio_domain_alloc(struct irq_domain *d, static int stm32_gpio_domain_alloc(struct irq_domain *d,
......
...@@ -1113,6 +1113,28 @@ static inline u32 irq_reg_readl(struct irq_chip_generic *gc, ...@@ -1113,6 +1113,28 @@ static inline u32 irq_reg_readl(struct irq_chip_generic *gc,
return readl(gc->reg_base + reg_offset); return readl(gc->reg_base + reg_offset);
} }
struct irq_matrix;
struct irq_matrix *irq_alloc_matrix(unsigned int matrix_bits,
unsigned int alloc_start,
unsigned int alloc_end);
void irq_matrix_online(struct irq_matrix *m);
void irq_matrix_offline(struct irq_matrix *m);
void irq_matrix_assign_system(struct irq_matrix *m, unsigned int bit, bool replace);
int irq_matrix_reserve_managed(struct irq_matrix *m, const struct cpumask *msk);
void irq_matrix_remove_managed(struct irq_matrix *m, const struct cpumask *msk);
int irq_matrix_alloc_managed(struct irq_matrix *m, unsigned int cpu);
void irq_matrix_reserve(struct irq_matrix *m);
void irq_matrix_remove_reserved(struct irq_matrix *m);
int irq_matrix_alloc(struct irq_matrix *m, const struct cpumask *msk,
bool reserved, unsigned int *mapped_cpu);
void irq_matrix_free(struct irq_matrix *m, unsigned int cpu,
unsigned int bit, bool managed);
void irq_matrix_assign(struct irq_matrix *m, unsigned int bit);
unsigned int irq_matrix_available(struct irq_matrix *m, bool cpudown);
unsigned int irq_matrix_allocated(struct irq_matrix *m);
unsigned int irq_matrix_reserved(struct irq_matrix *m);
void irq_matrix_debug_show(struct seq_file *sf, struct irq_matrix *m, int ind);
/* Contrary to Linux irqs, for hardware irqs the irq number 0 is valid */ /* Contrary to Linux irqs, for hardware irqs the irq number 0 is valid */
#define INVALID_HWIRQ (~0UL) #define INVALID_HWIRQ (~0UL)
irq_hw_number_t ipi_get_hwirq(unsigned int irq, unsigned int cpu); irq_hw_number_t ipi_get_hwirq(unsigned int irq, unsigned int cpu);
......
...@@ -93,6 +93,7 @@ struct irq_desc { ...@@ -93,6 +93,7 @@ struct irq_desc {
#endif #endif
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
struct dentry *debugfs_file; struct dentry *debugfs_file;
const char *dev_name;
#endif #endif
#ifdef CONFIG_SPARSE_IRQ #ifdef CONFIG_SPARSE_IRQ
struct rcu_head rcu; struct rcu_head rcu;
......
...@@ -40,6 +40,7 @@ struct of_device_id; ...@@ -40,6 +40,7 @@ struct of_device_id;
struct irq_chip; struct irq_chip;
struct irq_data; struct irq_data;
struct cpumask; struct cpumask;
struct seq_file;
/* Number of irqs reserved for a legacy isa controller */ /* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16 #define NUM_ISA_INTERRUPTS 16
...@@ -104,18 +105,21 @@ struct irq_domain_ops { ...@@ -104,18 +105,21 @@ struct irq_domain_ops {
int (*xlate)(struct irq_domain *d, struct device_node *node, int (*xlate)(struct irq_domain *d, struct device_node *node,
const u32 *intspec, unsigned int intsize, const u32 *intspec, unsigned int intsize,
unsigned long *out_hwirq, unsigned int *out_type); unsigned long *out_hwirq, unsigned int *out_type);
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
/* extended V2 interfaces to support hierarchy irq_domains */ /* extended V2 interfaces to support hierarchy irq_domains */
int (*alloc)(struct irq_domain *d, unsigned int virq, int (*alloc)(struct irq_domain *d, unsigned int virq,
unsigned int nr_irqs, void *arg); unsigned int nr_irqs, void *arg);
void (*free)(struct irq_domain *d, unsigned int virq, void (*free)(struct irq_domain *d, unsigned int virq,
unsigned int nr_irqs); unsigned int nr_irqs);
void (*activate)(struct irq_domain *d, struct irq_data *irq_data); int (*activate)(struct irq_domain *d, struct irq_data *irqd, bool early);
void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data); void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec, int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec,
unsigned long *out_hwirq, unsigned int *out_type); unsigned long *out_hwirq, unsigned int *out_type);
#endif #endif
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
void (*debug_show)(struct seq_file *m, struct irq_domain *d,
struct irq_data *irqd, int ind);
#endif
}; };
extern struct irq_domain_ops irq_generic_chip_ops; extern struct irq_domain_ops irq_generic_chip_ops;
...@@ -437,7 +441,7 @@ extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, ...@@ -437,7 +441,7 @@ extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
unsigned int nr_irqs, int node, void *arg, unsigned int nr_irqs, int node, void *arg,
bool realloc, const struct cpumask *affinity); bool realloc, const struct cpumask *affinity);
extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs); extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
extern void irq_domain_activate_irq(struct irq_data *irq_data); extern int irq_domain_activate_irq(struct irq_data *irq_data, bool early);
extern void irq_domain_deactivate_irq(struct irq_data *irq_data); extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
static inline int irq_domain_alloc_irqs(struct irq_domain *domain, static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
...@@ -507,8 +511,6 @@ static inline bool irq_domain_is_msi_remap(struct irq_domain *domain) ...@@ -507,8 +511,6 @@ static inline bool irq_domain_is_msi_remap(struct irq_domain *domain)
extern bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain); extern bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain);
#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */ #else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
static inline void irq_domain_activate_irq(struct irq_data *data) { }
static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
static inline int irq_domain_alloc_irqs(struct irq_domain *domain, static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
unsigned int nr_irqs, int node, void *arg) unsigned int nr_irqs, int node, void *arg)
{ {
...@@ -557,8 +559,6 @@ irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain) ...@@ -557,8 +559,6 @@ irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain)
#else /* CONFIG_IRQ_DOMAIN */ #else /* CONFIG_IRQ_DOMAIN */
static inline void irq_dispose_mapping(unsigned int virq) { } static inline void irq_dispose_mapping(unsigned int virq) { }
static inline void irq_domain_activate_irq(struct irq_data *data) { }
static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
static inline struct irq_domain *irq_find_matching_fwnode( static inline struct irq_domain *irq_find_matching_fwnode(
struct fwnode_handle *fwnode, enum irq_domain_bus_token bus_token) struct fwnode_handle *fwnode, enum irq_domain_bus_token bus_token)
{ {
......
...@@ -283,6 +283,11 @@ enum { ...@@ -283,6 +283,11 @@ enum {
MSI_FLAG_PCI_MSIX = (1 << 3), MSI_FLAG_PCI_MSIX = (1 << 3),
/* Needs early activate, required for PCI */ /* Needs early activate, required for PCI */
MSI_FLAG_ACTIVATE_EARLY = (1 << 4), MSI_FLAG_ACTIVATE_EARLY = (1 << 4),
/*
* Must reactivate when irq is started even when
* MSI_FLAG_ACTIVATE_EARLY has been set.
*/
MSI_FLAG_MUST_REACTIVATE = (1 << 5),
}; };
int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask, int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
......
#undef TRACE_SYSTEM
#define TRACE_SYSTEM irq_matrix
#if !defined(_TRACE_IRQ_MATRIX_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_IRQ_MATRIX_H
#include <linux/tracepoint.h>
struct irq_matrix;
struct cpumap;
DECLARE_EVENT_CLASS(irq_matrix_global,
TP_PROTO(struct irq_matrix *matrix),
TP_ARGS(matrix),
TP_STRUCT__entry(
__field( unsigned int, online_maps )
__field( unsigned int, global_available )
__field( unsigned int, global_reserved )
__field( unsigned int, total_allocated )
),
TP_fast_assign(
__entry->online_maps = matrix->online_maps;
__entry->global_available = matrix->global_available;
__entry->global_reserved = matrix->global_reserved;
__entry->total_allocated = matrix->total_allocated;
),
TP_printk("online_maps=%d global_avl=%u, global_rsvd=%u, total_alloc=%u",
__entry->online_maps, __entry->global_available,
__entry->global_reserved, __entry->total_allocated)
);
DECLARE_EVENT_CLASS(irq_matrix_global_update,
TP_PROTO(int bit, struct irq_matrix *matrix),
TP_ARGS(bit, matrix),
TP_STRUCT__entry(
__field( int, bit )
__field( unsigned int, online_maps )
__field( unsigned int, global_available )
__field( unsigned int, global_reserved )
__field( unsigned int, total_allocated )
),
TP_fast_assign(
__entry->bit = bit;
__entry->online_maps = matrix->online_maps;
__entry->global_available = matrix->global_available;
__entry->global_reserved = matrix->global_reserved;
__entry->total_allocated = matrix->total_allocated;
),
TP_printk("bit=%d online_maps=%d global_avl=%u, global_rsvd=%u, total_alloc=%u",
__entry->bit, __entry->online_maps,
__entry->global_available, __entry->global_reserved,
__entry->total_allocated)
);
DECLARE_EVENT_CLASS(irq_matrix_cpu,
TP_PROTO(int bit, unsigned int cpu, struct irq_matrix *matrix,
struct cpumap *cmap),
TP_ARGS(bit, cpu, matrix, cmap),
TP_STRUCT__entry(
__field( int, bit )
__field( unsigned int, cpu )
__field( bool, online )
__field( unsigned int, available )
__field( unsigned int, allocated )
__field( unsigned int, managed )
__field( unsigned int, online_maps )
__field( unsigned int, global_available )
__field( unsigned int, global_reserved )
__field( unsigned int, total_allocated )
),
TP_fast_assign(
__entry->bit = bit;
__entry->cpu = cpu;
__entry->online = cmap->online;
__entry->available = cmap->available;
__entry->allocated = cmap->allocated;
__entry->managed = cmap->managed;
__entry->online_maps = matrix->online_maps;
__entry->global_available = matrix->global_available;
__entry->global_reserved = matrix->global_reserved;
__entry->total_allocated = matrix->total_allocated;
),
TP_printk("bit=%d cpu=%u online=%d avl=%u alloc=%u managed=%u online_maps=%u global_avl=%u, global_rsvd=%u, total_alloc=%u",
__entry->bit, __entry->cpu, __entry->online,
__entry->available, __entry->allocated,
__entry->managed, __entry->online_maps,
__entry->global_available, __entry->global_reserved,
__entry->total_allocated)
);
DEFINE_EVENT(irq_matrix_global, irq_matrix_online,
TP_PROTO(struct irq_matrix *matrix),
TP_ARGS(matrix)
);
DEFINE_EVENT(irq_matrix_global, irq_matrix_offline,
TP_PROTO(struct irq_matrix *matrix),
TP_ARGS(matrix)
);
DEFINE_EVENT(irq_matrix_global, irq_matrix_reserve,
TP_PROTO(struct irq_matrix *matrix),
TP_ARGS(matrix)
);
DEFINE_EVENT(irq_matrix_global, irq_matrix_remove_reserved,
TP_PROTO(struct irq_matrix *matrix),
TP_ARGS(matrix)
);
DEFINE_EVENT(irq_matrix_global_update, irq_matrix_assign_system,
TP_PROTO(int bit, struct irq_matrix *matrix),
TP_ARGS(bit, matrix)
);
DEFINE_EVENT(irq_matrix_cpu, irq_matrix_alloc_reserved,
TP_PROTO(int bit, unsigned int cpu,
struct irq_matrix *matrix, struct cpumap *cmap),
TP_ARGS(bit, cpu, matrix, cmap)
);
DEFINE_EVENT(irq_matrix_cpu, irq_matrix_reserve_managed,
TP_PROTO(int bit, unsigned int cpu,
struct irq_matrix *matrix, struct cpumap *cmap),
TP_ARGS(bit, cpu, matrix, cmap)
);
DEFINE_EVENT(irq_matrix_cpu, irq_matrix_remove_managed,
TP_PROTO(int bit, unsigned int cpu,
struct irq_matrix *matrix, struct cpumap *cmap),
TP_ARGS(bit, cpu, matrix, cmap)
);
DEFINE_EVENT(irq_matrix_cpu, irq_matrix_alloc_managed,
TP_PROTO(int bit, unsigned int cpu,
struct irq_matrix *matrix, struct cpumap *cmap),
TP_ARGS(bit, cpu, matrix, cmap)
);
DEFINE_EVENT(irq_matrix_cpu, irq_matrix_assign,
TP_PROTO(int bit, unsigned int cpu,
struct irq_matrix *matrix, struct cpumap *cmap),
TP_ARGS(bit, cpu, matrix, cmap)
);
DEFINE_EVENT(irq_matrix_cpu, irq_matrix_alloc,
TP_PROTO(int bit, unsigned int cpu,
struct irq_matrix *matrix, struct cpumap *cmap),
TP_ARGS(bit, cpu, matrix, cmap)
);
DEFINE_EVENT(irq_matrix_cpu, irq_matrix_free,
TP_PROTO(int bit, unsigned int cpu,
struct irq_matrix *matrix, struct cpumap *cmap),
TP_ARGS(bit, cpu, matrix, cmap)
);
#endif /* _TRACE_IRQ_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
...@@ -97,6 +97,9 @@ config HANDLE_DOMAIN_IRQ ...@@ -97,6 +97,9 @@ config HANDLE_DOMAIN_IRQ
config IRQ_TIMINGS config IRQ_TIMINGS
bool bool
config GENERIC_IRQ_MATRIX_ALLOCATOR
bool
config IRQ_DOMAIN_DEBUG config IRQ_DOMAIN_DEBUG
bool "Expose hardware/virtual IRQ mapping via debugfs" bool "Expose hardware/virtual IRQ mapping via debugfs"
depends on IRQ_DOMAIN && DEBUG_FS depends on IRQ_DOMAIN && DEBUG_FS
......
...@@ -13,3 +13,4 @@ obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o ...@@ -13,3 +13,4 @@ obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o
obj-$(CONFIG_SMP) += affinity.o obj-$(CONFIG_SMP) += affinity.o
obj-$(CONFIG_GENERIC_IRQ_DEBUGFS) += debugfs.o obj-$(CONFIG_GENERIC_IRQ_DEBUGFS) += debugfs.o
obj-$(CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR) += matrix.o
...@@ -53,7 +53,7 @@ unsigned long probe_irq_on(void) ...@@ -53,7 +53,7 @@ unsigned long probe_irq_on(void)
if (desc->irq_data.chip->irq_set_type) if (desc->irq_data.chip->irq_set_type)
desc->irq_data.chip->irq_set_type(&desc->irq_data, desc->irq_data.chip->irq_set_type(&desc->irq_data,
IRQ_TYPE_PROBE); IRQ_TYPE_PROBE);
irq_startup(desc, IRQ_NORESEND, IRQ_START_FORCE); irq_activate_and_startup(desc, IRQ_NORESEND);
} }
raw_spin_unlock_irq(&desc->lock); raw_spin_unlock_irq(&desc->lock);
} }
......
...@@ -207,20 +207,24 @@ __irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force) ...@@ -207,20 +207,24 @@ __irq_startup_managed(struct irq_desc *desc, struct cpumask *aff, bool force)
* Catch code which fiddles with enable_irq() on a managed * Catch code which fiddles with enable_irq() on a managed
* and potentially shutdown IRQ. Chained interrupt * and potentially shutdown IRQ. Chained interrupt
* installment or irq auto probing should not happen on * installment or irq auto probing should not happen on
* managed irqs either. Emit a warning, break the affinity * managed irqs either.
* and start it up as a normal interrupt.
*/ */
if (WARN_ON_ONCE(force)) if (WARN_ON_ONCE(force))
return IRQ_STARTUP_NORMAL; return IRQ_STARTUP_ABORT;
/* /*
* The interrupt was requested, but there is no online CPU * The interrupt was requested, but there is no online CPU
* in it's affinity mask. Put it into managed shutdown * in it's affinity mask. Put it into managed shutdown
* state and let the cpu hotplug mechanism start it up once * state and let the cpu hotplug mechanism start it up once
* a CPU in the mask becomes available. * a CPU in the mask becomes available.
*/ */
irqd_set_managed_shutdown(d);
return IRQ_STARTUP_ABORT; return IRQ_STARTUP_ABORT;
} }
/*
* Managed interrupts have reserved resources, so this should not
* happen.
*/
if (WARN_ON(irq_domain_activate_irq(d, false)))
return IRQ_STARTUP_ABORT;
return IRQ_STARTUP_MANAGED; return IRQ_STARTUP_MANAGED;
} }
#else #else
...@@ -236,7 +240,9 @@ static int __irq_startup(struct irq_desc *desc) ...@@ -236,7 +240,9 @@ static int __irq_startup(struct irq_desc *desc)
struct irq_data *d = irq_desc_get_irq_data(desc); struct irq_data *d = irq_desc_get_irq_data(desc);
int ret = 0; int ret = 0;
irq_domain_activate_irq(d); /* Warn if this interrupt is not activated but try nevertheless */
WARN_ON_ONCE(!irqd_is_activated(d));
if (d->chip->irq_startup) { if (d->chip->irq_startup) {
ret = d->chip->irq_startup(d); ret = d->chip->irq_startup(d);
irq_state_clr_disabled(desc); irq_state_clr_disabled(desc);
...@@ -269,6 +275,7 @@ int irq_startup(struct irq_desc *desc, bool resend, bool force) ...@@ -269,6 +275,7 @@ int irq_startup(struct irq_desc *desc, bool resend, bool force)
irq_set_affinity_locked(d, aff, false); irq_set_affinity_locked(d, aff, false);
break; break;
case IRQ_STARTUP_ABORT: case IRQ_STARTUP_ABORT:
irqd_set_managed_shutdown(d);
return 0; return 0;
} }
} }
...@@ -278,6 +285,22 @@ int irq_startup(struct irq_desc *desc, bool resend, bool force) ...@@ -278,6 +285,22 @@ int irq_startup(struct irq_desc *desc, bool resend, bool force)
return ret; return ret;
} }
int irq_activate(struct irq_desc *desc)
{
struct irq_data *d = irq_desc_get_irq_data(desc);
if (!irqd_affinity_is_managed(d))
return irq_domain_activate_irq(d, false);
return 0;
}
void irq_activate_and_startup(struct irq_desc *desc, bool resend)
{
if (WARN_ON(irq_activate(desc)))
return;
irq_startup(desc, resend, IRQ_START_FORCE);
}
static void __irq_disable(struct irq_desc *desc, bool mask); static void __irq_disable(struct irq_desc *desc, bool mask);
void irq_shutdown(struct irq_desc *desc) void irq_shutdown(struct irq_desc *desc)
...@@ -953,7 +976,7 @@ __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle, ...@@ -953,7 +976,7 @@ __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
irq_settings_set_norequest(desc); irq_settings_set_norequest(desc);
irq_settings_set_nothread(desc); irq_settings_set_nothread(desc);
desc->action = &chained_action; desc->action = &chained_action;
irq_startup(desc, IRQ_RESEND, IRQ_START_FORCE); irq_activate_and_startup(desc, IRQ_RESEND);
} }
} }
......
...@@ -81,6 +81,8 @@ irq_debug_show_data(struct seq_file *m, struct irq_data *data, int ind) ...@@ -81,6 +81,8 @@ irq_debug_show_data(struct seq_file *m, struct irq_data *data, int ind)
data->domain ? data->domain->name : ""); data->domain ? data->domain->name : "");
seq_printf(m, "%*shwirq: 0x%lx\n", ind + 1, "", data->hwirq); seq_printf(m, "%*shwirq: 0x%lx\n", ind + 1, "", data->hwirq);
irq_debug_show_chip(m, data, ind + 1); irq_debug_show_chip(m, data, ind + 1);
if (data->domain && data->domain->ops && data->domain->ops->debug_show)
data->domain->ops->debug_show(m, NULL, data, ind + 1);
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
if (!data->parent_data) if (!data->parent_data)
return; return;
...@@ -149,6 +151,7 @@ static int irq_debug_show(struct seq_file *m, void *p) ...@@ -149,6 +151,7 @@ static int irq_debug_show(struct seq_file *m, void *p)
raw_spin_lock_irq(&desc->lock); raw_spin_lock_irq(&desc->lock);
data = irq_desc_get_irq_data(desc); data = irq_desc_get_irq_data(desc);
seq_printf(m, "handler: %pf\n", desc->handle_irq); seq_printf(m, "handler: %pf\n", desc->handle_irq);
seq_printf(m, "device: %s\n", desc->dev_name);
seq_printf(m, "status: 0x%08x\n", desc->status_use_accessors); seq_printf(m, "status: 0x%08x\n", desc->status_use_accessors);
irq_debug_show_bits(m, 0, desc->status_use_accessors, irqdesc_states, irq_debug_show_bits(m, 0, desc->status_use_accessors, irqdesc_states,
ARRAY_SIZE(irqdesc_states)); ARRAY_SIZE(irqdesc_states));
...@@ -226,6 +229,15 @@ static const struct file_operations dfs_irq_ops = { ...@@ -226,6 +229,15 @@ static const struct file_operations dfs_irq_ops = {
.release = single_release, .release = single_release,
}; };
void irq_debugfs_copy_devname(int irq, struct device *dev)
{
struct irq_desc *desc = irq_to_desc(irq);
const char *name = dev_name(dev);
if (name)
desc->dev_name = kstrdup(name, GFP_KERNEL);
}
void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc) void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc)
{ {
char name [10]; char name [10];
......
...@@ -74,6 +74,8 @@ extern void __enable_irq(struct irq_desc *desc); ...@@ -74,6 +74,8 @@ extern void __enable_irq(struct irq_desc *desc);
#define IRQ_START_FORCE true #define IRQ_START_FORCE true
#define IRQ_START_COND false #define IRQ_START_COND false
extern int irq_activate(struct irq_desc *desc);
extern void irq_activate_and_startup(struct irq_desc *desc, bool resend);
extern int irq_startup(struct irq_desc *desc, bool resend, bool force); extern int irq_startup(struct irq_desc *desc, bool resend, bool force);
extern void irq_shutdown(struct irq_desc *desc); extern void irq_shutdown(struct irq_desc *desc);
...@@ -436,6 +438,18 @@ static inline bool irq_fixup_move_pending(struct irq_desc *desc, bool fclear) ...@@ -436,6 +438,18 @@ static inline bool irq_fixup_move_pending(struct irq_desc *desc, bool fclear)
} }
#endif /* !CONFIG_GENERIC_PENDING_IRQ */ #endif /* !CONFIG_GENERIC_PENDING_IRQ */
#if !defined(CONFIG_IRQ_DOMAIN) || !defined(CONFIG_IRQ_DOMAIN_HIERARCHY)
static inline int irq_domain_activate_irq(struct irq_data *data, bool early)
{
irqd_set_activated(data);
return 0;
}
static inline void irq_domain_deactivate_irq(struct irq_data *data)
{
irqd_clr_activated(data);
}
#endif
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -443,7 +457,9 @@ void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc); ...@@ -443,7 +457,9 @@ void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc);
static inline void irq_remove_debugfs_entry(struct irq_desc *desc) static inline void irq_remove_debugfs_entry(struct irq_desc *desc)
{ {
debugfs_remove(desc->debugfs_file); debugfs_remove(desc->debugfs_file);
kfree(desc->dev_name);
} }
void irq_debugfs_copy_devname(int irq, struct device *dev);
# ifdef CONFIG_IRQ_DOMAIN # ifdef CONFIG_IRQ_DOMAIN
void irq_domain_debugfs_init(struct dentry *root); void irq_domain_debugfs_init(struct dentry *root);
# else # else
...@@ -458,4 +474,7 @@ static inline void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *d) ...@@ -458,4 +474,7 @@ static inline void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *d)
static inline void irq_remove_debugfs_entry(struct irq_desc *d) static inline void irq_remove_debugfs_entry(struct irq_desc *d)
{ {
} }
static inline void irq_debugfs_copy_devname(int irq, struct device *dev)
{
}
#endif /* CONFIG_GENERIC_IRQ_DEBUGFS */ #endif /* CONFIG_GENERIC_IRQ_DEBUGFS */
...@@ -448,7 +448,7 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node, ...@@ -448,7 +448,7 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node,
} }
} }
flags = affinity ? IRQD_AFFINITY_MANAGED : 0; flags = affinity ? IRQD_AFFINITY_MANAGED | IRQD_MANAGED_SHUTDOWN : 0;
mask = NULL; mask = NULL;
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
...@@ -462,6 +462,7 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node, ...@@ -462,6 +462,7 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node,
goto err; goto err;
irq_insert_desc(start + i, desc); irq_insert_desc(start + i, desc);
irq_sysfs_add(start + i, desc); irq_sysfs_add(start + i, desc);
irq_add_debugfs_entry(start + i, desc);
} }
bitmap_set(allocated_irqs, start, cnt); bitmap_set(allocated_irqs, start, cnt);
return start; return start;
......
...@@ -1682,28 +1682,36 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain, ...@@ -1682,28 +1682,36 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain,
} }
EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent); EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
static void __irq_domain_activate_irq(struct irq_data *irq_data) static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
{ {
if (irq_data && irq_data->domain) { if (irq_data && irq_data->domain) {
struct irq_domain *domain = irq_data->domain; struct irq_domain *domain = irq_data->domain;
if (domain->ops->deactivate)
domain->ops->deactivate(domain, irq_data);
if (irq_data->parent_data) if (irq_data->parent_data)
__irq_domain_activate_irq(irq_data->parent_data); __irq_domain_deactivate_irq(irq_data->parent_data);
if (domain->ops->activate)
domain->ops->activate(domain, irq_data);
} }
} }
static void __irq_domain_deactivate_irq(struct irq_data *irq_data) static int __irq_domain_activate_irq(struct irq_data *irqd, bool early)
{ {
if (irq_data && irq_data->domain) { int ret = 0;
struct irq_domain *domain = irq_data->domain;
if (domain->ops->deactivate) if (irqd && irqd->domain) {
domain->ops->deactivate(domain, irq_data); struct irq_domain *domain = irqd->domain;
if (irq_data->parent_data)
__irq_domain_deactivate_irq(irq_data->parent_data); if (irqd->parent_data)
ret = __irq_domain_activate_irq(irqd->parent_data,
early);
if (!ret && domain->ops->activate) {
ret = domain->ops->activate(domain, irqd, early);
/* Rollback in case of error */
if (ret && irqd->parent_data)
__irq_domain_deactivate_irq(irqd->parent_data);
}
} }
return ret;
} }
/** /**
...@@ -1714,12 +1722,15 @@ static void __irq_domain_deactivate_irq(struct irq_data *irq_data) ...@@ -1714,12 +1722,15 @@ static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
* This is the second step to call domain_ops->activate to program interrupt * This is the second step to call domain_ops->activate to program interrupt
* controllers, so the interrupt could actually get delivered. * controllers, so the interrupt could actually get delivered.
*/ */
void irq_domain_activate_irq(struct irq_data *irq_data) int irq_domain_activate_irq(struct irq_data *irq_data, bool early)
{ {
if (!irqd_is_activated(irq_data)) { int ret = 0;
__irq_domain_activate_irq(irq_data);
if (!irqd_is_activated(irq_data))
ret = __irq_domain_activate_irq(irq_data, early);
if (!ret)
irqd_set_activated(irq_data); irqd_set_activated(irq_data);
} return ret;
} }
/** /**
...@@ -1810,6 +1821,8 @@ irq_domain_debug_show_one(struct seq_file *m, struct irq_domain *d, int ind) ...@@ -1810,6 +1821,8 @@ irq_domain_debug_show_one(struct seq_file *m, struct irq_domain *d, int ind)
d->revmap_size + d->revmap_direct_max_irq); d->revmap_size + d->revmap_direct_max_irq);
seq_printf(m, "%*smapped: %u\n", ind + 1, "", d->mapcount); seq_printf(m, "%*smapped: %u\n", ind + 1, "", d->mapcount);
seq_printf(m, "%*sflags: 0x%08x\n", ind +1 , "", d->flags); seq_printf(m, "%*sflags: 0x%08x\n", ind +1 , "", d->flags);
if (d->ops && d->ops->debug_show)
d->ops->debug_show(m, d, NULL, ind + 1);
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
if (!d->parent) if (!d->parent)
return; return;
......
...@@ -519,7 +519,7 @@ void __enable_irq(struct irq_desc *desc) ...@@ -519,7 +519,7 @@ void __enable_irq(struct irq_desc *desc)
* time. If it was already started up, then irq_startup() * time. If it was already started up, then irq_startup()
* will invoke irq_enable() under the hood. * will invoke irq_enable() under the hood.
*/ */
irq_startup(desc, IRQ_RESEND, IRQ_START_COND); irq_startup(desc, IRQ_RESEND, IRQ_START_FORCE);
break; break;
} }
default: default:
...@@ -1325,6 +1325,21 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) ...@@ -1325,6 +1325,21 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
goto out_unlock; goto out_unlock;
} }
/*
* Activate the interrupt. That activation must happen
* independently of IRQ_NOAUTOEN. request_irq() can fail
* and the callers are supposed to handle
* that. enable_irq() of an interrupt requested with
* IRQ_NOAUTOEN is not supposed to fail. The activation
* keeps it in shutdown mode, it merily associates
* resources if necessary and if that's not possible it
* fails. Interrupts which are in managed shutdown mode
* will simply ignore that activation request.
*/
ret = irq_activate(desc);
if (ret)
goto out_unlock;
desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \ desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
IRQS_ONESHOT | IRQS_WAITING); IRQS_ONESHOT | IRQS_WAITING);
irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
...@@ -1400,7 +1415,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) ...@@ -1400,7 +1415,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
wake_up_process(new->secondary->thread); wake_up_process(new->secondary->thread);
register_irq_proc(irq, desc); register_irq_proc(irq, desc);
irq_add_debugfs_entry(irq, desc);
new->dir = NULL; new->dir = NULL;
register_handler_proc(irq, new); register_handler_proc(irq, new);
return 0; return 0;
...@@ -1643,6 +1657,10 @@ const void *free_irq(unsigned int irq, void *dev_id) ...@@ -1643,6 +1657,10 @@ const void *free_irq(unsigned int irq, void *dev_id)
#endif #endif
action = __free_irq(irq, dev_id); action = __free_irq(irq, dev_id);
if (!action)
return NULL;
devname = action->name; devname = action->name;
kfree(action); kfree(action);
return devname; return devname;
......
This diff is collapsed.
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <linux/msi.h> #include <linux/msi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "internals.h"
/** /**
* alloc_msi_entry - Allocate an initialize msi_entry * alloc_msi_entry - Allocate an initialize msi_entry
* @dev: Pointer to the device for which this is allocated * @dev: Pointer to the device for which this is allocated
...@@ -100,13 +102,14 @@ int msi_domain_set_affinity(struct irq_data *irq_data, ...@@ -100,13 +102,14 @@ int msi_domain_set_affinity(struct irq_data *irq_data,
return ret; return ret;
} }
static void msi_domain_activate(struct irq_domain *domain, static int msi_domain_activate(struct irq_domain *domain,
struct irq_data *irq_data) struct irq_data *irq_data, bool early)
{ {
struct msi_msg msg; struct msi_msg msg;
BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg)); BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
irq_chip_write_msi_msg(irq_data, &msg); irq_chip_write_msi_msg(irq_data, &msg);
return 0;
} }
static void msi_domain_deactivate(struct irq_domain *domain, static void msi_domain_deactivate(struct irq_domain *domain,
...@@ -373,8 +376,10 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, ...@@ -373,8 +376,10 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
return ret; return ret;
} }
for (i = 0; i < desc->nvec_used; i++) for (i = 0; i < desc->nvec_used; i++) {
irq_set_msi_desc_off(virq, i, desc); irq_set_msi_desc_off(virq, i, desc);
irq_debugfs_copy_devname(virq + i, dev);
}
} }
if (ops->msi_finish) if (ops->msi_finish)
...@@ -396,11 +401,28 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, ...@@ -396,11 +401,28 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
struct irq_data *irq_data; struct irq_data *irq_data;
irq_data = irq_domain_get_irq_data(domain, desc->irq); irq_data = irq_domain_get_irq_data(domain, desc->irq);
irq_domain_activate_irq(irq_data); ret = irq_domain_activate_irq(irq_data, true);
if (ret)
goto cleanup;
if (info->flags & MSI_FLAG_MUST_REACTIVATE)
irqd_clr_activated(irq_data);
} }
} }
return 0; return 0;
cleanup:
for_each_msi_entry(desc, dev) {
struct irq_data *irqd;
if (desc->irq == virq)
break;
irqd = irq_domain_get_irq_data(domain, desc->irq);
if (irqd_is_activated(irqd))
irq_domain_deactivate_irq(irqd);
}
msi_domain_free_irqs(domain, dev);
return ret;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment