首页 > 学院 > 开发设计 > 正文

echo 0 > /sys/devices/system/cpu/cpuX/online

2019-11-09 14:50:46
字体:
来源:转载
供稿:网友
当通过下面的code是cpu offline的话。echo 0 > /sys/devices/system/cpu/cpuX/online具体的code flow如下:int device_add(struct device *dev)->device_create_file而dev_attr_onlline 就是按照下面的方式定义的static ssize_t online_store(struct device *dev, struct device_attribute *attr,                const char *buf, size_t count){    bool val;    int ret;    ret = strtobool(buf, &val);    if (ret < 0)        return ret;    ret = lock_device_hotplug_sysfs();    if (ret)        return ret;    ret = val ? device_online(dev) : device_offline(dev);    unlock_device_hotplug();    return ret < 0 ? ret : count;}static DEVICE_ATTR_RW(online);当echo 0的时候选择device_online,否则device_offlineint device_offline(struct device *dev){    int ret;    if (dev->offline_disabled)        return -EPERM;    ret = device_for_each_child(dev, NULL, device_check_offline);    if (ret)        return ret;    device_lock(dev);    if (device_supports_offline(dev)) {        if (dev->offline) {            ret = 1;        } else {            ret = dev->bus->offline(dev);            if (!ret) {                kobject_uevent(&dev->kobj, KOBJ_OFFLINE);                dev->offline = true;            }        }    }    device_unlock(dev);    return ret;}可见是调用的bus->offline而cpu的bus定义如下:struct bus_type cpu_subsys = {    .name = "cpu",    .dev_name = "cpu",    .match = cpu_subsys_match,#ifdef CONFIG_HOTPLUG_CPU    .online = cpu_subsys_online,    .offline = cpu_subsys_offline,#endif};最终会调用cpu_subsys_offline->cpu_down->do_cpu_down->_cpu_down->cpuhp_down_callbacksstatic int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,                 bool bringup, struct hlist_node *node){    struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);    struct cpuhp_step *step = cpuhp_get_step(state);    int (*cbm)(unsigned int cpu, struct hlist_node *node);    int (*cb)(unsigned int cpu);    int ret, cnt;    if (!step->multi_instance) {        cb = bringup ? step->startup.single : step->teardown.single;        if (!cb)            return 0;        trace_cpuhp_enter(cpu, st->target, state, cb);        ret = cb(cpu);        trace_cpuhp_exit(cpu, st->state, state, ret);        return ret;    }    cbm = bringup ? step->startup.multi : step->teardown.multi;    if (!cbm)        return 0;    }在cpuhp_invoke_callback 中我们假定step->multi_instance == 0,因此cb= step->teardown.single其是在cpuhp_bp_states 数组中定义的    [CPUHP_TEARDOWN_CPU] = {        .name            = "cpu:teardown",        .startup.single        = NULL,        .teardown.single    = takedown_cpu,        .cant_stop        = true,    },takedown_cpu->__cpu_die->op_cpu_kill其中op_cpu_kill 在arm64下定义如下:static int op_cpu_kill(unsigned int cpu){    /*     * If we have no means of synchronising with the dying CPU, then assume     * that it is really dead. We can only wait for an arbitrary length of     * time and hope that it's dead, so let's skip the wait and just hope.     */    if (!cpu_ops[cpu]->cpu_kill)        return 0;    return cpu_ops[cpu]->cpu_kill(cpu);}而在smp_cpu_setup->cpu_read_ops来决定cpu_ops的值int __init cpu_read_ops(int cpu){    const char *enable_method = cpu_read_enable_method(cpu);    if (!enable_method)        return -ENODEV;    cpu_ops[cpu] = cpu_get_ops(enable_method);    if (!cpu_ops[cpu]) {        PR_warn("Unsupported enable-method: %s/n", enable_method);        return -EOPNOTSUPP;    }    return 0;}enable_method 是会从deviceTree或者acpi表中parse 当前的enable_methodstatic const char *__init cpu_read_enable_method(int cpu){    const char *enable_method;    if (acpi_disabled) {        struct device_node *dn = of_get_cpu_node(cpu, NULL);        if (!dn) {            if (!cpu)                pr_err("Failed to find device node for boot cpu/n");            return NULL;        }        enable_method = of_get_property(dn, "enable-method", NULL);        if (!enable_method) {            /*             * The boot CPU may not have an enable method (e.g.             * when spin-table is used for secondaries).             * Don't warn spuriously.             */            if (cpu != 0)                pr_err("%s: missing enable-method property/n",                    dn->full_name);        }    } else {        enable_method = acpi_get_enable_method(cpu);        if (!enable_method) {            /*             * In ACPI systems the boot CPU does not require             * checking the enable method since for some             * boot protocol (ie parking protocol) it need not             * be initialized. Don't warn spuriously.             */            if (cpu != 0)                pr_err("Unsupported ACPI enable-method/n");        }    }    return enable_method;}我们以acpi为例static inline const char *acpi_get_enable_method(int cpu){    if (acpi_psci_present())        return "psci";    if (acpi_parking_protocol_valid(cpu))        return "parking-protocol";    return NULL;}可见cpu_ops分为两类,psci和parking-protocol,目前主流是psci,具体是在acpi的FADT表中判断当前是否支持psci的bool __init acpi_psci_present(void){    return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;}决定是psci后,因此cpu_ops就是cpu_psci_opsstatic const struct cpu_Operations *acpi_supported_cpu_ops[] __initconst = {#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL    &acpi_parking_protocol_ops,#endif    &cpu_psci_ops,    NULL,};const struct cpu_operations cpu_psci_ops = {    .name        = "psci",#ifdef CONFIG_CPU_IDLE    .cpu_init_idle    = psci_cpu_init_idle,    .cpu_suspend    = psci_cpu_suspend_enter,#endif    .cpu_init    = cpu_psci_cpu_init,    .cpu_prepare    = cpu_psci_cpu_prepare,    .cpu_boot    = cpu_psci_cpu_boot,#ifdef CONFIG_HOTPLUG_CPU    .cpu_disable    = cpu_psci_cpu_disable,    .cpu_die    = cpu_psci_cpu_die,    .cpu_kill    = cpu_psci_cpu_kill,#endif};psci的cpu_kill是cpu_psci_cpu_killstatic int cpu_psci_cpu_kill(unsigned int cpu){    int err, i;    if (!psci_ops.affinity_info)        return 0;    /*     * cpu_kill could race with cpu_die and we can     * potentially end up declaring this cpu undead     * while it is dying. So, try again a few times.     */    for (i = 0; i < 10; i++) {        err = psci_ops.affinity_info(cpu_logical_map(cpu), 0);        if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) {            pr_info("CPU%d killed./n", cpu);            return 0;        }        msleep(10);        pr_info("Retrying again to check for CPU kill/n");    }    pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)/n",            cpu, err);    return -ETIMEDOUT;}有调用psci_ops.affinity_info    psci_ops.affinity_info = psci_affinity_info;可见最后是给ATF发信号让ATF来关掉cpu的。static int psci_affinity_info(unsigned long target_affinity,        unsigned long lowest_affinity_level){    return invoke_psci_fn(PSCI_FN_NATIVE(0_2, AFFINITY_INFO),                  target_affinity, lowest_affinity_level, 0);}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表