Esempio n. 1
0
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;
}
Esempio n. 2
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;
}
Esempio n. 3
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
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);
 }
Esempio n. 7
0
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;
}
Esempio n. 8
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;
	}
Esempio n. 9
0
/*! 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;
	}
Esempio n. 10
0
// 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 
	}