Merge tag 'powerpc-4.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[platform/kernel/linux-rpi.git] / arch / powerpc / mm / numa.c
index 7301645..adb6364 100644 (file)
@@ -1148,11 +1148,33 @@ struct topology_update_data {
        int new_nid;
 };
 
+#define TOPOLOGY_DEF_TIMER_SECS        60
+
 static u8 vphn_cpu_change_counts[NR_CPUS][MAX_DISTANCE_REF_POINTS];
 static cpumask_t cpu_associativity_changes_mask;
 static int vphn_enabled;
 static int prrn_enabled;
 static void reset_topology_timer(void);
+static int topology_timer_secs = 1;
+static int topology_inited;
+static int topology_update_needed;
+
+/*
+ * Change polling interval for associativity changes.
+ */
+int timed_topology_update(int nsecs)
+{
+       if (vphn_enabled) {
+               if (nsecs > 0)
+                       topology_timer_secs = nsecs;
+               else
+                       topology_timer_secs = TOPOLOGY_DEF_TIMER_SECS;
+
+               reset_topology_timer();
+       }
+
+       return 0;
+}
 
 /*
  * Store the current values of the associativity change counters in the
@@ -1246,6 +1268,11 @@ static long vphn_get_associativity(unsigned long cpu,
                        "hcall_vphn() experienced a hardware fault "
                        "preventing VPHN. Disabling polling...\n");
                stop_topology_update();
+               break;
+       case H_SUCCESS:
+               dbg("VPHN hcall succeeded. Reset polling...\n");
+               timed_topology_update(0);
+               break;
        }
 
        return rc;
@@ -1323,8 +1350,11 @@ int numa_update_cpu_topology(bool cpus_locked)
        struct device *dev;
        int weight, new_nid, i = 0;
 
-       if (!prrn_enabled && !vphn_enabled)
+       if (!prrn_enabled && !vphn_enabled) {
+               if (!topology_inited)
+                       topology_update_needed = 1;
                return 0;
+       }
 
        weight = cpumask_weight(&cpu_associativity_changes_mask);
        if (!weight)
@@ -1363,22 +1393,30 @@ int numa_update_cpu_topology(bool cpus_locked)
                        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",
+                                       new_nid, cpu);
                        cpu = cpu_last_thread_sibling(cpu);
                        continue;
                }
 
                for_each_cpu(sibling, cpu_sibling_mask(cpu)) {
                        ud = &updates[i++];
+                       ud->next = &updates[i];
                        ud->cpu = sibling;
                        ud->new_nid = new_nid;
                        ud->old_nid = numa_cpu_lookup_table[sibling];
                        cpumask_set_cpu(sibling, &updated_cpus);
-                       if (i < weight)
-                               ud->next = &updates[i];
                }
                cpu = cpu_last_thread_sibling(cpu);
        }
 
+       /*
+        * Prevent processing of 'updates' from overflowing array
+        * where last entry filled in a 'next' pointer.
+        */
+       if (i)
+               updates[i-1].next = NULL;
+
        pr_debug("Topology update for the following CPUs:\n");
        if (cpumask_weight(&updated_cpus)) {
                for (ud = &updates[0]; ud; ud = ud->next) {
@@ -1433,6 +1471,7 @@ int numa_update_cpu_topology(bool cpus_locked)
 
 out:
        kfree(updates);
+       topology_update_needed = 0;
        return changed;
 }
 
@@ -1466,7 +1505,7 @@ static struct timer_list topology_timer;
 
 static void reset_topology_timer(void)
 {
-       mod_timer(&topology_timer, jiffies + 60 * HZ);
+       mod_timer(&topology_timer, jiffies + topology_timer_secs * HZ);
 }
 
 #ifdef CONFIG_SMP
@@ -1515,15 +1554,14 @@ int start_topology_update(void)
        if (firmware_has_feature(FW_FEATURE_PRRN)) {
                if (!prrn_enabled) {
                        prrn_enabled = 1;
-                       vphn_enabled = 0;
 #ifdef CONFIG_SMP
                        rc = of_reconfig_notifier_register(&dt_update_nb);
 #endif
                }
-       } else if (firmware_has_feature(FW_FEATURE_VPHN) &&
+       }
+       if (firmware_has_feature(FW_FEATURE_VPHN) &&
                   lppaca_shared_proc(get_lppaca())) {
                if (!vphn_enabled) {
-                       prrn_enabled = 0;
                        vphn_enabled = 1;
                        setup_cpu_associativity_change_counters();
                        timer_setup(&topology_timer, topology_timer_fn,
@@ -1547,7 +1585,8 @@ int stop_topology_update(void)
 #ifdef CONFIG_SMP
                rc = of_reconfig_notifier_unregister(&dt_update_nb);
 #endif
-       } else if (vphn_enabled) {
+       }
+       if (vphn_enabled) {
                vphn_enabled = 0;
                rc = del_timer_sync(&topology_timer);
        }
@@ -1610,9 +1649,17 @@ static int topology_update_init(void)
        if (topology_updates_enabled)
                start_topology_update();
 
+       if (vphn_enabled)
+               topology_schedule_update();
+
        if (!proc_create("powerpc/topology_updates", 0644, NULL, &topology_ops))
                return -ENOMEM;
 
+       topology_inited = 1;
+       if (topology_update_needed)
+               bitmap_fill(cpumask_bits(&cpu_associativity_changes_mask),
+                                       nr_cpumask_bits);
+
        return 0;
 }
 device_initcall(topology_update_init);