Updates for the interrupt subsytem:
Core: - Exclude managed interrupts in the calculation of interrupts which are targeted to a CPU which is about to be offlined to ensure that there are enough free vectors on the still online CPUs to migrate them over. Managed interrupts do not need to be accounted because they are either shut down on offline or migrated to an already reserved and guaranteed slot on a still online CPU in the interrupts affinity mask. Including managed interrupts is overaccounting and can result in needlessly aborting hibernation on large server machines. - The usual set of small improvements Drivers: - Make the generic interrupt chip implementation handle interrupt domains correctly and initialize the name pointers correctly - Add interrupt affinity setting support to the Renesas RZG2L chip driver. - Prevent registering syscore operations multiple times in the SiFive PLIC chip driver. - Update device tree handling in the NXP Layerscape MSI chip driver -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmU+uawTHHRnbHhAbGlu dXRyb25peC5kZQAKCRCmGPVMDXSYoZJGD/9ZdvT7OWZVLbqPX7eNPxGXUbLImD8H lBgPEKi4oQGzNK+CANpicQa2YclZmprN8a9v6jjW/1HEY97WSUS8mNZymrwYjMsX hTWiFpF3CIknPQAVPgZG7Zu7iVLLeY/MYN7/H+outCAuncwkw/RVYFDJG4oe6jy3 mNsV5f22xAsL4yR1eRzkbvJwwq4iqdrk8JPE9YoYN3Oo1/OUU1LIW/mUK7CaClfZ +6mEuSYUCyhrYjYN68OZRyVQ+8ZuemOOwIQPTNXbx5tYOY+dsFOwNbOweXH8s4Gx 4IJ9u2QtvOXZRNvfWqz0zwhjPhaYNBHHWW2cDLM57v/Os3Fe0aYals6ElF/1SGGE KIITCP6Qi9IJlOtO44Zlz+7to5n+zgn6aQTxSkPxM1pC9J0AgDBSrL8GWbrpTjR+ bMbXDkOMkZLYVJEGrD07UiAsl1xwHjN+uQAKqq6SUXQcVIdQQCDAm37km8cf+URx hH7oWQCDRKCkrcjLvGAjRs9TxiD/UfAwZ8eWTg1L2gIMx5ugctr2RWLl87t/y25c DDFXn9Y9SmMBOeA4J99neCZfXeHo8iiVGYD8Wv3AVFAETAZE81XmiiGaVRoyty2N rbRgdmYZKUJu/XVvcHL+wxvQ9W7Y4p3qQI3fcgFXGx6cIco6cqcS4QrlE8di3SWf KLLhOCNUGRtcSQ== =Ok6p -----END PGP SIGNATURE----- Merge tag 'irq-core-2023-10-29-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull irq updates from Thomas Gleixner: "Core: - Exclude managed interrupts in the calculation of interrupts which are targeted to a CPU which is about to be offlined to ensure that there are enough free vectors on the still online CPUs to migrate them over. Managed interrupts do not need to be accounted because they are either shut down on offline or migrated to an already reserved and guaranteed slot on a still online CPU in the interrupts affinity mask. Including managed interrupts is overaccounting and can result in needlessly aborting hibernation on large server machines. - The usual set of small improvements Drivers: - Make the generic interrupt chip implementation handle interrupt domains correctly and initialize the name pointers correctly - Add interrupt affinity setting support to the Renesas RZG2L chip driver. - Prevent registering syscore operations multiple times in the SiFive PLIC chip driver. - Update device tree handling in the NXP Layerscape MSI chip driver" * tag 'irq-core-2023-10-29-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: irqchip/sifive-plic: Fix syscore registration for multi-socket systems irqchip/ls-scfg-msi: Use device_get_match_data() genirq/generic_chip: Make irq_remove_generic_chip() irqdomain aware genirq/matrix: Exclude managed interrupts in irq_matrix_allocated() PCI/MSI: Provide stubs for IMS functions irqchip/renesas-rzg2l: Enhance driver to support interrupt affinity setting genirq/generic-chip: Fix the irq_chip name for /proc/interrupts irqdomain: Annotate struct irq_domain with __counted_by
This commit is contained in:
commit
b08eccef9f
@ -17,7 +17,8 @@
|
|||||||
#include <linux/irqdomain.h>
|
#include <linux/irqdomain.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/of_pci.h>
|
#include <linux/of_pci.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/property.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
#define MSI_IRQS_PER_MSIR 32
|
#define MSI_IRQS_PER_MSIR 32
|
||||||
@ -334,20 +335,17 @@ MODULE_DEVICE_TABLE(of, ls_scfg_msi_id);
|
|||||||
|
|
||||||
static int ls_scfg_msi_probe(struct platform_device *pdev)
|
static int ls_scfg_msi_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const struct of_device_id *match;
|
|
||||||
struct ls_scfg_msi *msi_data;
|
struct ls_scfg_msi *msi_data;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
match = of_match_device(ls_scfg_msi_id, &pdev->dev);
|
|
||||||
if (!match)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL);
|
msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL);
|
||||||
if (!msi_data)
|
if (!msi_data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
msi_data->cfg = (struct ls_scfg_msi_cfg *) match->data;
|
msi_data->cfg = (struct ls_scfg_msi_cfg *)device_get_match_data(&pdev->dev);
|
||||||
|
if (!msi_data->cfg)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
msi_data->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
msi_data->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||||
if (IS_ERR(msi_data->regs)) {
|
if (IS_ERR(msi_data->regs)) {
|
||||||
|
@ -247,6 +247,7 @@ static const struct irq_chip irqc_chip = {
|
|||||||
.irq_set_irqchip_state = irq_chip_set_parent_state,
|
.irq_set_irqchip_state = irq_chip_set_parent_state,
|
||||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||||
.irq_set_type = rzg2l_irqc_set_type,
|
.irq_set_type = rzg2l_irqc_set_type,
|
||||||
|
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||||
.flags = IRQCHIP_MASK_ON_SUSPEND |
|
.flags = IRQCHIP_MASK_ON_SUSPEND |
|
||||||
IRQCHIP_SET_TYPE_MASKED |
|
IRQCHIP_SET_TYPE_MASKED |
|
||||||
IRQCHIP_SKIP_SET_WAKE,
|
IRQCHIP_SKIP_SET_WAKE,
|
||||||
|
@ -532,17 +532,18 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can have multiple PLIC instances so setup cpuhp state only
|
* We can have multiple PLIC instances so setup cpuhp state
|
||||||
* when context handler for current/boot CPU is present.
|
* and register syscore operations only when context handler
|
||||||
|
* for current/boot CPU is present.
|
||||||
*/
|
*/
|
||||||
handler = this_cpu_ptr(&plic_handlers);
|
handler = this_cpu_ptr(&plic_handlers);
|
||||||
if (handler->present && !plic_cpuhp_setup_done) {
|
if (handler->present && !plic_cpuhp_setup_done) {
|
||||||
cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
|
cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
|
||||||
"irqchip/sifive/plic:starting",
|
"irqchip/sifive/plic:starting",
|
||||||
plic_starting_cpu, plic_dying_cpu);
|
plic_starting_cpu, plic_dying_cpu);
|
||||||
|
register_syscore_ops(&plic_irq_syscore_ops);
|
||||||
plic_cpuhp_setup_done = true;
|
plic_cpuhp_setup_done = true;
|
||||||
}
|
}
|
||||||
register_syscore_ops(&plic_irq_syscore_ops);
|
|
||||||
|
|
||||||
pr_info("%pOFP: mapped %d interrupts with %d handlers for"
|
pr_info("%pOFP: mapped %d interrupts with %d handlers for"
|
||||||
" %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts);
|
" %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts);
|
||||||
|
@ -174,7 +174,7 @@ struct irq_domain {
|
|||||||
irq_hw_number_t hwirq_max;
|
irq_hw_number_t hwirq_max;
|
||||||
unsigned int revmap_size;
|
unsigned int revmap_size;
|
||||||
struct radix_tree_root revmap_tree;
|
struct radix_tree_root revmap_tree;
|
||||||
struct irq_data __rcu *revmap[];
|
struct irq_data __rcu *revmap[] __counted_by(revmap_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Irq domain flags */
|
/* Irq domain flags */
|
||||||
|
@ -1624,6 +1624,8 @@ struct msix_entry {
|
|||||||
u16 entry; /* Driver uses to specify entry, OS writes */
|
u16 entry; /* Driver uses to specify entry, OS writes */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct msi_domain_template;
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_MSI
|
#ifdef CONFIG_PCI_MSI
|
||||||
int pci_msi_vec_count(struct pci_dev *dev);
|
int pci_msi_vec_count(struct pci_dev *dev);
|
||||||
void pci_disable_msi(struct pci_dev *dev);
|
void pci_disable_msi(struct pci_dev *dev);
|
||||||
@ -1656,6 +1658,11 @@ void pci_msix_free_irq(struct pci_dev *pdev, struct msi_map map);
|
|||||||
void pci_free_irq_vectors(struct pci_dev *dev);
|
void pci_free_irq_vectors(struct pci_dev *dev);
|
||||||
int pci_irq_vector(struct pci_dev *dev, unsigned int nr);
|
int pci_irq_vector(struct pci_dev *dev, unsigned int nr);
|
||||||
const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, int vec);
|
const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, int vec);
|
||||||
|
bool pci_create_ims_domain(struct pci_dev *pdev, const struct msi_domain_template *template,
|
||||||
|
unsigned int hwsize, void *data);
|
||||||
|
struct msi_map pci_ims_alloc_irq(struct pci_dev *pdev, union msi_instance_cookie *icookie,
|
||||||
|
const struct irq_affinity_desc *affdesc);
|
||||||
|
void pci_ims_free_irq(struct pci_dev *pdev, struct msi_map map);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
|
static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
|
||||||
@ -1719,6 +1726,25 @@ static inline const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev,
|
|||||||
{
|
{
|
||||||
return cpu_possible_mask;
|
return cpu_possible_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool pci_create_ims_domain(struct pci_dev *pdev,
|
||||||
|
const struct msi_domain_template *template,
|
||||||
|
unsigned int hwsize, void *data)
|
||||||
|
{ return false; }
|
||||||
|
|
||||||
|
static inline struct msi_map pci_ims_alloc_irq(struct pci_dev *pdev,
|
||||||
|
union msi_instance_cookie *icookie,
|
||||||
|
const struct irq_affinity_desc *affdesc)
|
||||||
|
{
|
||||||
|
struct msi_map map = { .index = -ENOSYS, };
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pci_ims_free_irq(struct pci_dev *pdev, struct msi_map map)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2616,14 +2642,6 @@ static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev)
|
|||||||
void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);
|
void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct msi_domain_template;
|
|
||||||
|
|
||||||
bool pci_create_ims_domain(struct pci_dev *pdev, const struct msi_domain_template *template,
|
|
||||||
unsigned int hwsize, void *data);
|
|
||||||
struct msi_map pci_ims_alloc_irq(struct pci_dev *pdev, union msi_instance_cookie *icookie,
|
|
||||||
const struct irq_affinity_desc *affdesc);
|
|
||||||
void pci_ims_free_irq(struct pci_dev *pdev, struct msi_map map);
|
|
||||||
|
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
|
|
||||||
#define pci_printk(level, pdev, fmt, arg...) \
|
#define pci_printk(level, pdev, fmt, arg...) \
|
||||||
|
@ -219,11 +219,15 @@ void irq_init_generic_chip(struct irq_chip_generic *gc, const char *name,
|
|||||||
int num_ct, unsigned int irq_base,
|
int num_ct, unsigned int irq_base,
|
||||||
void __iomem *reg_base, irq_flow_handler_t handler)
|
void __iomem *reg_base, irq_flow_handler_t handler)
|
||||||
{
|
{
|
||||||
|
struct irq_chip_type *ct = gc->chip_types;
|
||||||
|
int i;
|
||||||
|
|
||||||
raw_spin_lock_init(&gc->lock);
|
raw_spin_lock_init(&gc->lock);
|
||||||
gc->num_ct = num_ct;
|
gc->num_ct = num_ct;
|
||||||
gc->irq_base = irq_base;
|
gc->irq_base = irq_base;
|
||||||
gc->reg_base = reg_base;
|
gc->reg_base = reg_base;
|
||||||
gc->chip_types->chip.name = name;
|
for (i = 0; i < num_ct; i++)
|
||||||
|
ct[i].chip.name = name;
|
||||||
gc->chip_types->handler = handler;
|
gc->chip_types->handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,21 +548,34 @@ EXPORT_SYMBOL_GPL(irq_setup_alt_chip);
|
|||||||
void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
|
void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
|
||||||
unsigned int clr, unsigned int set)
|
unsigned int clr, unsigned int set)
|
||||||
{
|
{
|
||||||
unsigned int i = gc->irq_base;
|
unsigned int i, virq;
|
||||||
|
|
||||||
raw_spin_lock(&gc_lock);
|
raw_spin_lock(&gc_lock);
|
||||||
list_del(&gc->list);
|
list_del(&gc->list);
|
||||||
raw_spin_unlock(&gc_lock);
|
raw_spin_unlock(&gc_lock);
|
||||||
|
|
||||||
for (; msk; msk >>= 1, i++) {
|
for (i = 0; msk; msk >>= 1, i++) {
|
||||||
if (!(msk & 0x01))
|
if (!(msk & 0x01))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt domain based chips store the base hardware
|
||||||
|
* interrupt number in gc::irq_base. Otherwise gc::irq_base
|
||||||
|
* contains the base Linux interrupt number.
|
||||||
|
*/
|
||||||
|
if (gc->domain) {
|
||||||
|
virq = irq_find_mapping(gc->domain, gc->irq_base + i);
|
||||||
|
if (!virq)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
virq = gc->irq_base + i;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remove handler first. That will mask the irq line */
|
/* Remove handler first. That will mask the irq line */
|
||||||
irq_set_handler(i, NULL);
|
irq_set_handler(virq, NULL);
|
||||||
irq_set_chip(i, &no_irq_chip);
|
irq_set_chip(virq, &no_irq_chip);
|
||||||
irq_set_chip_data(i, NULL);
|
irq_set_chip_data(virq, NULL);
|
||||||
irq_modify_status(i, clr, set);
|
irq_modify_status(virq, clr, set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(irq_remove_generic_chip);
|
EXPORT_SYMBOL_GPL(irq_remove_generic_chip);
|
||||||
|
@ -466,16 +466,16 @@ unsigned int irq_matrix_reserved(struct irq_matrix *m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* irq_matrix_allocated - Get the number of allocated irqs on the local cpu
|
* irq_matrix_allocated - Get the number of allocated non-managed irqs on the local CPU
|
||||||
* @m: Pointer to the matrix to search
|
* @m: Pointer to the matrix to search
|
||||||
*
|
*
|
||||||
* This returns number of allocated irqs
|
* This returns number of allocated non-managed interrupts.
|
||||||
*/
|
*/
|
||||||
unsigned int irq_matrix_allocated(struct irq_matrix *m)
|
unsigned int irq_matrix_allocated(struct irq_matrix *m)
|
||||||
{
|
{
|
||||||
struct cpumap *cm = this_cpu_ptr(m->maps);
|
struct cpumap *cm = this_cpu_ptr(m->maps);
|
||||||
|
|
||||||
return cm->allocated;
|
return cm->allocated - cm->managed_allocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
|
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
|
||||||
|
Loading…
Reference in New Issue
Block a user