当通过下面的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);}