167 lines
3.8 KiB
C
167 lines
3.8 KiB
C
|
// SPDX-License-Identifier: GPL-2.0-only
|
||
|
/*
|
||
|
* Copyright(c) 2015 EZchip Technologies.
|
||
|
*/
|
||
|
|
||
|
#include <linux/smp.h>
|
||
|
#include <linux/init.h>
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/io.h>
|
||
|
#include <linux/log2.h>
|
||
|
#include <asm/arcregs.h>
|
||
|
#include <plat/mtm.h>
|
||
|
#include <plat/smp.h>
|
||
|
|
||
|
#define MT_HS_CNT_MIN 0x01
|
||
|
#define MT_HS_CNT_MAX 0xFF
|
||
|
#define MT_CTRL_ST_CNT 0xF
|
||
|
#define NPS_NUM_HW_THREADS 0x10
|
||
|
|
||
|
static int mtm_hs_ctr = MT_HS_CNT_MAX;
|
||
|
|
||
|
#ifdef CONFIG_EZNPS_MEM_ERROR_ALIGN
|
||
|
int do_memory_error(unsigned long address, struct pt_regs *regs)
|
||
|
{
|
||
|
die("Invalid Mem Access", regs, address);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void mtm_init_nat(int cpu)
|
||
|
{
|
||
|
struct nps_host_reg_mtm_cfg mtm_cfg;
|
||
|
struct nps_host_reg_aux_udmc udmc;
|
||
|
int log_nat, nat = 0, i, t;
|
||
|
|
||
|
/* Iterate core threads and update nat */
|
||
|
for (i = 0, t = cpu; i < NPS_NUM_HW_THREADS; i++, t++)
|
||
|
nat += test_bit(t, cpumask_bits(cpu_possible_mask));
|
||
|
|
||
|
log_nat = ilog2(nat);
|
||
|
|
||
|
udmc.value = read_aux_reg(CTOP_AUX_UDMC);
|
||
|
udmc.nat = log_nat;
|
||
|
write_aux_reg(CTOP_AUX_UDMC, udmc.value);
|
||
|
|
||
|
mtm_cfg.value = ioread32be(MTM_CFG(cpu));
|
||
|
mtm_cfg.nat = log_nat;
|
||
|
iowrite32be(mtm_cfg.value, MTM_CFG(cpu));
|
||
|
}
|
||
|
|
||
|
static void mtm_init_thread(int cpu)
|
||
|
{
|
||
|
int i, tries = 5;
|
||
|
struct nps_host_reg_thr_init thr_init;
|
||
|
struct nps_host_reg_thr_init_sts thr_init_sts;
|
||
|
|
||
|
/* Set thread init register */
|
||
|
thr_init.value = 0;
|
||
|
iowrite32be(thr_init.value, MTM_THR_INIT(cpu));
|
||
|
thr_init.thr_id = NPS_CPU_TO_THREAD_NUM(cpu);
|
||
|
thr_init.str = 1;
|
||
|
iowrite32be(thr_init.value, MTM_THR_INIT(cpu));
|
||
|
|
||
|
/* Poll till thread init is done */
|
||
|
for (i = 0; i < tries; i++) {
|
||
|
thr_init_sts.value = ioread32be(MTM_THR_INIT_STS(cpu));
|
||
|
if (thr_init_sts.thr_id == thr_init.thr_id) {
|
||
|
if (thr_init_sts.bsy)
|
||
|
continue;
|
||
|
else if (thr_init_sts.err)
|
||
|
pr_warn("Failed to thread init cpu %u\n", cpu);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pr_warn("Wrong thread id in thread init for cpu %u\n", cpu);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (i == tries)
|
||
|
pr_warn("Got thread init timeout for cpu %u\n", cpu);
|
||
|
}
|
||
|
|
||
|
int mtm_enable_thread(int cpu)
|
||
|
{
|
||
|
struct nps_host_reg_mtm_cfg mtm_cfg;
|
||
|
|
||
|
if (NPS_CPU_TO_THREAD_NUM(cpu) == 0)
|
||
|
return 1;
|
||
|
|
||
|
/* Enable thread in mtm */
|
||
|
mtm_cfg.value = ioread32be(MTM_CFG(cpu));
|
||
|
mtm_cfg.ten |= (1 << (NPS_CPU_TO_THREAD_NUM(cpu)));
|
||
|
iowrite32be(mtm_cfg.value, MTM_CFG(cpu));
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void mtm_enable_core(unsigned int cpu)
|
||
|
{
|
||
|
int i;
|
||
|
struct nps_host_reg_aux_mt_ctrl mt_ctrl;
|
||
|
struct nps_host_reg_mtm_cfg mtm_cfg;
|
||
|
struct nps_host_reg_aux_dpc dpc;
|
||
|
|
||
|
/*
|
||
|
* Initializing dpc register in each CPU.
|
||
|
* Overwriting the init value of the DPC
|
||
|
* register so that CMEM and FMT virtual address
|
||
|
* spaces are accessible, and Data Plane HW
|
||
|
* facilities are enabled.
|
||
|
*/
|
||
|
dpc.ien = 1;
|
||
|
dpc.men = 1;
|
||
|
write_aux_reg(CTOP_AUX_DPC, dpc.value);
|
||
|
|
||
|
if (NPS_CPU_TO_THREAD_NUM(cpu) != 0)
|
||
|
return;
|
||
|
|
||
|
/* Initialize Number of Active Threads */
|
||
|
mtm_init_nat(cpu);
|
||
|
|
||
|
/* Initialize mtm_cfg */
|
||
|
mtm_cfg.value = ioread32be(MTM_CFG(cpu));
|
||
|
mtm_cfg.ten = 1;
|
||
|
iowrite32be(mtm_cfg.value, MTM_CFG(cpu));
|
||
|
|
||
|
/* Initialize all other threads in core */
|
||
|
for (i = 1; i < NPS_NUM_HW_THREADS; i++)
|
||
|
mtm_init_thread(cpu + i);
|
||
|
|
||
|
|
||
|
/* Enable HW schedule, stall counter, mtm */
|
||
|
mt_ctrl.value = 0;
|
||
|
mt_ctrl.hsen = 1;
|
||
|
mt_ctrl.hs_cnt = mtm_hs_ctr;
|
||
|
mt_ctrl.mten = 1;
|
||
|
write_aux_reg(CTOP_AUX_MT_CTRL, mt_ctrl.value);
|
||
|
|
||
|
/*
|
||
|
* HW scheduling mechanism will start working
|
||
|
* Only after call to instruction "schd.rw".
|
||
|
* cpu_relax() calls "schd.rw" instruction.
|
||
|
*/
|
||
|
cpu_relax();
|
||
|
}
|
||
|
|
||
|
/* Verify and set the value of the mtm hs counter */
|
||
|
static int __init set_mtm_hs_ctr(char *ctr_str)
|
||
|
{
|
||
|
int hs_ctr;
|
||
|
int ret;
|
||
|
|
||
|
ret = kstrtoint(ctr_str, 0, &hs_ctr);
|
||
|
|
||
|
if (ret || hs_ctr > MT_HS_CNT_MAX || hs_ctr < MT_HS_CNT_MIN) {
|
||
|
pr_err("** Invalid @nps_mtm_hs_ctr [%d] needs to be [%d:%d] (incl)\n",
|
||
|
hs_ctr, MT_HS_CNT_MIN, MT_HS_CNT_MAX);
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
mtm_hs_ctr = hs_ctr;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
early_param("nps_mtm_hs_ctr", set_mtm_hs_ctr);
|