mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
cpu_possible_mask is set early during boot based on information from the firmware. After that it remains read only and is never changed. Therefore there is no need to acquire the CPU-hotplug lock while reading it. Remove cpus_read_*() while accessing cpu_possible_mask. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Link: https://patch.msgid.link/20260401121334.xeMOSC1v@linutronix.de
125 lines
3.3 KiB
C
125 lines
3.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2016 Thomas Gleixner.
|
|
* Copyright (C) 2016-2017 Christoph Hellwig.
|
|
*/
|
|
#include <linux/interrupt.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/group_cpus.h>
|
|
|
|
static void default_calc_sets(struct irq_affinity *affd, unsigned int affvecs)
|
|
{
|
|
affd->nr_sets = 1;
|
|
affd->set_size[0] = affvecs;
|
|
}
|
|
|
|
/**
|
|
* irq_create_affinity_masks - Create affinity masks for multiqueue spreading
|
|
* @nvecs: The total number of vectors
|
|
* @affd: Description of the affinity requirements
|
|
*
|
|
* Returns the irq_affinity_desc pointer or NULL if allocation failed.
|
|
*/
|
|
struct irq_affinity_desc *
|
|
irq_create_affinity_masks(unsigned int nvecs, struct irq_affinity *affd)
|
|
{
|
|
unsigned int affvecs, curvec, usedvecs, i;
|
|
struct irq_affinity_desc *masks = NULL;
|
|
|
|
/*
|
|
* Determine the number of vectors which need interrupt affinities
|
|
* assigned. If the pre/post request exhausts the available vectors
|
|
* then nothing to do here except for invoking the calc_sets()
|
|
* callback so the device driver can adjust to the situation.
|
|
*/
|
|
if (nvecs > affd->pre_vectors + affd->post_vectors)
|
|
affvecs = nvecs - affd->pre_vectors - affd->post_vectors;
|
|
else
|
|
affvecs = 0;
|
|
|
|
/*
|
|
* Simple invocations do not provide a calc_sets() callback. Install
|
|
* the generic one.
|
|
*/
|
|
if (!affd->calc_sets)
|
|
affd->calc_sets = default_calc_sets;
|
|
|
|
/* Recalculate the sets */
|
|
affd->calc_sets(affd, affvecs);
|
|
|
|
if (WARN_ON_ONCE(affd->nr_sets > IRQ_AFFINITY_MAX_SETS))
|
|
return NULL;
|
|
|
|
/* Nothing to assign? */
|
|
if (!affvecs)
|
|
return NULL;
|
|
|
|
masks = kzalloc_objs(*masks, nvecs);
|
|
if (!masks)
|
|
return NULL;
|
|
|
|
/* Fill out vectors at the beginning that don't need affinity */
|
|
for (curvec = 0; curvec < affd->pre_vectors; curvec++)
|
|
cpumask_copy(&masks[curvec].mask, irq_default_affinity);
|
|
|
|
/*
|
|
* Spread on present CPUs starting from affd->pre_vectors. If we
|
|
* have multiple sets, build each sets affinity mask separately.
|
|
*/
|
|
for (i = 0, usedvecs = 0; i < affd->nr_sets; i++) {
|
|
unsigned int nr_masks, this_vecs = affd->set_size[i];
|
|
struct cpumask *result = group_cpus_evenly(this_vecs, &nr_masks);
|
|
|
|
if (!result) {
|
|
kfree(masks);
|
|
return NULL;
|
|
}
|
|
|
|
for (int j = 0; j < nr_masks; j++)
|
|
cpumask_copy(&masks[curvec + j].mask, &result[j]);
|
|
kfree(result);
|
|
|
|
curvec += nr_masks;
|
|
usedvecs += nr_masks;
|
|
}
|
|
|
|
/* Fill out vectors at the end that don't need affinity */
|
|
if (usedvecs >= affvecs)
|
|
curvec = affd->pre_vectors + affvecs;
|
|
else
|
|
curvec = affd->pre_vectors + usedvecs;
|
|
for (; curvec < nvecs; curvec++)
|
|
cpumask_copy(&masks[curvec].mask, irq_default_affinity);
|
|
|
|
/* Mark the managed interrupts */
|
|
for (i = affd->pre_vectors; i < nvecs - affd->post_vectors; i++)
|
|
masks[i].is_managed = 1;
|
|
|
|
return masks;
|
|
}
|
|
|
|
/**
|
|
* irq_calc_affinity_vectors - Calculate the optimal number of vectors
|
|
* @minvec: The minimum number of vectors available
|
|
* @maxvec: The maximum number of vectors available
|
|
* @affd: Description of the affinity requirements
|
|
*/
|
|
unsigned int irq_calc_affinity_vectors(unsigned int minvec, unsigned int maxvec,
|
|
const struct irq_affinity *affd)
|
|
{
|
|
unsigned int resv = affd->pre_vectors + affd->post_vectors;
|
|
unsigned int set_vecs;
|
|
|
|
if (resv > minvec)
|
|
return 0;
|
|
|
|
if (affd->calc_sets)
|
|
set_vecs = maxvec - resv;
|
|
else
|
|
set_vecs = cpumask_weight(cpu_possible_mask);
|
|
|
|
return resv + min(set_vecs, maxvec - resv);
|
|
}
|