diff options
| -rw-r--r-- | kernel/irq/affinity.c | 162 |
1 files changed, 106 insertions, 56 deletions
diff --git a/kernel/irq/affinity.c b/kernel/irq/affinity.c index a37a3b4b6342..f4f29b9d90ee 100644 --- a/kernel/irq/affinity.c +++ b/kernel/irq/affinity.c | |||
| @@ -39,7 +39,7 @@ static void irq_spread_init_one(struct cpumask *irqmsk, struct cpumask *nmsk, | |||
| 39 | } | 39 | } |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | static cpumask_var_t *alloc_node_to_possible_cpumask(void) | 42 | static cpumask_var_t *alloc_node_to_cpumask(void) |
| 43 | { | 43 | { |
| 44 | cpumask_var_t *masks; | 44 | cpumask_var_t *masks; |
| 45 | int node; | 45 | int node; |
| @@ -62,7 +62,7 @@ out_unwind: | |||
| 62 | return NULL; | 62 | return NULL; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static void free_node_to_possible_cpumask(cpumask_var_t *masks) | 65 | static void free_node_to_cpumask(cpumask_var_t *masks) |
| 66 | { | 66 | { |
| 67 | int node; | 67 | int node; |
| 68 | 68 | ||
| @@ -71,7 +71,7 @@ static void free_node_to_possible_cpumask(cpumask_var_t *masks) | |||
| 71 | kfree(masks); | 71 | kfree(masks); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static void build_node_to_possible_cpumask(cpumask_var_t *masks) | 74 | static void build_node_to_cpumask(cpumask_var_t *masks) |
| 75 | { | 75 | { |
| 76 | int cpu; | 76 | int cpu; |
| 77 | 77 | ||
| @@ -79,14 +79,14 @@ static void build_node_to_possible_cpumask(cpumask_var_t *masks) | |||
| 79 | cpumask_set_cpu(cpu, masks[cpu_to_node(cpu)]); | 79 | cpumask_set_cpu(cpu, masks[cpu_to_node(cpu)]); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | static int get_nodes_in_cpumask(cpumask_var_t *node_to_possible_cpumask, | 82 | static int get_nodes_in_cpumask(cpumask_var_t *node_to_cpumask, |
| 83 | const struct cpumask *mask, nodemask_t *nodemsk) | 83 | const struct cpumask *mask, nodemask_t *nodemsk) |
| 84 | { | 84 | { |
| 85 | int n, nodes = 0; | 85 | int n, nodes = 0; |
| 86 | 86 | ||
| 87 | /* Calculate the number of nodes in the supplied affinity mask */ | 87 | /* Calculate the number of nodes in the supplied affinity mask */ |
| 88 | for_each_node(n) { | 88 | for_each_node(n) { |
| 89 | if (cpumask_intersects(mask, node_to_possible_cpumask[n])) { | 89 | if (cpumask_intersects(mask, node_to_cpumask[n])) { |
| 90 | node_set(n, *nodemsk); | 90 | node_set(n, *nodemsk); |
| 91 | nodes++; | 91 | nodes++; |
| 92 | } | 92 | } |
| @@ -94,73 +94,46 @@ static int get_nodes_in_cpumask(cpumask_var_t *node_to_possible_cpumask, | |||
| 94 | return nodes; | 94 | return nodes; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | /** | 97 | static int irq_build_affinity_masks(const struct irq_affinity *affd, |
| 98 | * irq_create_affinity_masks - Create affinity masks for multiqueue spreading | 98 | int startvec, int numvecs, |
| 99 | * @nvecs: The total number of vectors | 99 | cpumask_var_t *node_to_cpumask, |
| 100 | * @affd: Description of the affinity requirements | 100 | const struct cpumask *cpu_mask, |
| 101 | * | 101 | struct cpumask *nmsk, |
| 102 | * Returns the masks pointer or NULL if allocation failed. | 102 | struct cpumask *masks) |
| 103 | */ | ||
| 104 | struct cpumask * | ||
| 105 | irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd) | ||
| 106 | { | 103 | { |
| 107 | int n, nodes, cpus_per_vec, extra_vecs, curvec; | 104 | int n, nodes, cpus_per_vec, extra_vecs, done = 0; |
| 108 | int affv = nvecs - affd->pre_vectors - affd->post_vectors; | 105 | int last_affv = affd->pre_vectors + numvecs; |
| 109 | int last_affv = affv + affd->pre_vectors; | 106 | int curvec = startvec; |
| 110 | nodemask_t nodemsk = NODE_MASK_NONE; | 107 | nodemask_t nodemsk = NODE_MASK_NONE; |
| 111 | struct cpumask *masks; | ||
| 112 | cpumask_var_t nmsk, *node_to_possible_cpumask; | ||
| 113 | |||
| 114 | /* | ||
| 115 | * If there aren't any vectors left after applying the pre/post | ||
| 116 | * vectors don't bother with assigning affinity. | ||
| 117 | */ | ||
| 118 | if (!affv) | ||
| 119 | return NULL; | ||
| 120 | |||
| 121 | if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL)) | ||
| 122 | return NULL; | ||
| 123 | |||
| 124 | masks = kcalloc(nvecs, sizeof(*masks), GFP_KERNEL); | ||
| 125 | if (!masks) | ||
| 126 | goto out; | ||
| 127 | 108 | ||
| 128 | node_to_possible_cpumask = alloc_node_to_possible_cpumask(); | 109 | if (!cpumask_weight(cpu_mask)) |
| 129 | if (!node_to_possible_cpumask) | 110 | return 0; |
| 130 | goto out; | ||
| 131 | 111 | ||
| 132 | /* Fill out vectors at the beginning that don't need affinity */ | 112 | nodes = get_nodes_in_cpumask(node_to_cpumask, cpu_mask, &nodemsk); |
| 133 | for (curvec = 0; curvec < affd->pre_vectors; curvec++) | ||
| 134 | cpumask_copy(masks + curvec, irq_default_affinity); | ||
| 135 | |||
| 136 | /* Stabilize the cpumasks */ | ||
| 137 | get_online_cpus(); | ||
| 138 | build_node_to_possible_cpumask(node_to_possible_cpumask); | ||
| 139 | nodes = get_nodes_in_cpumask(node_to_possible_cpumask, cpu_possible_mask, | ||
| 140 | &nodemsk); | ||
| 141 | 113 | ||
| 142 | /* | 114 | /* |
| 143 | * If the number of nodes in the mask is greater than or equal the | 115 | * If the number of nodes in the mask is greater than or equal the |
| 144 | * number of vectors we just spread the vectors across the nodes. | 116 | * number of vectors we just spread the vectors across the nodes. |
| 145 | */ | 117 | */ |
| 146 | if (affv <= nodes) { | 118 | if (numvecs <= nodes) { |
| 147 | for_each_node_mask(n, nodemsk) { | 119 | for_each_node_mask(n, nodemsk) { |
| 148 | cpumask_copy(masks + curvec, | 120 | cpumask_copy(masks + curvec, node_to_cpumask[n]); |
| 149 | node_to_possible_cpumask[n]); | 121 | if (++done == numvecs) |
| 150 | if (++curvec == last_affv) | ||
| 151 | break; | 122 | break; |
| 123 | if (++curvec == last_affv) | ||
| 124 | curvec = affd->pre_vectors; | ||
| 152 | } | 125 | } |
| 153 | goto done; | 126 | goto out; |
| 154 | } | 127 | } |
| 155 | 128 | ||
| 156 | for_each_node_mask(n, nodemsk) { | 129 | for_each_node_mask(n, nodemsk) { |
| 157 | int ncpus, v, vecs_to_assign, vecs_per_node; | 130 | int ncpus, v, vecs_to_assign, vecs_per_node; |
| 158 | 131 | ||
| 159 | /* Spread the vectors per node */ | 132 | /* Spread the vectors per node */ |
| 160 | vecs_per_node = (affv - (curvec - affd->pre_vectors)) / nodes; | 133 | vecs_per_node = (numvecs - (curvec - affd->pre_vectors)) / nodes; |
| 161 | 134 | ||
| 162 | /* Get the cpus on this node which are in the mask */ | 135 | /* Get the cpus on this node which are in the mask */ |
| 163 | cpumask_and(nmsk, cpu_possible_mask, node_to_possible_cpumask[n]); | 136 | cpumask_and(nmsk, cpu_mask, node_to_cpumask[n]); |
| 164 | 137 | ||
| 165 | /* Calculate the number of cpus per vector */ | 138 | /* Calculate the number of cpus per vector */ |
| 166 | ncpus = cpumask_weight(nmsk); | 139 | ncpus = cpumask_weight(nmsk); |
| @@ -181,19 +154,96 @@ irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd) | |||
| 181 | irq_spread_init_one(masks + curvec, nmsk, cpus_per_vec); | 154 | irq_spread_init_one(masks + curvec, nmsk, cpus_per_vec); |
| 182 | } | 155 | } |
| 183 | 156 | ||
| 184 | if (curvec >= last_affv) | 157 | done += v; |
| 158 | if (done >= numvecs) | ||
| 185 | break; | 159 | break; |
| 160 | if (curvec >= last_affv) | ||
| 161 | curvec = affd->pre_vectors; | ||
| 186 | --nodes; | 162 | --nodes; |
| 187 | } | 163 | } |
| 188 | 164 | ||
| 189 | done: | 165 | out: |
| 166 | return done; | ||
| 167 | } | ||
| 168 | |||
| 169 | /** | ||
| 170 | * irq_create_affinity_masks - Create affinity masks for multiqueue spreading | ||
| 171 | * @nvecs: The total number of vectors | ||
| 172 | * @affd: Description of the affinity requirements | ||
| 173 | * | ||
| 174 | * Returns the masks pointer or NULL if allocation failed. | ||
| 175 | */ | ||
| 176 | struct cpumask * | ||
| 177 | irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd) | ||
| 178 | { | ||
| 179 | int affvecs = nvecs - affd->pre_vectors - affd->post_vectors; | ||
| 180 | int curvec, usedvecs; | ||
| 181 | cpumask_var_t nmsk, npresmsk, *node_to_cpumask; | ||
| 182 | struct cpumask *masks = NULL; | ||
| 183 | |||
| 184 | /* | ||
| 185 | * If there aren't any vectors left after applying the pre/post | ||
| 186 | * vectors don't bother with assigning affinity. | ||
| 187 | */ | ||
| 188 | if (nvecs == affd->pre_vectors + affd->post_vectors) | ||
| 189 | return NULL; | ||
| 190 | |||
| 191 | if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL)) | ||
| 192 | return NULL; | ||
| 193 | |||
| 194 | if (!zalloc_cpumask_var(&npresmsk, GFP_KERNEL)) | ||
| 195 | goto outcpumsk; | ||
| 196 | |||
| 197 | node_to_cpumask = alloc_node_to_cpumask(); | ||
| 198 | if (!node_to_cpumask) | ||
| 199 | goto outnpresmsk; | ||
| 200 | |||
| 201 | masks = kcalloc(nvecs, sizeof(*masks), GFP_KERNEL); | ||
| 202 | if (!masks) | ||
| 203 | goto outnodemsk; | ||
| 204 | |||
| 205 | /* Fill out vectors at the beginning that don't need affinity */ | ||
| 206 | for (curvec = 0; curvec < affd->pre_vectors; curvec++) | ||
| 207 | cpumask_copy(masks + curvec, irq_default_affinity); | ||
| 208 | |||
| 209 | /* Stabilize the cpumasks */ | ||
| 210 | get_online_cpus(); | ||
| 211 | build_node_to_cpumask(node_to_cpumask); | ||
| 212 | |||
| 213 | /* Spread on present CPUs starting from affd->pre_vectors */ | ||
| 214 | usedvecs = irq_build_affinity_masks(affd, curvec, affvecs, | ||
| 215 | node_to_cpumask, cpu_present_mask, | ||
| 216 | nmsk, masks); | ||
| 217 | |||
| 218 | /* | ||
| 219 | * Spread on non present CPUs starting from the next vector to be | ||
| 220 | * handled. If the spreading of present CPUs already exhausted the | ||
| 221 | * vector space, assign the non present CPUs to the already spread | ||
| 222 | * out vectors. | ||
| 223 | */ | ||
| 224 | if (usedvecs >= affvecs) | ||
| 225 | curvec = affd->pre_vectors; | ||
| 226 | else | ||
| 227 | curvec = affd->pre_vectors + usedvecs; | ||
| 228 | cpumask_andnot(npresmsk, cpu_possible_mask, cpu_present_mask); | ||
| 229 | usedvecs += irq_build_affinity_masks(affd, curvec, affvecs, | ||
| 230 | node_to_cpumask, npresmsk, | ||
| 231 | nmsk, masks); | ||
| 190 | put_online_cpus(); | 232 | put_online_cpus(); |
| 191 | 233 | ||
| 192 | /* Fill out vectors at the end that don't need affinity */ | 234 | /* Fill out vectors at the end that don't need affinity */ |
| 235 | if (usedvecs >= affvecs) | ||
| 236 | curvec = affd->pre_vectors + affvecs; | ||
| 237 | else | ||
| 238 | curvec = affd->pre_vectors + usedvecs; | ||
| 193 | for (; curvec < nvecs; curvec++) | 239 | for (; curvec < nvecs; curvec++) |
| 194 | cpumask_copy(masks + curvec, irq_default_affinity); | 240 | cpumask_copy(masks + curvec, irq_default_affinity); |
| 195 | free_node_to_possible_cpumask(node_to_possible_cpumask); | 241 | |
| 196 | out: | 242 | outnodemsk: |
| 243 | free_node_to_cpumask(node_to_cpumask); | ||
| 244 | outnpresmsk: | ||
| 245 | free_cpumask_var(npresmsk); | ||
| 246 | outcpumsk: | ||
| 197 | free_cpumask_var(nmsk); | 247 | free_cpumask_var(nmsk); |
| 198 | return masks; | 248 | return masks; |
| 199 | } | 249 | } |
