1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2acf7d768SBenjamin Herrenschmidt /*
3acf7d768SBenjamin Herrenschmidt  * cbe_regs.c
4acf7d768SBenjamin Herrenschmidt  *
5acf7d768SBenjamin Herrenschmidt  * Accessor routines for the various MMIO register blocks of the CBE
6acf7d768SBenjamin Herrenschmidt  *
7acf7d768SBenjamin Herrenschmidt  * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
8acf7d768SBenjamin Herrenschmidt  */
9acf7d768SBenjamin Herrenschmidt 
10acf7d768SBenjamin Herrenschmidt #include <linux/percpu.h>
11acf7d768SBenjamin Herrenschmidt #include <linux/types.h>
124b16f8e2SPaul Gortmaker #include <linux/export.h>
13*81d7cac4SRob Herring #include <linux/of.h>
14e6f6390aSChristophe Leroy #include <linux/of_address.h>
1565fddcfcSMike Rapoport #include <linux/pgtable.h>
16acf7d768SBenjamin Herrenschmidt 
17acf7d768SBenjamin Herrenschmidt #include <asm/io.h>
18acf7d768SBenjamin Herrenschmidt #include <asm/ptrace.h>
19eef686a0SBenjamin Herrenschmidt #include <asm/cell-regs.h>
20acf7d768SBenjamin Herrenschmidt 
21acf7d768SBenjamin Herrenschmidt /*
22acf7d768SBenjamin Herrenschmidt  * Current implementation uses "cpu" nodes. We build our own mapping
23acf7d768SBenjamin Herrenschmidt  * array of cpu numbers to cpu nodes locally for now to allow interrupt
24acf7d768SBenjamin Herrenschmidt  * time code to have a fast path rather than call of_get_cpu_node(). If
251fd02f66SJulia Lawall  * we implement cpu hotplug, we'll have to install an appropriate notifier
26acf7d768SBenjamin Herrenschmidt  * in order to release references to the cpu going away
27acf7d768SBenjamin Herrenschmidt  */
28acf7d768SBenjamin Herrenschmidt static struct cbe_regs_map
29acf7d768SBenjamin Herrenschmidt {
30acf7d768SBenjamin Herrenschmidt 	struct device_node *cpu_node;
319dd855a7SChristian Krafft 	struct device_node *be_node;
32acf7d768SBenjamin Herrenschmidt 	struct cbe_pmd_regs __iomem *pmd_regs;
33acf7d768SBenjamin Herrenschmidt 	struct cbe_iic_regs __iomem *iic_regs;
3422b8c9f5SDavid Erb 	struct cbe_mic_tm_regs __iomem *mic_tm_regs;
35bffd4927SKevin Corry 	struct cbe_pmd_shadow_regs pmd_shadow_regs;
36acf7d768SBenjamin Herrenschmidt } cbe_regs_maps[MAX_CBE];
37acf7d768SBenjamin Herrenschmidt static int cbe_regs_map_count;
38acf7d768SBenjamin Herrenschmidt 
39acf7d768SBenjamin Herrenschmidt static struct cbe_thread_map
40acf7d768SBenjamin Herrenschmidt {
41acf7d768SBenjamin Herrenschmidt 	struct device_node *cpu_node;
429dd855a7SChristian Krafft 	struct device_node *be_node;
43acf7d768SBenjamin Herrenschmidt 	struct cbe_regs_map *regs;
4491a69c96SChristian Krafft 	unsigned int thread_id;
4591a69c96SChristian Krafft 	unsigned int cbe_id;
46acf7d768SBenjamin Herrenschmidt } cbe_thread_map[NR_CPUS];
47acf7d768SBenjamin Herrenschmidt 
48104699c0SKOSAKI Motohiro static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = {CPU_BITS_NONE} };
49104699c0SKOSAKI Motohiro static cpumask_t cbe_first_online_cpu = { CPU_BITS_NONE };
5091a69c96SChristian Krafft 
cbe_find_map(struct device_node * np)51acf7d768SBenjamin Herrenschmidt static struct cbe_regs_map *cbe_find_map(struct device_node *np)
52acf7d768SBenjamin Herrenschmidt {
53acf7d768SBenjamin Herrenschmidt 	int i;
5422b8c9f5SDavid Erb 	struct device_node *tmp_np;
5522b8c9f5SDavid Erb 
56e5480bdcSRob Herring 	if (!of_node_is_type(np, "spe")) {
57acf7d768SBenjamin Herrenschmidt 		for (i = 0; i < cbe_regs_map_count; i++)
589dd855a7SChristian Krafft 			if (cbe_regs_maps[i].cpu_node == np ||
599dd855a7SChristian Krafft 			    cbe_regs_maps[i].be_node == np)
60acf7d768SBenjamin Herrenschmidt 				return &cbe_regs_maps[i];
61acf7d768SBenjamin Herrenschmidt 		return NULL;
62acf7d768SBenjamin Herrenschmidt 	}
63acf7d768SBenjamin Herrenschmidt 
649dd855a7SChristian Krafft 	if (np->data)
659dd855a7SChristian Krafft 		return np->data;
669dd855a7SChristian Krafft 
679dd855a7SChristian Krafft 	/* walk up path until cpu or be node was found */
689dd855a7SChristian Krafft 	tmp_np = np;
699dd855a7SChristian Krafft 	do {
709dd855a7SChristian Krafft 		tmp_np = tmp_np->parent;
719dd855a7SChristian Krafft 		/* on a correct devicetree we wont get up to root */
729dd855a7SChristian Krafft 		BUG_ON(!tmp_np);
73e5480bdcSRob Herring 	} while (!of_node_is_type(tmp_np, "cpu") ||
74e5480bdcSRob Herring 		 !of_node_is_type(tmp_np, "be"));
759dd855a7SChristian Krafft 
769dd855a7SChristian Krafft 	np->data = cbe_find_map(tmp_np);
779dd855a7SChristian Krafft 
789dd855a7SChristian Krafft 	return np->data;
799dd855a7SChristian Krafft }
809dd855a7SChristian Krafft 
cbe_get_pmd_regs(struct device_node * np)81acf7d768SBenjamin Herrenschmidt struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np)
82acf7d768SBenjamin Herrenschmidt {
83acf7d768SBenjamin Herrenschmidt 	struct cbe_regs_map *map = cbe_find_map(np);
84acf7d768SBenjamin Herrenschmidt 	if (map == NULL)
85acf7d768SBenjamin Herrenschmidt 		return NULL;
86acf7d768SBenjamin Herrenschmidt 	return map->pmd_regs;
87acf7d768SBenjamin Herrenschmidt }
8822b8c9f5SDavid Erb EXPORT_SYMBOL_GPL(cbe_get_pmd_regs);
89acf7d768SBenjamin Herrenschmidt 
cbe_get_cpu_pmd_regs(int cpu)90acf7d768SBenjamin Herrenschmidt struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu)
91acf7d768SBenjamin Herrenschmidt {
92acf7d768SBenjamin Herrenschmidt 	struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
93acf7d768SBenjamin Herrenschmidt 	if (map == NULL)
94acf7d768SBenjamin Herrenschmidt 		return NULL;
95acf7d768SBenjamin Herrenschmidt 	return map->pmd_regs;
96acf7d768SBenjamin Herrenschmidt }
9722b8c9f5SDavid Erb EXPORT_SYMBOL_GPL(cbe_get_cpu_pmd_regs);
98acf7d768SBenjamin Herrenschmidt 
cbe_get_pmd_shadow_regs(struct device_node * np)99bffd4927SKevin Corry struct cbe_pmd_shadow_regs *cbe_get_pmd_shadow_regs(struct device_node *np)
100bffd4927SKevin Corry {
101bffd4927SKevin Corry 	struct cbe_regs_map *map = cbe_find_map(np);
102bffd4927SKevin Corry 	if (map == NULL)
103bffd4927SKevin Corry 		return NULL;
104bffd4927SKevin Corry 	return &map->pmd_shadow_regs;
105bffd4927SKevin Corry }
106bffd4927SKevin Corry 
cbe_get_cpu_pmd_shadow_regs(int cpu)107bffd4927SKevin Corry struct cbe_pmd_shadow_regs *cbe_get_cpu_pmd_shadow_regs(int cpu)
108bffd4927SKevin Corry {
109bffd4927SKevin Corry 	struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
110bffd4927SKevin Corry 	if (map == NULL)
111bffd4927SKevin Corry 		return NULL;
112bffd4927SKevin Corry 	return &map->pmd_shadow_regs;
113bffd4927SKevin Corry }
114bffd4927SKevin Corry 
cbe_get_iic_regs(struct device_node * np)115acf7d768SBenjamin Herrenschmidt struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np)
116acf7d768SBenjamin Herrenschmidt {
117acf7d768SBenjamin Herrenschmidt 	struct cbe_regs_map *map = cbe_find_map(np);
118acf7d768SBenjamin Herrenschmidt 	if (map == NULL)
119acf7d768SBenjamin Herrenschmidt 		return NULL;
120acf7d768SBenjamin Herrenschmidt 	return map->iic_regs;
121acf7d768SBenjamin Herrenschmidt }
12222b8c9f5SDavid Erb 
cbe_get_cpu_iic_regs(int cpu)123acf7d768SBenjamin Herrenschmidt struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu)
124acf7d768SBenjamin Herrenschmidt {
125acf7d768SBenjamin Herrenschmidt 	struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
126acf7d768SBenjamin Herrenschmidt 	if (map == NULL)
127acf7d768SBenjamin Herrenschmidt 		return NULL;
128acf7d768SBenjamin Herrenschmidt 	return map->iic_regs;
129acf7d768SBenjamin Herrenschmidt }
130acf7d768SBenjamin Herrenschmidt 
cbe_get_mic_tm_regs(struct device_node * np)13122b8c9f5SDavid Erb struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np)
13222b8c9f5SDavid Erb {
13322b8c9f5SDavid Erb 	struct cbe_regs_map *map = cbe_find_map(np);
13422b8c9f5SDavid Erb 	if (map == NULL)
13522b8c9f5SDavid Erb 		return NULL;
13622b8c9f5SDavid Erb 	return map->mic_tm_regs;
13722b8c9f5SDavid Erb }
13822b8c9f5SDavid Erb 
cbe_get_cpu_mic_tm_regs(int cpu)13922b8c9f5SDavid Erb struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu)
14022b8c9f5SDavid Erb {
14122b8c9f5SDavid Erb 	struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
14222b8c9f5SDavid Erb 	if (map == NULL)
14322b8c9f5SDavid Erb 		return NULL;
14422b8c9f5SDavid Erb 	return map->mic_tm_regs;
14522b8c9f5SDavid Erb }
14622b8c9f5SDavid Erb EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs);
14722b8c9f5SDavid Erb 
cbe_get_hw_thread_id(int cpu)14818f2190dSMaynard Johnson u32 cbe_get_hw_thread_id(int cpu)
14918f2190dSMaynard Johnson {
15091a69c96SChristian Krafft 	return cbe_thread_map[cpu].thread_id;
15118f2190dSMaynard Johnson }
15218f2190dSMaynard Johnson EXPORT_SYMBOL_GPL(cbe_get_hw_thread_id);
15322b8c9f5SDavid Erb 
cbe_cpu_to_node(int cpu)15491a69c96SChristian Krafft u32 cbe_cpu_to_node(int cpu)
15591a69c96SChristian Krafft {
15691a69c96SChristian Krafft 	return cbe_thread_map[cpu].cbe_id;
15791a69c96SChristian Krafft }
15891a69c96SChristian Krafft EXPORT_SYMBOL_GPL(cbe_cpu_to_node);
15991a69c96SChristian Krafft 
cbe_node_to_cpu(int node)16091a69c96SChristian Krafft u32 cbe_node_to_cpu(int node)
16191a69c96SChristian Krafft {
162104699c0SKOSAKI Motohiro 	return cpumask_first(&cbe_local_mask[node]);
163104699c0SKOSAKI Motohiro 
16491a69c96SChristian Krafft }
16591a69c96SChristian Krafft EXPORT_SYMBOL_GPL(cbe_node_to_cpu);
16691a69c96SChristian Krafft 
cbe_get_be_node(int cpu_id)1677c1ab16bSNick Child static struct device_node *__init cbe_get_be_node(int cpu_id)
1689dd855a7SChristian Krafft {
1699dd855a7SChristian Krafft 	struct device_node *np;
1709dd855a7SChristian Krafft 
1719dd855a7SChristian Krafft 	for_each_node_by_type (np, "be") {
1729dd855a7SChristian Krafft 		int len,i;
1739dd855a7SChristian Krafft 		const phandle *cpu_handle;
1749dd855a7SChristian Krafft 
1759dd855a7SChristian Krafft 		cpu_handle = of_get_property(np, "cpus", &len);
1769dd855a7SChristian Krafft 
177b86ce01cSJean-Christophe DUBOIS 		/*
178b86ce01cSJean-Christophe DUBOIS 		 * the CAB SLOF tree is non compliant, so we just assume
179b86ce01cSJean-Christophe DUBOIS 		 * there is only one node
180b86ce01cSJean-Christophe DUBOIS 		 */
181b86ce01cSJean-Christophe DUBOIS 		if (WARN_ON_ONCE(!cpu_handle))
182b86ce01cSJean-Christophe DUBOIS 			return np;
183b86ce01cSJean-Christophe DUBOIS 
184ad4b3236SLiang He 		for (i = 0; i < len; i++) {
185ad4b3236SLiang He 			struct device_node *ch_np = of_find_node_by_phandle(cpu_handle[i]);
186ad4b3236SLiang He 			struct device_node *ci_np = of_get_cpu_node(cpu_id, NULL);
187ad4b3236SLiang He 
188ad4b3236SLiang He 			of_node_put(ch_np);
189ad4b3236SLiang He 			of_node_put(ci_np);
190ad4b3236SLiang He 
191ad4b3236SLiang He 			if (ch_np == ci_np)
1929dd855a7SChristian Krafft 				return np;
1939dd855a7SChristian Krafft 		}
194ad4b3236SLiang He 	}
1959dd855a7SChristian Krafft 
1969dd855a7SChristian Krafft 	return NULL;
1979dd855a7SChristian Krafft }
1989dd855a7SChristian Krafft 
cbe_fill_regs_map(struct cbe_regs_map * map)1997c98bd72SDaniel Axtens static void __init cbe_fill_regs_map(struct cbe_regs_map *map)
2009dd855a7SChristian Krafft {
2019dd855a7SChristian Krafft 	if(map->be_node) {
202ad4b3236SLiang He 		struct device_node *be, *np, *parent_np;
2039dd855a7SChristian Krafft 
2049dd855a7SChristian Krafft 		be = map->be_node;
2059dd855a7SChristian Krafft 
206ad4b3236SLiang He 		for_each_node_by_type(np, "pervasive") {
207ad4b3236SLiang He 			parent_np = of_get_parent(np);
208ad4b3236SLiang He 			if (parent_np == be)
2099dd855a7SChristian Krafft 				map->pmd_regs = of_iomap(np, 0);
210ad4b3236SLiang He 			of_node_put(parent_np);
211ad4b3236SLiang He 		}
2129dd855a7SChristian Krafft 
213ad4b3236SLiang He 		for_each_node_by_type(np, "CBEA-Internal-Interrupt-Controller") {
214ad4b3236SLiang He 			parent_np = of_get_parent(np);
215ad4b3236SLiang He 			if (parent_np == be)
2169dd855a7SChristian Krafft 				map->iic_regs = of_iomap(np, 2);
217ad4b3236SLiang He 			of_node_put(parent_np);
218ad4b3236SLiang He 		}
2199dd855a7SChristian Krafft 
220ad4b3236SLiang He 		for_each_node_by_type(np, "mic-tm") {
221ad4b3236SLiang He 			parent_np = of_get_parent(np);
222ad4b3236SLiang He 			if (parent_np == be)
2239dd855a7SChristian Krafft 				map->mic_tm_regs = of_iomap(np, 0);
224ad4b3236SLiang He 			of_node_put(parent_np);
225ad4b3236SLiang He 		}
2269dd855a7SChristian Krafft 	} else {
2279dd855a7SChristian Krafft 		struct device_node *cpu;
2289dd855a7SChristian Krafft 		/* That hack must die die die ! */
2299dd855a7SChristian Krafft 		const struct address_prop {
2309dd855a7SChristian Krafft 			unsigned long address;
2319dd855a7SChristian Krafft 			unsigned int len;
2329dd855a7SChristian Krafft 		} __attribute__((packed)) *prop;
2339dd855a7SChristian Krafft 
2349dd855a7SChristian Krafft 		cpu = map->cpu_node;
2359dd855a7SChristian Krafft 
2369dd855a7SChristian Krafft 		prop = of_get_property(cpu, "pervasive", NULL);
2379dd855a7SChristian Krafft 		if (prop != NULL)
2389dd855a7SChristian Krafft 			map->pmd_regs = ioremap(prop->address, prop->len);
2399dd855a7SChristian Krafft 
2409dd855a7SChristian Krafft 		prop = of_get_property(cpu, "iic", NULL);
2419dd855a7SChristian Krafft 		if (prop != NULL)
2429dd855a7SChristian Krafft 			map->iic_regs = ioremap(prop->address, prop->len);
2439dd855a7SChristian Krafft 
2449dd855a7SChristian Krafft 		prop = of_get_property(cpu, "mic-tm", NULL);
2459dd855a7SChristian Krafft 		if (prop != NULL)
2469dd855a7SChristian Krafft 			map->mic_tm_regs = ioremap(prop->address, prop->len);
2479dd855a7SChristian Krafft 	}
2489dd855a7SChristian Krafft }
2499dd855a7SChristian Krafft 
2509dd855a7SChristian Krafft 
cbe_regs_init(void)251acf7d768SBenjamin Herrenschmidt void __init cbe_regs_init(void)
252acf7d768SBenjamin Herrenschmidt {
253acf7d768SBenjamin Herrenschmidt 	int i;
25491a69c96SChristian Krafft 	unsigned int thread_id;
255acf7d768SBenjamin Herrenschmidt 	struct device_node *cpu;
256acf7d768SBenjamin Herrenschmidt 
257acf7d768SBenjamin Herrenschmidt 	/* Build local fast map of CPUs */
25891a69c96SChristian Krafft 	for_each_possible_cpu(i) {
25991a69c96SChristian Krafft 		cbe_thread_map[i].cpu_node = of_get_cpu_node(i, &thread_id);
2609dd855a7SChristian Krafft 		cbe_thread_map[i].be_node = cbe_get_be_node(i);
26191a69c96SChristian Krafft 		cbe_thread_map[i].thread_id = thread_id;
26291a69c96SChristian Krafft 	}
263acf7d768SBenjamin Herrenschmidt 
264acf7d768SBenjamin Herrenschmidt 	/* Find maps for each device tree CPU */
265acf7d768SBenjamin Herrenschmidt 	for_each_node_by_type(cpu, "cpu") {
26691a69c96SChristian Krafft 		struct cbe_regs_map *map;
26791a69c96SChristian Krafft 		unsigned int cbe_id;
268acf7d768SBenjamin Herrenschmidt 
26991a69c96SChristian Krafft 		cbe_id = cbe_regs_map_count++;
27091a69c96SChristian Krafft 		map = &cbe_regs_maps[cbe_id];
271acf7d768SBenjamin Herrenschmidt 
272acf7d768SBenjamin Herrenschmidt 		if (cbe_regs_map_count > MAX_CBE) {
273acf7d768SBenjamin Herrenschmidt 			printk(KERN_ERR "cbe_regs: More BE chips than supported"
274acf7d768SBenjamin Herrenschmidt 			       "!\n");
275acf7d768SBenjamin Herrenschmidt 			cbe_regs_map_count--;
2761fe58a87SJulia Lawall 			of_node_put(cpu);
277acf7d768SBenjamin Herrenschmidt 			return;
278acf7d768SBenjamin Herrenschmidt 		}
279ad4b3236SLiang He 		of_node_put(map->cpu_node);
280ad4b3236SLiang He 		map->cpu_node = of_node_get(cpu);
28191a69c96SChristian Krafft 
28291a69c96SChristian Krafft 		for_each_possible_cpu(i) {
28391a69c96SChristian Krafft 			struct cbe_thread_map *thread = &cbe_thread_map[i];
28491a69c96SChristian Krafft 
28591a69c96SChristian Krafft 			if (thread->cpu_node == cpu) {
28691a69c96SChristian Krafft 				thread->regs = map;
28791a69c96SChristian Krafft 				thread->cbe_id = cbe_id;
2889dd855a7SChristian Krafft 				map->be_node = thread->be_node;
289104699c0SKOSAKI Motohiro 				cpumask_set_cpu(i, &cbe_local_mask[cbe_id]);
29091a69c96SChristian Krafft 				if(thread->thread_id == 0)
291104699c0SKOSAKI Motohiro 					cpumask_set_cpu(i, &cbe_first_online_cpu);
29291a69c96SChristian Krafft 			}
29391a69c96SChristian Krafft 		}
294acf7d768SBenjamin Herrenschmidt 
2959dd855a7SChristian Krafft 		cbe_fill_regs_map(map);
296acf7d768SBenjamin Herrenschmidt 	}
297acf7d768SBenjamin Herrenschmidt }
298acf7d768SBenjamin Herrenschmidt 
299