1 /*
2  * Copyright(c) 2015 EZchip Technologies.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * The full GNU General Public License is included in this distribution in
14  * the file called "COPYING".
15  */
16 
17 #include <linux/smp.h>
18 #include <linux/init.h>
19 #include <linux/kernel.h>
20 #include <linux/io.h>
21 #include <linux/log2.h>
22 #include <asm/arcregs.h>
23 #include <plat/mtm.h>
24 #include <plat/smp.h>
25 
26 #define MT_HS_CNT_MIN		0x01
27 #define MT_HS_CNT_MAX		0xFF
28 #define MT_CTRL_ST_CNT		0xF
29 #define NPS_NUM_HW_THREADS	0x10
30 
31 static int mtm_hs_ctr = MT_HS_CNT_MAX;
32 
33 #ifdef CONFIG_EZNPS_MEM_ERROR_ALIGN
do_memory_error(unsigned long address,struct pt_regs * regs)34 int do_memory_error(unsigned long address, struct pt_regs *regs)
35 {
36 	die("Invalid Mem Access", regs, address);
37 
38 	return 1;
39 }
40 #endif
41 
mtm_init_nat(int cpu)42 static void mtm_init_nat(int cpu)
43 {
44 	struct nps_host_reg_mtm_cfg mtm_cfg;
45 	struct nps_host_reg_aux_udmc udmc;
46 	int log_nat, nat = 0, i, t;
47 
48 	/* Iterate core threads and update nat */
49 	for (i = 0, t = cpu; i < NPS_NUM_HW_THREADS; i++, t++)
50 		nat += test_bit(t, cpumask_bits(cpu_possible_mask));
51 
52 	log_nat = ilog2(nat);
53 
54 	udmc.value = read_aux_reg(CTOP_AUX_UDMC);
55 	udmc.nat = log_nat;
56 	write_aux_reg(CTOP_AUX_UDMC, udmc.value);
57 
58 	mtm_cfg.value = ioread32be(MTM_CFG(cpu));
59 	mtm_cfg.nat = log_nat;
60 	iowrite32be(mtm_cfg.value, MTM_CFG(cpu));
61 }
62 
mtm_init_thread(int cpu)63 static void mtm_init_thread(int cpu)
64 {
65 	int i, tries = 5;
66 	struct nps_host_reg_thr_init thr_init;
67 	struct nps_host_reg_thr_init_sts thr_init_sts;
68 
69 	/* Set thread init register */
70 	thr_init.value = 0;
71 	iowrite32be(thr_init.value, MTM_THR_INIT(cpu));
72 	thr_init.thr_id = NPS_CPU_TO_THREAD_NUM(cpu);
73 	thr_init.str = 1;
74 	iowrite32be(thr_init.value, MTM_THR_INIT(cpu));
75 
76 	/* Poll till thread init is done */
77 	for (i = 0; i < tries; i++) {
78 		thr_init_sts.value = ioread32be(MTM_THR_INIT_STS(cpu));
79 		if (thr_init_sts.thr_id == thr_init.thr_id) {
80 			if (thr_init_sts.bsy)
81 				continue;
82 			else if (thr_init_sts.err)
83 				pr_warn("Failed to thread init cpu %u\n", cpu);
84 			break;
85 		}
86 
87 		pr_warn("Wrong thread id in thread init for cpu %u\n", cpu);
88 		break;
89 	}
90 
91 	if (i == tries)
92 		pr_warn("Got thread init timeout for cpu %u\n", cpu);
93 }
94 
mtm_enable_thread(int cpu)95 int mtm_enable_thread(int cpu)
96 {
97 	struct nps_host_reg_mtm_cfg mtm_cfg;
98 
99 	if (NPS_CPU_TO_THREAD_NUM(cpu) == 0)
100 		return 1;
101 
102 	/* Enable thread in mtm */
103 	mtm_cfg.value = ioread32be(MTM_CFG(cpu));
104 	mtm_cfg.ten |= (1 << (NPS_CPU_TO_THREAD_NUM(cpu)));
105 	iowrite32be(mtm_cfg.value, MTM_CFG(cpu));
106 
107 	return 0;
108 }
109 
mtm_enable_core(unsigned int cpu)110 void mtm_enable_core(unsigned int cpu)
111 {
112 	int i;
113 	struct nps_host_reg_aux_mt_ctrl mt_ctrl;
114 	struct nps_host_reg_mtm_cfg mtm_cfg;
115 	struct nps_host_reg_aux_dpc dpc;
116 
117 	/*
118 	 * Initializing dpc register in each CPU.
119 	 * Overwriting the init value of the DPC
120 	 * register so that CMEM and FMT virtual address
121 	 * spaces are accessible, and Data Plane HW
122 	 * facilities are enabled.
123 	 */
124 	dpc.ien = 1;
125 	dpc.men = 1;
126 	write_aux_reg(CTOP_AUX_DPC, dpc.value);
127 
128 	if (NPS_CPU_TO_THREAD_NUM(cpu) != 0)
129 		return;
130 
131 	/* Initialize Number of Active Threads */
132 	mtm_init_nat(cpu);
133 
134 	/* Initialize mtm_cfg */
135 	mtm_cfg.value = ioread32be(MTM_CFG(cpu));
136 	mtm_cfg.ten = 1;
137 	iowrite32be(mtm_cfg.value, MTM_CFG(cpu));
138 
139 	/* Initialize all other threads in core */
140 	for (i = 1; i < NPS_NUM_HW_THREADS; i++)
141 		mtm_init_thread(cpu + i);
142 
143 
144 	/* Enable HW schedule, stall counter, mtm */
145 	mt_ctrl.value = 0;
146 	mt_ctrl.hsen = 1;
147 	mt_ctrl.hs_cnt = mtm_hs_ctr;
148 	mt_ctrl.mten = 1;
149 	write_aux_reg(CTOP_AUX_MT_CTRL, mt_ctrl.value);
150 
151 	/*
152 	 * HW scheduling mechanism will start working
153 	 * Only after call to instruction "schd.rw".
154 	 * cpu_relax() calls "schd.rw" instruction.
155 	 */
156 	cpu_relax();
157 }
158 
159 /* Verify and set the value of the mtm hs counter */
set_mtm_hs_ctr(char * ctr_str)160 static int __init set_mtm_hs_ctr(char *ctr_str)
161 {
162 	int hs_ctr;
163 	int ret;
164 
165 	ret = kstrtoint(ctr_str, 0, &hs_ctr);
166 
167 	if (ret || hs_ctr > MT_HS_CNT_MAX || hs_ctr < MT_HS_CNT_MIN) {
168 		pr_err("** Invalid @nps_mtm_hs_ctr [%d] needs to be [%d:%d] (incl)\n",
169 		       hs_ctr, MT_HS_CNT_MIN, MT_HS_CNT_MAX);
170 		return -EINVAL;
171 	}
172 
173 	mtm_hs_ctr = hs_ctr;
174 
175 	return 0;
176 }
177 early_param("nps_mtm_hs_ctr", set_mtm_hs_ctr);
178