/* * (C) 2004-2009 Dominik Brodowski * * Licensed under the terms of the GNU GPL License version 2. */ #include #include #include #include #include #include #include #include #include "cpufreq.h" #include "cpuidle.h" #include "helpers/helpers.h" #define NORM_FREQ_LEN 32 static struct option set_opts[] = { {"min", required_argument, NULL, 'd'}, {"max", required_argument, NULL, 'u'}, {"governor", required_argument, NULL, 'g'}, {"freq", required_argument, NULL, 'f'}, {"related", no_argument, NULL, 'r'}, { }, }; static void print_error(void) { printf(_("Error setting new values. Common errors:\n" "- Do you have proper administration rights? (super-user?)\n" "- Is the governor you requested available and modprobed?\n" "- Trying to set an invalid policy?\n" "- Trying to set a specific frequency, but userspace governor is not available,\n" " for example because of hardware which cannot be set to a specific frequency\n" " or because the userspace governor isn't loaded?\n")); }; struct freq_units { char *str_unit; int power_of_ten; }; const struct freq_units def_units[] = { {"hz", -3}, {"khz", 0}, /* default */ {"mhz", 3}, {"ghz", 6}, {"thz", 9}, {NULL, 0} }; static void print_unknown_arg(void) { printf(_("invalid or unknown argument\n")); } static unsigned long string_to_frequency(const char *str) { char normalized[NORM_FREQ_LEN]; const struct freq_units *unit; const char *scan; char *end; unsigned long freq; int power = 0, match_count = 0, i, cp, pad; while (*str == '0') str++; for (scan = str; isdigit(*scan) || *scan == '.'; scan++) { if (*scan == '.' && match_count == 0) match_count = 1; else if (*scan == '.' && match_count == 1) return 0; } if (*scan) { match_count = 0; for (unit = def_units; unit->str_unit; unit++) { for (i = 0; scan[i] && tolower(scan[i]) == unit->str_unit[i]; ++i) continue; if (scan[i]) continue; match_count++; power = unit->power_of_ten; } if (match_count != 1) return 0; } /* count the number of digits to be copied */ for (cp = 0; isdigit(str[cp]); cp++) continue; if (str[cp] == '.') { while (power > -1 && isdigit(str[cp+1])) cp++, power--; } if (power >= -1) /* not enough => pad */ pad = power + 1; else /* to much => strip */ pad = 0, cp += power + 1; /* check bounds */ if (cp <= 0 || cp + pad > NORM_FREQ_LEN - 1) return 0; /* copy digits */ for (i = 0; i < cp; i++, str++) { if (*str == '.') str++; normalized[i] = *str; } /* and pad */ for (; i < cp + pad; i++) normalized[i] = '0'; /* round up, down ? */ match_count = (normalized[i-1] >= '5'); /* and drop the decimal part */ normalized[i-1] = 0; /* cp > 0 && pad >= 0 ==> i > 0 */ /* final conversion (and applying rounding) */ errno = 0; freq = strtoul(normalized, &end, 10); if (errno) return 0; else { if (match_count && freq != ULONG_MAX) freq++; return freq; } } static int do_new_policy(unsigned int cpu, struct cpufreq_policy *new_pol) { struct cpufreq_policy *cur_pol = cpufreq_get_policy(cpu); int ret; if (!cur_pol) { printf(_("wrong, unknown or unhandled CPU?\n")); return -EINVAL; } if (!new_pol->min) new_pol->min = cur_pol->min; if (!new_pol->max) new_pol->max = cur_pol->max; if (!new_pol->governor) new_pol->governor = cur_pol->governor; ret = cpufreq_set_policy(cpu, new_pol); cpufreq_put_policy(cur_pol); return ret; } static int do_one_cpu(unsigned int cpu, struct cpufreq_policy *new_pol, unsigned long freq, unsigned int pc) { switch (pc) { case 0: return cpufreq_set_frequency(cpu, freq); case 1: /* if only one value of a policy is to be changed, we can * use a "fast path". */ if (new_pol->min) return cpufreq_modify_policy_min(cpu, new_pol->min); else if (new_pol->max) return cpufreq_modify_policy_max(cpu, new_pol->max); else if (new_pol->governor) return cpufreq_modify_policy_governor(cpu, new_pol->governor); default: /* slow path */ return do_new_policy(cpu, new_pol); } } int cmd_freq_set(int argc, char **argv) { extern char *optarg; extern int optind, opterr, optopt; int ret = 0, cont = 1; int double_parm = 0, related = 0, policychange = 0; unsigned long freq = 0; char gov[20]; unsigned int cpu; struct cpufreq_policy new_pol = { .min = 0, .max = 0, .governor = NULL, }; /* parameter parsing */ do { ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL); switch (ret) { case '?': print_unknown_arg(); return -EINVAL; case -1: cont = 0; break; case 'r': if (related) double_parm++; related++; break; case 'd': if (new_pol.min) double_parm++; policychange++; new_pol.min = string_to_frequency(optarg); if (new_pol.min == 0) { print_unknown_arg(); return -EINVAL; } break; case 'u': if (new_pol.max) double_parm++; policychange++; new_pol.max = string_to_frequency(optarg); if (new_pol.max == 0) { print_unknown_arg(); return -EINVAL; } break; case 'f': if (freq) double_parm++; freq = string_to_frequency(optarg); if (freq == 0) { print_unknown_arg(); return -EINVAL; } break; case 'g': if (new_pol.governor) double_parm++; policychange++; if ((strlen(optarg) < 3) || (strlen(optarg) > 18)) { print_unknown_arg(); return -EINVAL; } if ((sscanf(optarg, "%19s", gov)) != 1) { print_unknown_arg(); return -EINVAL; } new_pol.governor = gov; break; } } while (cont); /* parameter checking */ if (double_parm) { printf("the same parameter was passed more than once\n"); return -EINVAL; } if (freq && policychange) { printf(_("the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" "-g/--governor parameters\n")); return -EINVAL; } if (!freq && !policychange) { printf(_("At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" "-g/--governor must be passed\n")); return -EINVAL; } /* Default is: set all CPUs */ if (bitmask_isallclear(cpus_chosen)) bitmask_setall(cpus_chosen); /* Also set frequency settings for related CPUs if -r is passed */ if (related) { for (cpu = bitmask_first(cpus_chosen); cpu <= bitmask_last(cpus_chosen); cpu++) { struct cpufreq_affected_cpus *cpus; if (!bitmask_isbitset(cpus_chosen, cpu) || cpupower_is_cpu_online(cpu) != 1) continue; cpus = cpufreq_get_related_cpus(cpu); if (!cpus) break; while (cpus->next) { bitmask_setbit(cpus_chosen, cpus->cpu); cpus = cpus->next; } cpufreq_put_related_cpus(cpus); } } /* loop over CPUs */ for (cpu = bitmask_first(cpus_chosen); cpu <= bitmask_last(cpus_chosen); cpu++) { if (!bitmask_isbitset(cpus_chosen, cpu) || cpupower_is_cpu_online(cpu) != 1) continue; printf(_("Setting cpu: %d\n"), cpu); ret = do_one_cpu(cpu, &new_pol, freq, policychange); if (ret) { print_error(); return ret; } } return 0; } MU off may result in alignment faults. So fix the situation by moving the update_fdt_memmap() call into the callback function invoked by efi_exit_boot_services() right before it calls the ExitBootServices() UEFI service (which is arguably a better place for it anyway) Note that disabling the MMU in ExitBootServices() is not compliant with the UEFI spec, and carries great risk due to the fact that switching from cached to uncached memory accesses halfway through compiler generated code (i.e., involving a stack) can never be done in a way that is architecturally safe. Fixes: abfb7b686a3e ("efi/libstub/arm*: Pass latest memory map to the kernel") Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Tested-by: Riku Voipio <riku.voipio@linaro.org> Cc: <stable@vger.kernel.org> Cc: mark.rutland@arm.com Cc: linux-efi@vger.kernel.org Cc: matt@codeblueprint.co.uk Cc: leif.lindholm@linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1485971102-23330-2-git-send-email-ard.biesheuvel@linaro.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'net/dns_resolver/internal.h')