static struct chip {
unsigned int id;
bool throttled;
+ cpumask_t mask;
+ struct work_struct throttle;
} *chips;
static int nr_chips;
return powernv_pstate_info.max - powernv_pstate_info.nominal;
}
-static void powernv_cpufreq_throttle_check(unsigned int cpu)
+static void powernv_cpufreq_throttle_check(void *data)
{
+ unsigned int cpu = smp_processor_id();
unsigned long pmsr;
int pmsr_pmax, pmsr_lp, i;
return 0;
if (!throttled)
- powernv_cpufreq_throttle_check(smp_processor_id());
+ powernv_cpufreq_throttle_check(NULL);
freq_data.pstate_id = powernv_freqs[new_index].driver_data;
.notifier_call = powernv_cpufreq_reboot_notifier,
};
+void powernv_cpufreq_work_fn(struct work_struct *work)
+{
+ struct chip *chip = container_of(work, struct chip, throttle);
+
+ smp_call_function_any(&chip->mask,
+ powernv_cpufreq_throttle_check, NULL, 0);
+}
+
static char throttle_reason[][30] = {
"No throttling",
"Power Cap",
{
struct opal_msg *msg = _msg;
struct opal_occ_msg omsg;
+ int i;
if (msg_type != OPAL_MSG_OCC)
return 0;
occ_reset = false;
throttled = false;
pr_info("OCC: Active\n");
+
+ for (i = 0; i < nr_chips; i++)
+ schedule_work(&chips[i].throttle);
+
return 0;
}
else if (!omsg.throttle_status)
pr_info("OCC: Chip %u %s\n", (unsigned int)omsg.chip,
throttle_reason[omsg.throttle_status]);
+ else
+ return 0;
+
+ for (i = 0; i < nr_chips; i++)
+ if (chips[i].id == omsg.chip)
+ schedule_work(&chips[i].throttle);
}
return 0;
}
for (i = 0; i < nr_chips; i++) {
chips[i].id = chip[i];
chips[i].throttled = false;
+ cpumask_copy(&chips[i].mask, cpumask_of_node(chip[i]));
+ INIT_WORK(&chips[i].throttle, powernv_cpufreq_work_fn);
}
return 0;