예제 #1
0
int __cpuinit twd_clockchip_init(virtual_addr_t base, 
				virtual_addr_t ref_counter_addr,
				u32 ref_counter_freq,
				u32 ppi_hirq)
{
	int rc;
	u32 cpu = vmm_smp_processor_id();
	struct twd_clockchip *cc = &this_cpu(twd_cc);

	memset(cc, 0, sizeof(struct twd_clockchip));

	twd_caliberate_freq(base, ref_counter_addr, ref_counter_freq);

	vmm_sprintf(cc->name, "twd/%d", cpu);

	cc->base = base;
	cc->clkchip.name = cc->name;
	cc->clkchip.hirq = ppi_hirq;
	cc->clkchip.rating = 350;
	cc->clkchip.cpumask = vmm_cpumask_of(cpu);
	cc->clkchip.features = 
		VMM_CLOCKCHIP_FEAT_PERIODIC | VMM_CLOCKCHIP_FEAT_ONESHOT;
	cc->clkchip.shift = 20;
	cc->clkchip.mult = vmm_clockchip_hz2mult(twd_freq_hz, cc->clkchip.shift);
	cc->clkchip.min_delta_ns = vmm_clockchip_delta2ns(0xF, &cc->clkchip);
	cc->clkchip.max_delta_ns = 
			vmm_clockchip_delta2ns(0xFFFFFFFF, &cc->clkchip);
	cc->clkchip.set_mode = &twd_clockchip_set_mode;
	cc->clkchip.set_next_event = &twd_clockchip_set_next_event;
	cc->clkchip.expire = &twd_clockchip_expire;
	cc->clkchip.priv = cc;

	if (!cpu) {
		/* Register interrupt handler */
		if ((rc = vmm_host_irq_register(ppi_hirq, "twd",
						&twd_clockchip_irq_handler, 
						cc))) {
			return rc;
		}

		/* Mark interrupt as per-cpu */
		if ((rc = vmm_host_irq_mark_per_cpu(ppi_hirq))) {
			return rc;
		}
	}

	/* Explicitly enable local timer PPI in GIC 
	 * Note: Local timer requires PPI support hence requires GIC
	 */
	gic_enable_ppi(ppi_hirq);

	return vmm_clockchip_register(&cc->clkchip);
}
예제 #2
0
파일: smp_twd.c 프로젝트: HeidCloud/xvisor
static int __cpuinit twd_clockchip_init(struct vmm_devtree_node *node)
{
	int rc;
	u32 ref_cnt_freq;
	virtual_addr_t ref_cnt_addr;
	u32 cpu = vmm_smp_processor_id();
	struct twd_clockchip *cc = &this_cpu(twd_cc);

	if (!twd_base) {
		rc = vmm_devtree_regmap(node, &twd_base, 0);
		if (rc) {
			goto fail;
		}
	}

	if (!twd_ppi_irq) {
		rc = vmm_devtree_irq_get(node, &twd_ppi_irq, 0);
		if (rc) {
			goto fail_regunmap;
		}
	}

	if (!twd_freq_hz) {
		/* First try to find TWD clock */
		if (!twd_clk) {
			twd_clk = of_clk_get(node, 0);
		}
		if (!twd_clk) {
			twd_clk = clk_get_sys("smp_twd", NULL);
		}

		if (twd_clk) {
			/* Use TWD clock to find frequency */
			rc = clk_prepare_enable(twd_clk);
			if (rc) {
				clk_put(twd_clk);
				goto fail_regunmap;
			}
			twd_freq_hz = clk_get_rate(twd_clk);
		} else {
			/* No TWD clock found hence caliberate */
			rc = vmm_devtree_regmap(node, &ref_cnt_addr, 1);
			if (rc) {
				vmm_devtree_regunmap(node, ref_cnt_addr, 1);
				goto fail_regunmap;
			}
			if (vmm_devtree_read_u32(node, "ref-counter-freq",
						 &ref_cnt_freq)) {
				vmm_devtree_regunmap(node, ref_cnt_addr, 1);
				goto fail_regunmap;
			}
			twd_caliberate_freq(twd_base, 
					ref_cnt_addr, ref_cnt_freq);
			vmm_devtree_regunmap(node, ref_cnt_addr, 1);
		}
	}

	memset(cc, 0, sizeof(struct twd_clockchip));

	vmm_sprintf(cc->name, "twd/%d", cpu);

	cc->clkchip.name = cc->name;
	cc->clkchip.hirq = twd_ppi_irq;
	cc->clkchip.rating = 350;
	cc->clkchip.cpumask = vmm_cpumask_of(cpu);
	cc->clkchip.features = 
		VMM_CLOCKCHIP_FEAT_PERIODIC | VMM_CLOCKCHIP_FEAT_ONESHOT;
	vmm_clocks_calc_mult_shift(&cc->clkchip.mult, &cc->clkchip.shift, 
				   VMM_NSEC_PER_SEC, twd_freq_hz, 10);
	cc->clkchip.min_delta_ns = vmm_clockchip_delta2ns(0xF, &cc->clkchip);
	cc->clkchip.max_delta_ns = 
			vmm_clockchip_delta2ns(0xFFFFFFFF, &cc->clkchip);
	cc->clkchip.set_mode = &twd_clockchip_set_mode;
	cc->clkchip.set_next_event = &twd_clockchip_set_next_event;
	cc->clkchip.priv = cc;

	if (vmm_smp_is_bootcpu()) {
		/* Register interrupt handler */
		if ((rc = vmm_host_irq_register(twd_ppi_irq, "twd",
						&twd_clockchip_irq_handler, 
						cc))) {
			
			goto fail_regunmap;
		}

		/* Mark interrupt as per-cpu */
		if ((rc = vmm_host_irq_mark_per_cpu(twd_ppi_irq))) {
			goto fail_unreg_irq;
		}
	}

	/* Explicitly enable local timer PPI in GIC 
	 * Note: Local timer requires PPI support hence requires GIC
	 */
	gic_enable_ppi(twd_ppi_irq);

	rc = vmm_clockchip_register(&cc->clkchip);
	if (rc) {
		goto fail_unreg_irq;
	}

	return VMM_OK;

fail_unreg_irq:
	if (vmm_smp_is_bootcpu()) {
		vmm_host_irq_unregister(twd_ppi_irq, cc);
	}
fail_regunmap:
	vmm_devtree_regunmap(node, twd_base, 0);
fail:
	return rc;
}
예제 #3
0
파일: smp_twd.c 프로젝트: simonkim/xvisor
int __cpuinit twd_clockchip_init(virtual_addr_t ref_counter_addr,
                                 u32 ref_counter_freq)
{
    int rc;
    u32 cpu = vmm_smp_processor_id();
    struct vmm_devtree_node *node;
    struct twd_clockchip *cc = &this_cpu(twd_cc);

    node = vmm_devtree_find_matching(NULL, twd_match);
    if (!node) {
        return VMM_ENODEV;
    }

    if (!twd_base) {
        rc = vmm_devtree_regmap(node, &twd_base, 0);
        if (rc) {
            return rc;
        }
    }

    if (!twd_ppi_irq) {
        rc = vmm_devtree_irq_get(node, &twd_ppi_irq, 0);
        if (rc) {
            return rc;
        }
    }

    twd_caliberate_freq(twd_base, ref_counter_addr, ref_counter_freq);

    memset(cc, 0, sizeof(struct twd_clockchip));

    vmm_sprintf(cc->name, "twd/%d", cpu);

    cc->clkchip.name = cc->name;
    cc->clkchip.hirq = twd_ppi_irq;
    cc->clkchip.rating = 350;
    cc->clkchip.cpumask = vmm_cpumask_of(cpu);
    cc->clkchip.features =
        VMM_CLOCKCHIP_FEAT_PERIODIC | VMM_CLOCKCHIP_FEAT_ONESHOT;
    vmm_clocks_calc_mult_shift(&cc->clkchip.mult, &cc->clkchip.shift,
                               VMM_NSEC_PER_SEC, twd_freq_hz, 10);
    cc->clkchip.min_delta_ns = vmm_clockchip_delta2ns(0xF, &cc->clkchip);
    cc->clkchip.max_delta_ns =
        vmm_clockchip_delta2ns(0xFFFFFFFF, &cc->clkchip);
    cc->clkchip.set_mode = &twd_clockchip_set_mode;
    cc->clkchip.set_next_event = &twd_clockchip_set_next_event;
    cc->clkchip.priv = cc;

    if (!cpu) {
        /* Register interrupt handler */
        if ((rc = vmm_host_irq_register(twd_ppi_irq, "twd",
                                        &twd_clockchip_irq_handler,
                                        cc))) {
            return rc;
        }

        /* Mark interrupt as per-cpu */
        if ((rc = vmm_host_irq_mark_per_cpu(twd_ppi_irq))) {
            return rc;
        }
    }

    /* Explicitly enable local timer PPI in GIC
     * Note: Local timer requires PPI support hence requires GIC
     */
    gic_enable_ppi(twd_ppi_irq);

    return vmm_clockchip_register(&cc->clkchip);
}