Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq updates from Thomas Gleixner:
 "The interrupt departement delivers this time:

   - New infrastructure to manage NMIs on platforms which have a sane
     NMI delivery, i.e. identifiable NMI vectors instead of a single
     lump.

   - Simplification of the interrupt affinity management so drivers
     don't have to implement ugly loops around the PCI/MSI enablement.

   - Speedup for interrupt statistics in /proc/stat

   - Provide a function to retrieve the default irq domain

   - A new interrupt controller for the Loongson LS1X platform

   - Affinity support for the SiFive PLIC

   - Better support for the iMX irqsteer driver

   - NUMA aware memory allocations for GICv3

   - The usual small fixes, improvements and cleanups all over the
     place"

* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (36 commits)
  irqchip/imx-irqsteer: Add multi output interrupts support
  irqchip/imx-irqsteer: Change to use reg_num instead of irq_group
  dt-bindings: irq: imx-irqsteer: Add multi output interrupts support
  dt-binding: irq: imx-irqsteer: Use irq number instead of group number
  irqchip/brcmstb-l2: Use _irqsave locking variants in non-interrupt code
  irqchip/gicv3-its: Use NUMA aware memory allocation for ITS tables
  irqdomain: Allow the default irq domain to be retrieved
  irqchip/sifive-plic: Implement irq_set_affinity() for SMP host
  irqchip/sifive-plic: Differentiate between PLIC handler and context
  irqchip/sifive-plic: Add warning in plic_init() if handler already present
  irqchip/sifive-plic: Pre-compute context hart base and enable base
  PCI/MSI: Remove obsolete sanity checks for multiple interrupt sets
  genirq/affinity: Remove the leftovers of the original set support
  nvme-pci: Simplify interrupt allocation
  genirq/affinity: Add new callback for (re)calculating interrupt sets
  genirq/affinity: Store interrupt sets size in struct irq_affinity
  genirq/affinity: Code consolidation
  irqchip/irq-sifive-plic: Check and continue in case of an invalid cpuid.
  irqchip/i8259: Fix shutdown order by moving syscore_ops registration
  dt-bindings: interrupt-controller: loongson ls1x intc
  ...
This commit is contained in:
Linus Torvalds
2019-03-05 12:21:47 -08:00
30 changed files with 1177 additions and 281 deletions

View File

@@ -2041,53 +2041,52 @@ static int nvme_setup_host_mem(struct nvme_dev *dev)
return ret;
}
/* irq_queues covers admin queue */
static void nvme_calc_io_queues(struct nvme_dev *dev, unsigned int irq_queues)
/*
* nirqs is the number of interrupts available for write and read
* queues. The core already reserved an interrupt for the admin queue.
*/
static void nvme_calc_irq_sets(struct irq_affinity *affd, unsigned int nrirqs)
{
unsigned int this_w_queues = write_queues;
WARN_ON(!irq_queues);
struct nvme_dev *dev = affd->priv;
unsigned int nr_read_queues;
/*
* Setup read/write queue split, assign admin queue one independent
* irq vector if irq_queues is > 1.
* If there is no interupt available for queues, ensure that
* the default queue is set to 1. The affinity set size is
* also set to one, but the irq core ignores it for this case.
*
* If only one interrupt is available or 'write_queue' == 0, combine
* write and read queues.
*
* If 'write_queues' > 0, ensure it leaves room for at least one read
* queue.
*/
if (irq_queues <= 2) {
dev->io_queues[HCTX_TYPE_DEFAULT] = 1;
dev->io_queues[HCTX_TYPE_READ] = 0;
return;
}
/*
* If 'write_queues' is set, ensure it leaves room for at least
* one read queue and one admin queue
*/
if (this_w_queues >= irq_queues)
this_w_queues = irq_queues - 2;
/*
* If 'write_queues' is set to zero, reads and writes will share
* a queue set.
*/
if (!this_w_queues) {
dev->io_queues[HCTX_TYPE_DEFAULT] = irq_queues - 1;
dev->io_queues[HCTX_TYPE_READ] = 0;
if (!nrirqs) {
nrirqs = 1;
nr_read_queues = 0;
} else if (nrirqs == 1 || !write_queues) {
nr_read_queues = 0;
} else if (write_queues >= nrirqs) {
nr_read_queues = 1;
} else {
dev->io_queues[HCTX_TYPE_DEFAULT] = this_w_queues;
dev->io_queues[HCTX_TYPE_READ] = irq_queues - this_w_queues - 1;
nr_read_queues = nrirqs - write_queues;
}
dev->io_queues[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues;
affd->set_size[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues;
dev->io_queues[HCTX_TYPE_READ] = nr_read_queues;
affd->set_size[HCTX_TYPE_READ] = nr_read_queues;
affd->nr_sets = nr_read_queues ? 2 : 1;
}
static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues)
{
struct pci_dev *pdev = to_pci_dev(dev->dev);
int irq_sets[2];
struct irq_affinity affd = {
.pre_vectors = 1,
.nr_sets = ARRAY_SIZE(irq_sets),
.sets = irq_sets,
.pre_vectors = 1,
.calc_sets = nvme_calc_irq_sets,
.priv = dev,
};
int result = 0;
unsigned int irq_queues, this_p_queues;
/*
@@ -2103,51 +2102,12 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues)
}
dev->io_queues[HCTX_TYPE_POLL] = this_p_queues;
/*
* For irq sets, we have to ask for minvec == maxvec. This passes
* any reduction back to us, so we can adjust our queue counts and
* IRQ vector needs.
*/
do {
nvme_calc_io_queues(dev, irq_queues);
irq_sets[0] = dev->io_queues[HCTX_TYPE_DEFAULT];
irq_sets[1] = dev->io_queues[HCTX_TYPE_READ];
if (!irq_sets[1])
affd.nr_sets = 1;
/* Initialize for the single interrupt case */
dev->io_queues[HCTX_TYPE_DEFAULT] = 1;
dev->io_queues[HCTX_TYPE_READ] = 0;
/*
* If we got a failure and we're down to asking for just
* 1 + 1 queues, just ask for a single vector. We'll share
* that between the single IO queue and the admin queue.
* Otherwise, we assign one independent vector to admin queue.
*/
if (irq_queues > 1)
irq_queues = irq_sets[0] + irq_sets[1] + 1;
result = pci_alloc_irq_vectors_affinity(pdev, irq_queues,
irq_queues,
PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd);
/*
* Need to reduce our vec counts. If we get ENOSPC, the
* platform should support mulitple vecs, we just need
* to decrease our ask. If we get EINVAL, the platform
* likely does not. Back down to ask for just one vector.
*/
if (result == -ENOSPC) {
irq_queues--;
if (!irq_queues)
return result;
continue;
} else if (result == -EINVAL) {
irq_queues = 1;
continue;
} else if (result <= 0)
return -EIO;
break;
} while (1);
return result;
return pci_alloc_irq_vectors_affinity(pdev, 1, irq_queues,
PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd);
}
static void nvme_disable_io_queues(struct nvme_dev *dev)
@@ -3024,6 +2984,7 @@ static struct pci_driver nvme_driver = {
static int __init nvme_init(void)
{
BUILD_BUG_ON(IRQ_AFFINITY_MAX_SETS < 2);
return pci_register_driver(&nvme_driver);
}