static int __cpuinit tegra30_idle_lp2(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu; bool entered_lp2 = false; bool last_cpu; local_fiq_disable(); last_cpu = tegra_set_cpu_in_lp2(cpu); cpu_pm_enter(); if (cpu == 0) { if (last_cpu) entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, index); else cpu_do_idle(); } else { entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index); } cpu_pm_exit(); tegra_clear_cpu_in_lp2(cpu); local_fiq_enable(); smp_rmb(); return (entered_lp2) ? index : 0; }
static int __init coherency_late_init(void) { struct device_node *np; if (!is_smp()) return 0; np = of_find_matching_node(NULL, of_coherency_table); if (np) { bus_register_notifier(&platform_bus_type, &mvebu_hwcc_platform_nb); of_node_put(np); } return 0; }
int __init coherency_init(void) { struct device_node *np; /* * The coherency fabric is needed: * - For coherency between processors on Armada XP, so only * when SMP is enabled. * - For coherency between the processor and I/O devices, but * this coherency requires many pre-requisites (write * allocate cache policy, shareable pages, SMP bit set) that * are only meant in SMP situations. * * Note that this means that on Armada 370, there is currently * no way to use hardware I/O coherency, because even when * CONFIG_SMP is enabled, is_smp() returns false due to the * Armada 370 being a single-core processor. To lift this * limitation, we would have to find a way to make the cache * policy set to write-allocate (on all Armada SoCs), and to * set the shareable attribute in page tables (on all Armada * SoCs except the Armada 370). Unfortunately, such decisions * are taken very early in the kernel boot process, at a point * where we don't know yet on which SoC we are running. */ if (!is_smp()) return 0; np = of_find_matching_node(NULL, of_coherency_table); if (np) { struct resource res; pr_info("Initializing Coherency fabric\n"); of_address_to_resource(np, 0, &res); coherency_phys_base = res.start; /* * Ensure secondary CPUs will see the updated value, * which they read before they join the coherency * fabric, and therefore before they are coherent with * the boot CPU cache. */ sync_cache_w(&coherency_phys_base); coherency_base = of_iomap(np, 0); coherency_cpu_base = of_iomap(np, 1); set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); of_node_put(np); } return 0; }
static int __init msm_rq_stats_init(void) { int ret; /* Bail out if this is not an SMP Target */ if (!is_smp()) { rq_info.init = 0; return -ENOSYS; } rq_wq = create_singlethread_workqueue("rq_stats"); BUG_ON(!rq_wq); INIT_WORK(&rq_info.def_timer_work, def_work_fn); spin_lock_init(&rq_lock); rq_info.rq_poll_jiffies = DEFAULT_RQ_POLL_JIFFIES; rq_info.def_timer_jiffies = DEFAULT_DEF_TIMER_JIFFIES; rq_info.rq_poll_last_jiffy = 0; rq_info.def_timer_last_jiffy = 0; ret = init_rq_attribs(); rq_info.init = 1; return ret; }
static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu; bool entered_lp2 = false; if (tegra_pending_sgi()) ACCESS_ONCE_RW(abort_flag) = true; cpuidle_coupled_parallel_barrier(dev, &abort_barrier); if (abort_flag) { cpuidle_coupled_parallel_barrier(dev, &abort_barrier); abort_flag = false; /* clean flag for next coming */ return -EINTR; } local_fiq_disable(); tegra_set_cpu_in_lp2(cpu); cpu_pm_enter(); if (cpu == 0) entered_lp2 = tegra20_cpu_cluster_power_down(dev, drv, index); else entered_lp2 = tegra20_idle_enter_lp2_cpu_1(dev, drv, index); cpu_pm_exit(); tegra_clear_cpu_in_lp2(cpu); local_fiq_enable(); smp_rmb(); return entered_lp2 ? index : 0; }
static void __init twd_local_timer_of_register(struct device_node *np) { int err; if (!is_smp() || !setup_max_cpus) return; twd_ppi = irq_of_parse_and_map(np, 0); if (!twd_ppi) { err = -EINVAL; goto out; } twd_base = of_iomap(np, 0); if (!twd_base) { err = -ENOMEM; goto out; } err = twd_local_timer_common_register(np); out: WARN(err, "twd_local_timer_of_register failed (%d)\n", err); }
static int __init bl_idle_driver_init(struct cpuidle_driver *drv, int cpu_id) { struct cpuinfo_arm *cpu_info; struct cpumask *cpumask; unsigned long cpuid; int cpu; cpumask = kzalloc(cpumask_size(), GFP_KERNEL); if (!cpumask) return -ENOMEM; for_each_possible_cpu(cpu) { cpu_info = &per_cpu(cpu_data, cpu); cpuid = is_smp() ? cpu_info->cpuid : read_cpuid_id(); /* read cpu id part number */ if ((cpuid & 0xFFF0) == cpu_id) cpumask_set_cpu(cpu, cpumask); } drv->cpumask = cpumask; return 0; }
/* * arm_dt_init_cpu_maps - Function retrieves cpu nodes from the device tree * and builds the cpu logical map array containing MPIDR values related to * logical cpus * * Updates the cpu possible mask with the number of parsed cpu nodes */ void __init arm_dt_init_cpu_maps(void) { /* * Temp logical map is initialized with UINT_MAX values that are * considered invalid logical map entries since the logical map must * contain a list of MPIDR[23:0] values where MPIDR[31:24] must * read as 0. */ struct device_node *cpu, *cpus; u32 i, j, cpuidx = 1; u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0; u32 tmp_map[NR_CPUS] = { [0 ... NR_CPUS-1] = UINT_MAX }; bool bootcpu_valid = false; cpus = of_find_node_by_path("/cpus"); if (!cpus) return; for_each_child_of_node(cpus, cpu) { u32 hwid; pr_debug(" * %s...\n", cpu->full_name); /* * A device tree containing CPU nodes with missing "reg" * properties is considered invalid to build the * cpu_logical_map. */ if (of_property_read_u32(cpu, "reg", &hwid)) { pr_debug(" * %s missing reg property\n", cpu->full_name); return; } /* * 8 MSBs must be set to 0 in the DT since the reg property * defines the MPIDR[23:0]. */ if (hwid & ~MPIDR_HWID_BITMASK) return; /* * Duplicate MPIDRs are a recipe for disaster. * Scan all initialized entries and check for * duplicates. If any is found just bail out. * temp values were initialized to UINT_MAX * to avoid matching valid MPIDR[23:0] values. */ for (j = 0; j < cpuidx; j++) if (WARN(tmp_map[j] == hwid, "Duplicate /cpu reg " "properties in the DT\n")) return; /* * Build a stashed array of MPIDR values. Numbering scheme * requires that if detected the boot CPU must be assigned * logical id 0. Other CPUs get sequential indexes starting * from 1. If a CPU node with a reg property matching the * boot CPU MPIDR is detected, this is recorded so that the * logical map built from DT is validated and can be used * to override the map created in smp_setup_processor_id(). */ if (hwid == mpidr) { i = 0; bootcpu_valid = true; } else { i = cpuidx++; } if (WARN(cpuidx > nr_cpu_ids, "DT /cpu %u nodes greater than " "max cores %u, capping them\n", cpuidx, nr_cpu_ids)) { cpuidx = nr_cpu_ids; break; } tmp_map[i] = hwid; }
/*! 20140104 * cpus device node 자식의 cpu device node의 reg property 값을 가지고 * dtb 유효성 검사 후 __cpu_logical_map 초기화 */ void __init arm_dt_init_cpu_maps(void) { /* * Temp logical map is initialized with UINT_MAX values that are * considered invalid logical map entries since the logical map must * contain a list of MPIDR[23:0] values where MPIDR[31:24] must * read as 0. */ struct device_node *cpu, *cpus; u32 i, j, cpuidx = 1; /*! 20140104 mpidr[23:0] 값 추출 / MPIDR_HWID_BITMASK 0xFFFFFF */ u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0; /*! 20140104 * 0 ~ NR_CPUS(4)-1 까지의 Index에 MPIDR_INVALID(0xFF000000) 을 삽입 * - gcc manual - * To initialize a range of elements to the same value, * write '[FIRST ...LAST] = VALUE'. This is a GNU extension. For example, * ex) int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 }; */ u32 tmp_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID }; bool bootcpu_valid = false; /*! 20140104 cpus device node를 찾음 */ cpus = of_find_node_by_path("/cpus"); if (!cpus) return; /*! 20140104 * cpus { #address-cells = <0x1>; #size-cells = <0x0>; cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a15"; reg = <0x0>; clock-frequency = <0x6b49d200>; }; cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a15"; reg = <0x1>; clock-frequency = <0x6b49d200>; }; ...생략 }; */ /*! 20140104 * parent = cpus / child = cpu (child 는 각 cpus device node의 cpu device node를 나타냄) * of_get_next_child는 parent의 자식에 대한 device node 또는 자식의 sibling들을 반환 * - for_each_child_of_node - * for (child = of_get_next_child(parent, NULL); child != NULL; * child = of_get_next_child(parent, child)) */ for_each_child_of_node(cpus, cpu) { u32 hwid; /*! 20140104 cpu device node의 type이 'cpu'인지 확인 */ if (of_node_cmp(cpu->type, "cpu")) continue; pr_debug(" * %s...\n", cpu->full_name); /* * A device tree containing CPU nodes with missing "reg" * properties is considered invalid to build the * cpu_logical_map. */ /*! 20140104 cpu device node의 reg property의 값을 hwid에 할당 */ if (of_property_read_u32(cpu, "reg", &hwid)) { pr_debug(" * %s missing reg property\n", cpu->full_name); return; } /* * 8 MSBs must be set to 0 in the DT since the reg property * defines the MPIDR[23:0]. */ /*! 20140104 * hwid & ~MPIDR_HWID_BITMASK(0xFF000000) * 상위 8bit가 설정되어 있으면 return */ if (hwid & ~MPIDR_HWID_BITMASK) return; /* * Duplicate MPIDRs are a recipe for disaster. * Scan all initialized entries and check for * duplicates. If any is found just bail out. * temp values were initialized to UINT_MAX * to avoid matching valid MPIDR[23:0] values. */ /*! 20140104 동일한 reg 값이 존재하면 중복됫다고 하고 return */ for (j = 0; j < cpuidx; j++) if (WARN(tmp_map[j] == hwid, "Duplicate /cpu reg " "properties in the DT\n")) return; /* * Build a stashed array of MPIDR values. Numbering scheme * requires that if detected the boot CPU must be assigned * logical id 0. Other CPUs get sequential indexes starting * from 1. If a CPU node with a reg property matching the * boot CPU MPIDR is detected, this is recorded so that the * logical map built from DT is validated and can be used * to override the map created in smp_setup_processor_id(). */ /*! 20140104 hwid == mpidr 과 같으면 booting cpu 보통 첫번째 cpu, i = cpuidx */ if (hwid == mpidr) { i = 0; bootcpu_valid = true; } else { i = cpuidx++; } /*! 20140104 Kernel config 값인 nr_cpu_ids 값보다 cpuidx가 크면 nr_cpu_ids 이상의 cpu값들은 무시됨 */ if (WARN(cpuidx > nr_cpu_ids, "DT /cpu %u nodes greater than " "max cores %u, capping them\n", cpuidx, nr_cpu_ids)) { cpuidx = nr_cpu_ids; break; } tmp_map[i] = hwid; }
// ARM10C 20140215 void __init arm_dt_init_cpu_maps(void) { /* * Temp logical map is initialized with UINT_MAX values that are * considered invalid logical map entries since the logical map must * contain a list of MPIDR[23:0] values where MPIDR[31:24] must * read as 0. */ struct device_node *cpu, *cpus; u32 i, j, cpuidx = 1; // A.R.M: B4.1.106 MPIDR, Multiprocessor Affinity Register, VMSA // T.R.M: 4.3.5 Multiprocessor Affinity Register // MPIDR_HWID_BITMASK: 0xFFFFFF // mpidr: CPU ID를 가리킴 u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0; // mpidr 값은 0 // NR_CPUS: 4, MPIDR_INVALID: 0xFF000000 u32 tmp_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID }; bool bootcpu_valid = false; cpus = of_find_node_by_path("/cpus"); // cpus: cpus의tree의주소값 if (!cpus) return; // for_each_child_of_node(cpus, cpu) // for (cpu = of_get_next_child(cpus, NULL); cpu != NULL; // cpu = of_get_next_child(cpus, cpu)) for_each_child_of_node(cpus, cpu) { // [0] cpu: cpu0의 node의 주소값 u32 hwid; // cpu->type: "cpu", "cpu" if (of_node_cmp(cpu->type, "cpu")) continue; // cpu->full_name: "/cpus/cpu@0" pr_debug(" * %s...\n", cpu->full_name); /* * A device tree containing CPU nodes with missing "reg" * properties is considered invalid to build the * cpu_logical_map. */ // [0] cpu: cpu0의 node의 주소값, "reg", &hwid if (of_property_read_u32(cpu, "reg", &hwid)) { pr_debug(" * %s missing reg property\n", cpu->full_name); return; } // hwid: 0 /* * 8 MSBs must be set to 0 in the DT since the reg property * defines the MPIDR[23:0]. */ // ~MPIDR_HWID_BITMASK: 0xFF000000 if (hwid & ~MPIDR_HWID_BITMASK) return; /* * Duplicate MPIDRs are a recipe for disaster. * Scan all initialized entries and check for * duplicates. If any is found just bail out. * temp values were initialized to UINT_MAX * to avoid matching valid MPIDR[23:0] values. */ // cpuidx: 1 for (j = 0; j < cpuidx; j++) // tmp_map[0]: 0xFF000000, hwid: 0 if (WARN(tmp_map[j] == hwid, "Duplicate /cpu reg " "properties in the DT\n")) return; /* * Build a stashed array of MPIDR values. Numbering scheme * requires that if detected the boot CPU must be assigned * logical id 0. Other CPUs get sequential indexes starting * from 1. If a CPU node with a reg property matching the * boot CPU MPIDR is detected, this is recorded so that the * logical map built from DT is validated and can be used * to override the map created in smp_setup_processor_id(). */ // hwid: 0, mpidr: 0 if (hwid == mpidr) { i = 0; bootcpu_valid = true; } else { i = cpuidx++; } // cpuidx: 1, nr_cpu_ids: 4 if (WARN(cpuidx > nr_cpu_ids, "DT /cpu %u nodes greater than " "max cores %u, capping them\n", cpuidx, nr_cpu_ids)) { cpuidx = nr_cpu_ids; break; } // i:0 hwid: 0 tmp_map[i] = hwid; // tmp_map[0]: 0 }