@@ -42,7 +42,7 @@ extern void __init dump_numa_cpu_topology(void);
extern int sysfs_add_device_to_node(struct device *dev, int nid);
extern void sysfs_remove_device_from_node(struct device *dev, int nid);
-extern int numa_update_cpu_topology(bool cpus_locked);
+extern void topology_schedule_update(void);
static inline void update_numa_cpu_lookup_table(unsigned int cpu, int node)
{
@@ -77,10 +77,7 @@ static inline void sysfs_remove_device_from_node(struct device *dev,
{
}
-static inline int numa_update_cpu_topology(bool cpus_locked)
-{
- return 0;
-}
+static inline void topology_schedule_update(void) {}
static inline void update_numa_cpu_lookup_table(unsigned int cpu, int node) {}
@@ -285,7 +285,7 @@ static void handle_prrn_event(s32 scope)
* the RTAS event.
*/
pseries_devicetree_update(-scope);
- numa_update_cpu_topology(false);
+ topology_schedule_update();
}
static void handle_rtas_event(const struct rtas_error_log *log)
@@ -1077,6 +1077,8 @@ static int prrn_enabled;
static void reset_topology_timer(void);
static int topology_timer_secs = 1;
static int topology_inited;
+static int topology_update_in_progress;
+static int topology_changed;
/*
* Change polling interval for associativity changes.
@@ -1297,9 +1299,9 @@ static int update_lookup_table(void *data)
* Update the node maps and sysfs entries for each cpu whose home node
* has changed. Returns 1 when the topology has changed, and 0 otherwise.
*
- * cpus_locked says whether we already hold cpu_hotplug_lock.
+ * readd_cpus: Also readd any CPUs that have changed affinity
*/
-int numa_update_cpu_topology(bool cpus_locked)
+static int numa_update_cpu_topology(bool readd_cpus)
{
unsigned int cpu, sibling, changed = 0;
struct topology_update_data *updates, *ud;
@@ -1307,7 +1309,8 @@ int numa_update_cpu_topology(bool cpus_locked)
struct device *dev;
int weight, new_nid, i = 0;
- if (!prrn_enabled && !vphn_enabled && topology_inited)
+ if ((!prrn_enabled && !vphn_enabled && topology_inited) ||
+ topology_update_in_progress)
return 0;
weight = cpumask_weight(&cpu_associativity_changes_mask);
@@ -1318,6 +1321,8 @@ int numa_update_cpu_topology(bool cpus_locked)
if (!updates)
return 0;
+ topology_update_in_progress = 1;
+
cpumask_clear(&updated_cpus);
for_each_cpu(cpu, &cpu_associativity_changes_mask) {
@@ -1339,16 +1344,21 @@ int numa_update_cpu_topology(bool cpus_locked)
new_nid = find_and_online_cpu_nid(cpu);
- if (new_nid == numa_cpu_lookup_table[cpu]) {
+ if ((new_nid == numa_cpu_lookup_table[cpu]) ||
+ !cpu_present(cpu)) {
cpumask_andnot(&cpu_associativity_changes_mask,
&cpu_associativity_changes_mask,
cpu_sibling_mask(cpu));
- dbg("Assoc chg gives same node %d for cpu%d\n",
+ if (cpu_present(cpu))
+ dbg("Assoc chg gives same node %d for cpu%d\n",
new_nid, cpu);
cpu = cpu_last_thread_sibling(cpu);
continue;
}
+ if (readd_cpus)
+ dlpar_cpu_readd(cpu);
+
for_each_cpu(sibling, cpu_sibling_mask(cpu)) {
ud = &updates[i++];
ud->next = &updates[i];
@@ -1390,7 +1400,7 @@ int numa_update_cpu_topology(bool cpus_locked)
if (!cpumask_weight(&updated_cpus))
goto out;
- if (cpus_locked)
+ if (!readd_cpus)
stop_machine_cpuslocked(update_cpu_topology, &updates[0],
&updated_cpus);
else
@@ -1401,9 +1411,9 @@ int numa_update_cpu_topology(bool cpus_locked)
* offline CPUs. It is best to perform this update from the stop-
* machine context.
*/
- if (cpus_locked)
+ if (!readd_cpus)
stop_machine_cpuslocked(update_lookup_table, &updates[0],
- cpumask_of(raw_smp_processor_id()));
+ cpumask_of(raw_smp_processor_id()));
else
stop_machine(update_lookup_table, &updates[0],
cpumask_of(raw_smp_processor_id()));
@@ -1420,35 +1430,40 @@ int numa_update_cpu_topology(bool cpus_locked)
}
out:
+ topology_update_in_progress = 0;
kfree(updates);
return changed;
}
int arch_update_cpu_topology(void)
{
- return numa_update_cpu_topology(true);
+ return numa_update_cpu_topology(false);
}
static void topology_work_fn(struct work_struct *work)
{
- rebuild_sched_domains();
+ lock_device_hotplug();
+ if (numa_update_cpu_topology(true))
+ rebuild_sched_domains();
+ unlock_device_hotplug();
}
static DECLARE_WORK(topology_work, topology_work_fn);
-static void topology_schedule_update(void)
+void topology_schedule_update(void)
{
- schedule_work(&topology_work);
+ if (!topology_update_in_progress)
+ schedule_work(&topology_work);
}
static void topology_timer_fn(struct timer_list *unused)
{
- if (prrn_enabled && cpumask_weight(&cpu_associativity_changes_mask))
- topology_schedule_update();
- else if (vphn_enabled) {
+ if (vphn_enabled) {
if (update_cpu_associativity_changes_mask() > 0)
topology_schedule_update();
reset_topology_timer();
}
+ else if (prrn_enabled && cpumask_weight(&cpu_associativity_changes_mask))
+ topology_schedule_update();
}
static struct timer_list topology_timer;
@@ -1553,7 +1568,7 @@ void __init shared_proc_topology_init(void)
if (lppaca_shared_proc(get_lppaca())) {
bitmap_fill(cpumask_bits(&cpu_associativity_changes_mask),
nr_cpumask_bits);
- numa_update_cpu_topology(false);
+ topology_schedule_update();
}
}