Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
[platform/adaptation/renesas_rcar/renesas_kernel.git] / lib / cpu_rmap.c
1 /*
2  * cpu_rmap.c: CPU affinity reverse-map support
3  * Copyright 2011 Solarflare Communications Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published
7  * by the Free Software Foundation, incorporated herein by reference.
8  */
9
10 #include <linux/cpu_rmap.h>
11 #ifdef CONFIG_GENERIC_HARDIRQS
12 #include <linux/interrupt.h>
13 #endif
14 #include <linux/export.h>
15
16 /*
17  * These functions maintain a mapping from CPUs to some ordered set of
18  * objects with CPU affinities.  This can be seen as a reverse-map of
19  * CPU affinity.  However, we do not assume that the object affinities
20  * cover all CPUs in the system.  For those CPUs not directly covered
21  * by object affinities, we attempt to find a nearest object based on
22  * CPU topology.
23  */
24
25 /**
26  * alloc_cpu_rmap - allocate CPU affinity reverse-map
27  * @size: Number of objects to be mapped
28  * @flags: Allocation flags e.g. %GFP_KERNEL
29  */
30 struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags)
31 {
32         struct cpu_rmap *rmap;
33         unsigned int cpu;
34         size_t obj_offset;
35
36         /* This is a silly number of objects, and we use u16 indices. */
37         if (size > 0xffff)
38                 return NULL;
39
40         /* Offset of object pointer array from base structure */
41         obj_offset = ALIGN(offsetof(struct cpu_rmap, near[nr_cpu_ids]),
42                            sizeof(void *));
43
44         rmap = kzalloc(obj_offset + size * sizeof(rmap->obj[0]), flags);
45         if (!rmap)
46                 return NULL;
47
48         rmap->obj = (void **)((char *)rmap + obj_offset);
49
50         /* Initially assign CPUs to objects on a rota, since we have
51          * no idea where the objects are.  Use infinite distance, so
52          * any object with known distance is preferable.  Include the
53          * CPUs that are not present/online, since we definitely want
54          * any newly-hotplugged CPUs to have some object assigned.
55          */
56         for_each_possible_cpu(cpu) {
57                 rmap->near[cpu].index = cpu % size;
58                 rmap->near[cpu].dist = CPU_RMAP_DIST_INF;
59         }
60
61         rmap->size = size;
62         return rmap;
63 }
64 EXPORT_SYMBOL(alloc_cpu_rmap);
65
66 /* Reevaluate nearest object for given CPU, comparing with the given
67  * neighbours at the given distance.
68  */
69 static bool cpu_rmap_copy_neigh(struct cpu_rmap *rmap, unsigned int cpu,
70                                 const struct cpumask *mask, u16 dist)
71 {
72         int neigh;
73
74         for_each_cpu(neigh, mask) {
75                 if (rmap->near[cpu].dist > dist &&
76                     rmap->near[neigh].dist <= dist) {
77                         rmap->near[cpu].index = rmap->near[neigh].index;
78                         rmap->near[cpu].dist = dist;
79                         return true;
80                 }
81         }
82         return false;
83 }
84
85 #ifdef DEBUG
86 static void debug_print_rmap(const struct cpu_rmap *rmap, const char *prefix)
87 {
88         unsigned index;
89         unsigned int cpu;
90
91         pr_info("cpu_rmap %p, %s:\n", rmap, prefix);
92
93         for_each_possible_cpu(cpu) {
94                 index = rmap->near[cpu].index;
95                 pr_info("cpu %d -> obj %u (distance %u)\n",
96                         cpu, index, rmap->near[cpu].dist);
97         }
98 }
99 #else
100 static inline void
101 debug_print_rmap(const struct cpu_rmap *rmap, const char *prefix)
102 {
103 }
104 #endif
105
106 /**
107  * cpu_rmap_add - add object to a rmap
108  * @rmap: CPU rmap allocated with alloc_cpu_rmap()
109  * @obj: Object to add to rmap
110  *
111  * Return index of object.
112  */
113 int cpu_rmap_add(struct cpu_rmap *rmap, void *obj)
114 {
115         u16 index;
116
117         BUG_ON(rmap->used >= rmap->size);
118         index = rmap->used++;
119         rmap->obj[index] = obj;
120         return index;
121 }
122 EXPORT_SYMBOL(cpu_rmap_add);
123
124 /**
125  * cpu_rmap_update - update CPU rmap following a change of object affinity
126  * @rmap: CPU rmap to update
127  * @index: Index of object whose affinity changed
128  * @affinity: New CPU affinity of object
129  */
130 int cpu_rmap_update(struct cpu_rmap *rmap, u16 index,
131                     const struct cpumask *affinity)
132 {
133         cpumask_var_t update_mask;
134         unsigned int cpu;
135
136         if (unlikely(!zalloc_cpumask_var(&update_mask, GFP_KERNEL)))
137                 return -ENOMEM;
138
139         /* Invalidate distance for all CPUs for which this used to be
140          * the nearest object.  Mark those CPUs for update.
141          */
142         for_each_online_cpu(cpu) {
143                 if (rmap->near[cpu].index == index) {
144                         rmap->near[cpu].dist = CPU_RMAP_DIST_INF;
145                         cpumask_set_cpu(cpu, update_mask);
146                 }
147         }
148
149         debug_print_rmap(rmap, "after invalidating old distances");
150
151         /* Set distance to 0 for all CPUs in the new affinity mask.
152          * Mark all CPUs within their NUMA nodes for update.
153          */
154         for_each_cpu(cpu, affinity) {
155                 rmap->near[cpu].index = index;
156                 rmap->near[cpu].dist = 0;
157                 cpumask_or(update_mask, update_mask,
158                            cpumask_of_node(cpu_to_node(cpu)));
159         }
160
161         debug_print_rmap(rmap, "after updating neighbours");
162
163         /* Update distances based on topology */
164         for_each_cpu(cpu, update_mask) {
165                 if (cpu_rmap_copy_neigh(rmap, cpu,
166                                         topology_thread_cpumask(cpu), 1))
167                         continue;
168                 if (cpu_rmap_copy_neigh(rmap, cpu,
169                                         topology_core_cpumask(cpu), 2))
170                         continue;
171                 if (cpu_rmap_copy_neigh(rmap, cpu,
172                                         cpumask_of_node(cpu_to_node(cpu)), 3))
173                         continue;
174                 /* We could continue into NUMA node distances, but for now
175                  * we give up.
176                  */
177         }
178
179         debug_print_rmap(rmap, "after copying neighbours");
180
181         free_cpumask_var(update_mask);
182         return 0;
183 }
184 EXPORT_SYMBOL(cpu_rmap_update);
185
186 #ifdef CONFIG_GENERIC_HARDIRQS
187
188 /* Glue between IRQ affinity notifiers and CPU rmaps */
189
190 struct irq_glue {
191         struct irq_affinity_notify notify;
192         struct cpu_rmap *rmap;
193         u16 index;
194 };
195
196 /**
197  * free_irq_cpu_rmap - free a CPU affinity reverse-map used for IRQs
198  * @rmap: Reverse-map allocated with alloc_irq_cpu_map(), or %NULL
199  *
200  * Must be called in process context, before freeing the IRQs, and
201  * without holding any locks required by global workqueue items.
202  */
203 void free_irq_cpu_rmap(struct cpu_rmap *rmap)
204 {
205         struct irq_glue *glue;
206         u16 index;
207
208         if (!rmap)
209                 return;
210
211         for (index = 0; index < rmap->used; index++) {
212                 glue = rmap->obj[index];
213                 irq_set_affinity_notifier(glue->notify.irq, NULL);
214         }
215         irq_run_affinity_notifiers();
216
217         kfree(rmap);
218 }
219 EXPORT_SYMBOL(free_irq_cpu_rmap);
220
221 static void
222 irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask)
223 {
224         struct irq_glue *glue =
225                 container_of(notify, struct irq_glue, notify);
226         int rc;
227
228         rc = cpu_rmap_update(glue->rmap, glue->index, mask);
229         if (rc)
230                 pr_warning("irq_cpu_rmap_notify: update failed: %d\n", rc);
231 }
232
233 static void irq_cpu_rmap_release(struct kref *ref)
234 {
235         struct irq_glue *glue =
236                 container_of(ref, struct irq_glue, notify.kref);
237         kfree(glue);
238 }
239
240 /**
241  * irq_cpu_rmap_add - add an IRQ to a CPU affinity reverse-map
242  * @rmap: The reverse-map
243  * @irq: The IRQ number
244  *
245  * This adds an IRQ affinity notifier that will update the reverse-map
246  * automatically.
247  *
248  * Must be called in process context, after the IRQ is allocated but
249  * before it is bound with request_irq().
250  */
251 int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq)
252 {
253         struct irq_glue *glue = kzalloc(sizeof(*glue), GFP_KERNEL);
254         int rc;
255
256         if (!glue)
257                 return -ENOMEM;
258         glue->notify.notify = irq_cpu_rmap_notify;
259         glue->notify.release = irq_cpu_rmap_release;
260         glue->rmap = rmap;
261         glue->index = cpu_rmap_add(rmap, glue);
262         rc = irq_set_affinity_notifier(irq, &glue->notify);
263         if (rc)
264                 kfree(glue);
265         return rc;
266 }
267 EXPORT_SYMBOL(irq_cpu_rmap_add);
268
269 #endif /* CONFIG_GENERIC_HARDIRQS */