xref: /linux/arch/powerpc/kernel/sysfs.c (revision a1e0eb104249817e5251bd4aade50921ffcb2159)
1d3d2176aSDavid Gibson #include <linux/sysdev.h>
2d3d2176aSDavid Gibson #include <linux/cpu.h>
3d3d2176aSDavid Gibson #include <linux/smp.h>
4d3d2176aSDavid Gibson #include <linux/percpu.h>
5d3d2176aSDavid Gibson #include <linux/init.h>
6d3d2176aSDavid Gibson #include <linux/sched.h>
7d3d2176aSDavid Gibson #include <linux/module.h>
8d3d2176aSDavid Gibson #include <linux/nodemask.h>
9d3d2176aSDavid Gibson #include <linux/cpumask.h>
10d3d2176aSDavid Gibson #include <linux/notifier.h>
11d3d2176aSDavid Gibson 
12d3d2176aSDavid Gibson #include <asm/current.h>
13d3d2176aSDavid Gibson #include <asm/processor.h>
14d3d2176aSDavid Gibson #include <asm/cputable.h>
15d3d2176aSDavid Gibson #include <asm/firmware.h>
16d3d2176aSDavid Gibson #include <asm/hvcall.h>
17d3d2176aSDavid Gibson #include <asm/prom.h>
18d3d2176aSDavid Gibson #include <asm/machdep.h>
19d3d2176aSDavid Gibson #include <asm/smp.h>
20d3d2176aSDavid Gibson 
21b950bdd0SBenjamin Herrenschmidt #ifdef CONFIG_PPC64
22b950bdd0SBenjamin Herrenschmidt #include <asm/paca.h>
23b950bdd0SBenjamin Herrenschmidt #include <asm/lppaca.h>
24b950bdd0SBenjamin Herrenschmidt #endif
25b950bdd0SBenjamin Herrenschmidt 
26d3d2176aSDavid Gibson static DEFINE_PER_CPU(struct cpu, cpu_devices);
27d3d2176aSDavid Gibson 
28124c27d3SNathan Lynch static DEFINE_PER_CPU(struct kobject *, cache_toplevel);
29124c27d3SNathan Lynch 
30b950bdd0SBenjamin Herrenschmidt /*
31b950bdd0SBenjamin Herrenschmidt  * SMT snooze delay stuff, 64-bit only for now
32b950bdd0SBenjamin Herrenschmidt  */
33d3d2176aSDavid Gibson 
34b950bdd0SBenjamin Herrenschmidt #ifdef CONFIG_PPC64
35b950bdd0SBenjamin Herrenschmidt 
360ddd3e7dSAnton Blanchard /* Time in microseconds we delay before sleeping in the idle loop */
370ddd3e7dSAnton Blanchard DEFINE_PER_CPU(unsigned long, smt_snooze_delay) = { 100 };
38d3d2176aSDavid Gibson 
394a0b2b4dSAndi Kleen static ssize_t store_smt_snooze_delay(struct sys_device *dev,
404a0b2b4dSAndi Kleen 				      struct sysdev_attribute *attr,
414a0b2b4dSAndi Kleen 				      const char *buf,
42d3d2176aSDavid Gibson 				      size_t count)
43d3d2176aSDavid Gibson {
44d3d2176aSDavid Gibson 	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
45d3d2176aSDavid Gibson 	ssize_t ret;
46d3d2176aSDavid Gibson 	unsigned long snooze;
47d3d2176aSDavid Gibson 
48d3d2176aSDavid Gibson 	ret = sscanf(buf, "%lu", &snooze);
49d3d2176aSDavid Gibson 	if (ret != 1)
50d3d2176aSDavid Gibson 		return -EINVAL;
51d3d2176aSDavid Gibson 
52d3d2176aSDavid Gibson 	per_cpu(smt_snooze_delay, cpu->sysdev.id) = snooze;
53d3d2176aSDavid Gibson 
54d3d2176aSDavid Gibson 	return count;
55d3d2176aSDavid Gibson }
56d3d2176aSDavid Gibson 
574a0b2b4dSAndi Kleen static ssize_t show_smt_snooze_delay(struct sys_device *dev,
584a0b2b4dSAndi Kleen 				     struct sysdev_attribute *attr,
594a0b2b4dSAndi Kleen 				     char *buf)
60d3d2176aSDavid Gibson {
61d3d2176aSDavid Gibson 	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
62d3d2176aSDavid Gibson 
63d3d2176aSDavid Gibson 	return sprintf(buf, "%lu\n", per_cpu(smt_snooze_delay, cpu->sysdev.id));
64d3d2176aSDavid Gibson }
65d3d2176aSDavid Gibson 
66d3d2176aSDavid Gibson static SYSDEV_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay,
67d3d2176aSDavid Gibson 		   store_smt_snooze_delay);
68d3d2176aSDavid Gibson 
69d3d2176aSDavid Gibson /* Only parse OF options if the matching cmdline option was not specified */
70d3d2176aSDavid Gibson static int smt_snooze_cmdline;
71d3d2176aSDavid Gibson 
72d3d2176aSDavid Gibson static int __init smt_setup(void)
73d3d2176aSDavid Gibson {
74d3d2176aSDavid Gibson 	struct device_node *options;
75a7f67bdfSJeremy Kerr 	const unsigned int *val;
76d3d2176aSDavid Gibson 	unsigned int cpu;
77d3d2176aSDavid Gibson 
78d3d2176aSDavid Gibson 	if (!cpu_has_feature(CPU_FTR_SMT))
7969ed3324SAnton Blanchard 		return -ENODEV;
80d3d2176aSDavid Gibson 
818c8dc322SStephen Rothwell 	options = of_find_node_by_path("/options");
82d3d2176aSDavid Gibson 	if (!options)
8369ed3324SAnton Blanchard 		return -ENODEV;
84d3d2176aSDavid Gibson 
85e2eb6392SStephen Rothwell 	val = of_get_property(options, "ibm,smt-snooze-delay", NULL);
86d3d2176aSDavid Gibson 	if (!smt_snooze_cmdline && val) {
870e551954SKAMEZAWA Hiroyuki 		for_each_possible_cpu(cpu)
88d3d2176aSDavid Gibson 			per_cpu(smt_snooze_delay, cpu) = *val;
89d3d2176aSDavid Gibson 	}
90d3d2176aSDavid Gibson 
918c8dc322SStephen Rothwell 	of_node_put(options);
9269ed3324SAnton Blanchard 	return 0;
93d3d2176aSDavid Gibson }
94d3d2176aSDavid Gibson __initcall(smt_setup);
95d3d2176aSDavid Gibson 
96d3d2176aSDavid Gibson static int __init setup_smt_snooze_delay(char *str)
97d3d2176aSDavid Gibson {
98d3d2176aSDavid Gibson 	unsigned int cpu;
99d3d2176aSDavid Gibson 	int snooze;
100d3d2176aSDavid Gibson 
101d3d2176aSDavid Gibson 	if (!cpu_has_feature(CPU_FTR_SMT))
102d3d2176aSDavid Gibson 		return 1;
103d3d2176aSDavid Gibson 
104d3d2176aSDavid Gibson 	smt_snooze_cmdline = 1;
105d3d2176aSDavid Gibson 
106d3d2176aSDavid Gibson 	if (get_option(&str, &snooze)) {
1070e551954SKAMEZAWA Hiroyuki 		for_each_possible_cpu(cpu)
108d3d2176aSDavid Gibson 			per_cpu(smt_snooze_delay, cpu) = snooze;
109d3d2176aSDavid Gibson 	}
110d3d2176aSDavid Gibson 
111d3d2176aSDavid Gibson 	return 1;
112d3d2176aSDavid Gibson }
113d3d2176aSDavid Gibson __setup("smt-snooze-delay=", setup_smt_snooze_delay);
114d3d2176aSDavid Gibson 
115b950bdd0SBenjamin Herrenschmidt #endif /* CONFIG_PPC64 */
116d3d2176aSDavid Gibson 
117d3d2176aSDavid Gibson /*
118d3d2176aSDavid Gibson  * Enabling PMCs will slow partition context switch times so we only do
119d3d2176aSDavid Gibson  * it the first time we write to the PMCs.
120d3d2176aSDavid Gibson  */
121d3d2176aSDavid Gibson 
122d3d2176aSDavid Gibson static DEFINE_PER_CPU(char, pmcs_enabled);
123d3d2176aSDavid Gibson 
124b950bdd0SBenjamin Herrenschmidt void ppc_enable_pmcs(void)
125d3d2176aSDavid Gibson {
126d3d2176aSDavid Gibson 	/* Only need to enable them once */
127d3d2176aSDavid Gibson 	if (__get_cpu_var(pmcs_enabled))
128d3d2176aSDavid Gibson 		return;
129d3d2176aSDavid Gibson 
130d3d2176aSDavid Gibson 	__get_cpu_var(pmcs_enabled) = 1;
131d3d2176aSDavid Gibson 
132d3d2176aSDavid Gibson 	if (ppc_md.enable_pmcs)
133d3d2176aSDavid Gibson 		ppc_md.enable_pmcs();
134d3d2176aSDavid Gibson }
135b950bdd0SBenjamin Herrenschmidt EXPORT_SYMBOL(ppc_enable_pmcs);
136d3d2176aSDavid Gibson 
13733a7f122SKumar Gala #if defined(CONFIG_6xx) || defined(CONFIG_PPC64)
138d3d2176aSDavid Gibson /* XXX convert to rusty's on_one_cpu */
139d3d2176aSDavid Gibson static unsigned long run_on_cpu(unsigned long cpu,
140d3d2176aSDavid Gibson 			        unsigned long (*func)(unsigned long),
141d3d2176aSDavid Gibson 				unsigned long arg)
142d3d2176aSDavid Gibson {
143d3d2176aSDavid Gibson 	cpumask_t old_affinity = current->cpus_allowed;
144d3d2176aSDavid Gibson 	unsigned long ret;
145d3d2176aSDavid Gibson 
146d3d2176aSDavid Gibson 	/* should return -EINVAL to userspace */
147d3d2176aSDavid Gibson 	if (set_cpus_allowed(current, cpumask_of_cpu(cpu)))
148d3d2176aSDavid Gibson 		return 0;
149d3d2176aSDavid Gibson 
150d3d2176aSDavid Gibson 	ret = func(arg);
151d3d2176aSDavid Gibson 
152d3d2176aSDavid Gibson 	set_cpus_allowed(current, old_affinity);
153d3d2176aSDavid Gibson 
154d3d2176aSDavid Gibson 	return ret;
155d3d2176aSDavid Gibson }
15633a7f122SKumar Gala #endif
157d3d2176aSDavid Gibson 
158d3d2176aSDavid Gibson #define SYSFS_PMCSETUP(NAME, ADDRESS) \
159d3d2176aSDavid Gibson static unsigned long read_##NAME(unsigned long junk) \
160d3d2176aSDavid Gibson { \
161d3d2176aSDavid Gibson 	return mfspr(ADDRESS); \
162d3d2176aSDavid Gibson } \
163d3d2176aSDavid Gibson static unsigned long write_##NAME(unsigned long val) \
164d3d2176aSDavid Gibson { \
165b950bdd0SBenjamin Herrenschmidt 	ppc_enable_pmcs(); \
166d3d2176aSDavid Gibson 	mtspr(ADDRESS, val); \
167d3d2176aSDavid Gibson 	return 0; \
168d3d2176aSDavid Gibson } \
1694a0b2b4dSAndi Kleen static ssize_t show_##NAME(struct sys_device *dev, \
1704a0b2b4dSAndi Kleen 			struct sysdev_attribute *attr, \
1714a0b2b4dSAndi Kleen 			char *buf) \
172d3d2176aSDavid Gibson { \
173d3d2176aSDavid Gibson 	struct cpu *cpu = container_of(dev, struct cpu, sysdev); \
174d3d2176aSDavid Gibson 	unsigned long val = run_on_cpu(cpu->sysdev.id, read_##NAME, 0); \
175d3d2176aSDavid Gibson 	return sprintf(buf, "%lx\n", val); \
176d3d2176aSDavid Gibson } \
1773ff6eeccSAdrian Bunk static ssize_t __used \
1784a0b2b4dSAndi Kleen 	store_##NAME(struct sys_device *dev, struct sysdev_attribute *attr, \
1794a0b2b4dSAndi Kleen 			const char *buf, size_t count) \
180d3d2176aSDavid Gibson { \
181d3d2176aSDavid Gibson 	struct cpu *cpu = container_of(dev, struct cpu, sysdev); \
182d3d2176aSDavid Gibson 	unsigned long val; \
183d3d2176aSDavid Gibson 	int ret = sscanf(buf, "%lx", &val); \
184d3d2176aSDavid Gibson 	if (ret != 1) \
185d3d2176aSDavid Gibson 		return -EINVAL; \
186d3d2176aSDavid Gibson 	run_on_cpu(cpu->sysdev.id, write_##NAME, val); \
187d3d2176aSDavid Gibson 	return count; \
188d3d2176aSDavid Gibson }
189d3d2176aSDavid Gibson 
1906529c13dSOlof Johansson 
1916529c13dSOlof Johansson /* Let's define all possible registers, we'll only hook up the ones
1926529c13dSOlof Johansson  * that are implemented on the current processor
1936529c13dSOlof Johansson  */
1946529c13dSOlof Johansson 
19533a7f122SKumar Gala #if defined(CONFIG_PPC64)
196b950bdd0SBenjamin Herrenschmidt #define HAS_PPC_PMC_CLASSIC	1
197b950bdd0SBenjamin Herrenschmidt #define HAS_PPC_PMC_IBM		1
198b950bdd0SBenjamin Herrenschmidt #define HAS_PPC_PMC_PA6T	1
19933a7f122SKumar Gala #elif defined(CONFIG_6xx)
200b950bdd0SBenjamin Herrenschmidt #define HAS_PPC_PMC_CLASSIC	1
201b950bdd0SBenjamin Herrenschmidt #define HAS_PPC_PMC_IBM		1
202b950bdd0SBenjamin Herrenschmidt #define HAS_PPC_PMC_G4		1
203b950bdd0SBenjamin Herrenschmidt #endif
204b950bdd0SBenjamin Herrenschmidt 
205b950bdd0SBenjamin Herrenschmidt 
206b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_CLASSIC
207d3d2176aSDavid Gibson SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0);
208d3d2176aSDavid Gibson SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1);
209d3d2176aSDavid Gibson SYSFS_PMCSETUP(pmc1, SPRN_PMC1);
210d3d2176aSDavid Gibson SYSFS_PMCSETUP(pmc2, SPRN_PMC2);
211d3d2176aSDavid Gibson SYSFS_PMCSETUP(pmc3, SPRN_PMC3);
212d3d2176aSDavid Gibson SYSFS_PMCSETUP(pmc4, SPRN_PMC4);
213d3d2176aSDavid Gibson SYSFS_PMCSETUP(pmc5, SPRN_PMC5);
214d3d2176aSDavid Gibson SYSFS_PMCSETUP(pmc6, SPRN_PMC6);
215b950bdd0SBenjamin Herrenschmidt 
216b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_G4
217b950bdd0SBenjamin Herrenschmidt SYSFS_PMCSETUP(mmcr2, SPRN_MMCR2);
218b950bdd0SBenjamin Herrenschmidt #endif
219b950bdd0SBenjamin Herrenschmidt 
220b950bdd0SBenjamin Herrenschmidt #ifdef CONFIG_PPC64
221d3d2176aSDavid Gibson SYSFS_PMCSETUP(pmc7, SPRN_PMC7);
222d3d2176aSDavid Gibson SYSFS_PMCSETUP(pmc8, SPRN_PMC8);
223b950bdd0SBenjamin Herrenschmidt 
224b950bdd0SBenjamin Herrenschmidt SYSFS_PMCSETUP(mmcra, SPRN_MMCRA);
225d3d2176aSDavid Gibson SYSFS_PMCSETUP(purr, SPRN_PURR);
226f050982aSAnton Blanchard SYSFS_PMCSETUP(spurr, SPRN_SPURR);
2274c198557SAnton Blanchard SYSFS_PMCSETUP(dscr, SPRN_DSCR);
228d3d2176aSDavid Gibson 
229b950bdd0SBenjamin Herrenschmidt static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
230b950bdd0SBenjamin Herrenschmidt static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
231b950bdd0SBenjamin Herrenschmidt static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
232b950bdd0SBenjamin Herrenschmidt static SYSDEV_ATTR(purr, 0600, show_purr, store_purr);
233b950bdd0SBenjamin Herrenschmidt #endif /* CONFIG_PPC64 */
234b950bdd0SBenjamin Herrenschmidt 
235b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_PA6T
23625fc530eSOlof Johansson SYSFS_PMCSETUP(pa6t_pmc0, SPRN_PA6T_PMC0);
23725fc530eSOlof Johansson SYSFS_PMCSETUP(pa6t_pmc1, SPRN_PA6T_PMC1);
23825fc530eSOlof Johansson SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2);
23925fc530eSOlof Johansson SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3);
24025fc530eSOlof Johansson SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4);
24125fc530eSOlof Johansson SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5);
2422e1957fdSOlof Johansson #ifdef CONFIG_DEBUG_KERNEL
2432e1957fdSOlof Johansson SYSFS_PMCSETUP(hid0, SPRN_HID0);
2442e1957fdSOlof Johansson SYSFS_PMCSETUP(hid1, SPRN_HID1);
2452e1957fdSOlof Johansson SYSFS_PMCSETUP(hid4, SPRN_HID4);
2462e1957fdSOlof Johansson SYSFS_PMCSETUP(hid5, SPRN_HID5);
2472e1957fdSOlof Johansson SYSFS_PMCSETUP(ima0, SPRN_PA6T_IMA0);
2482e1957fdSOlof Johansson SYSFS_PMCSETUP(ima1, SPRN_PA6T_IMA1);
2492e1957fdSOlof Johansson SYSFS_PMCSETUP(ima2, SPRN_PA6T_IMA2);
2502e1957fdSOlof Johansson SYSFS_PMCSETUP(ima3, SPRN_PA6T_IMA3);
2512e1957fdSOlof Johansson SYSFS_PMCSETUP(ima4, SPRN_PA6T_IMA4);
2522e1957fdSOlof Johansson SYSFS_PMCSETUP(ima5, SPRN_PA6T_IMA5);
2532e1957fdSOlof Johansson SYSFS_PMCSETUP(ima6, SPRN_PA6T_IMA6);
2542e1957fdSOlof Johansson SYSFS_PMCSETUP(ima7, SPRN_PA6T_IMA7);
2552e1957fdSOlof Johansson SYSFS_PMCSETUP(ima8, SPRN_PA6T_IMA8);
2562e1957fdSOlof Johansson SYSFS_PMCSETUP(ima9, SPRN_PA6T_IMA9);
2572e1957fdSOlof Johansson SYSFS_PMCSETUP(imaat, SPRN_PA6T_IMAAT);
2582e1957fdSOlof Johansson SYSFS_PMCSETUP(btcr, SPRN_PA6T_BTCR);
2592e1957fdSOlof Johansson SYSFS_PMCSETUP(pccr, SPRN_PA6T_PCCR);
2602e1957fdSOlof Johansson SYSFS_PMCSETUP(rpccr, SPRN_PA6T_RPCCR);
2612e1957fdSOlof Johansson SYSFS_PMCSETUP(der, SPRN_PA6T_DER);
2622e1957fdSOlof Johansson SYSFS_PMCSETUP(mer, SPRN_PA6T_MER);
2632e1957fdSOlof Johansson SYSFS_PMCSETUP(ber, SPRN_PA6T_BER);
2642e1957fdSOlof Johansson SYSFS_PMCSETUP(ier, SPRN_PA6T_IER);
2652e1957fdSOlof Johansson SYSFS_PMCSETUP(sier, SPRN_PA6T_SIER);
2662e1957fdSOlof Johansson SYSFS_PMCSETUP(siar, SPRN_PA6T_SIAR);
2672e1957fdSOlof Johansson SYSFS_PMCSETUP(tsr0, SPRN_PA6T_TSR0);
2682e1957fdSOlof Johansson SYSFS_PMCSETUP(tsr1, SPRN_PA6T_TSR1);
2692e1957fdSOlof Johansson SYSFS_PMCSETUP(tsr2, SPRN_PA6T_TSR2);
2702e1957fdSOlof Johansson SYSFS_PMCSETUP(tsr3, SPRN_PA6T_TSR3);
2712e1957fdSOlof Johansson #endif /* CONFIG_DEBUG_KERNEL */
272b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_PA6T */
2736529c13dSOlof Johansson 
274b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_IBM
2756529c13dSOlof Johansson static struct sysdev_attribute ibm_common_attrs[] = {
2766529c13dSOlof Johansson 	_SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
2776529c13dSOlof Johansson 	_SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
2786529c13dSOlof Johansson };
279b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_G4 */
2806529c13dSOlof Johansson 
281b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_G4
282b950bdd0SBenjamin Herrenschmidt static struct sysdev_attribute g4_common_attrs[] = {
283b950bdd0SBenjamin Herrenschmidt 	_SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
284b950bdd0SBenjamin Herrenschmidt 	_SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
285b950bdd0SBenjamin Herrenschmidt 	_SYSDEV_ATTR(mmcr2, 0600, show_mmcr2, store_mmcr2),
286b950bdd0SBenjamin Herrenschmidt };
287b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_G4 */
288b950bdd0SBenjamin Herrenschmidt 
289b950bdd0SBenjamin Herrenschmidt static struct sysdev_attribute classic_pmc_attrs[] = {
2906529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1),
2916529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2),
2926529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3),
2936529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4),
2946529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5),
2956529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6),
296b950bdd0SBenjamin Herrenschmidt #ifdef CONFIG_PPC64
2976529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7),
2986529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8),
299b950bdd0SBenjamin Herrenschmidt #endif
3006529c13dSOlof Johansson };
3016529c13dSOlof Johansson 
302b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_PA6T
3036529c13dSOlof Johansson static struct sysdev_attribute pa6t_attrs[] = {
3046529c13dSOlof Johansson 	_SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
3056529c13dSOlof Johansson 	_SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
3066529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc0, 0600, show_pa6t_pmc0, store_pa6t_pmc0),
3076529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc1, 0600, show_pa6t_pmc1, store_pa6t_pmc1),
3086529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc2, 0600, show_pa6t_pmc2, store_pa6t_pmc2),
3096529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc3, 0600, show_pa6t_pmc3, store_pa6t_pmc3),
3106529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc4, 0600, show_pa6t_pmc4, store_pa6t_pmc4),
3116529c13dSOlof Johansson 	_SYSDEV_ATTR(pmc5, 0600, show_pa6t_pmc5, store_pa6t_pmc5),
3122e1957fdSOlof Johansson #ifdef CONFIG_DEBUG_KERNEL
3132e1957fdSOlof Johansson 	_SYSDEV_ATTR(hid0, 0600, show_hid0, store_hid0),
3142e1957fdSOlof Johansson 	_SYSDEV_ATTR(hid1, 0600, show_hid1, store_hid1),
3152e1957fdSOlof Johansson 	_SYSDEV_ATTR(hid4, 0600, show_hid4, store_hid4),
3162e1957fdSOlof Johansson 	_SYSDEV_ATTR(hid5, 0600, show_hid5, store_hid5),
3172e1957fdSOlof Johansson 	_SYSDEV_ATTR(ima0, 0600, show_ima0, store_ima0),
3182e1957fdSOlof Johansson 	_SYSDEV_ATTR(ima1, 0600, show_ima1, store_ima1),
3192e1957fdSOlof Johansson 	_SYSDEV_ATTR(ima2, 0600, show_ima2, store_ima2),
3202e1957fdSOlof Johansson 	_SYSDEV_ATTR(ima3, 0600, show_ima3, store_ima3),
3212e1957fdSOlof Johansson 	_SYSDEV_ATTR(ima4, 0600, show_ima4, store_ima4),
3222e1957fdSOlof Johansson 	_SYSDEV_ATTR(ima5, 0600, show_ima5, store_ima5),
3232e1957fdSOlof Johansson 	_SYSDEV_ATTR(ima6, 0600, show_ima6, store_ima6),
3242e1957fdSOlof Johansson 	_SYSDEV_ATTR(ima7, 0600, show_ima7, store_ima7),
3252e1957fdSOlof Johansson 	_SYSDEV_ATTR(ima8, 0600, show_ima8, store_ima8),
3262e1957fdSOlof Johansson 	_SYSDEV_ATTR(ima9, 0600, show_ima9, store_ima9),
3272e1957fdSOlof Johansson 	_SYSDEV_ATTR(imaat, 0600, show_imaat, store_imaat),
3282e1957fdSOlof Johansson 	_SYSDEV_ATTR(btcr, 0600, show_btcr, store_btcr),
3292e1957fdSOlof Johansson 	_SYSDEV_ATTR(pccr, 0600, show_pccr, store_pccr),
3302e1957fdSOlof Johansson 	_SYSDEV_ATTR(rpccr, 0600, show_rpccr, store_rpccr),
3312e1957fdSOlof Johansson 	_SYSDEV_ATTR(der, 0600, show_der, store_der),
3322e1957fdSOlof Johansson 	_SYSDEV_ATTR(mer, 0600, show_mer, store_mer),
3332e1957fdSOlof Johansson 	_SYSDEV_ATTR(ber, 0600, show_ber, store_ber),
3342e1957fdSOlof Johansson 	_SYSDEV_ATTR(ier, 0600, show_ier, store_ier),
3352e1957fdSOlof Johansson 	_SYSDEV_ATTR(sier, 0600, show_sier, store_sier),
3362e1957fdSOlof Johansson 	_SYSDEV_ATTR(siar, 0600, show_siar, store_siar),
3372e1957fdSOlof Johansson 	_SYSDEV_ATTR(tsr0, 0600, show_tsr0, store_tsr0),
3382e1957fdSOlof Johansson 	_SYSDEV_ATTR(tsr1, 0600, show_tsr1, store_tsr1),
3392e1957fdSOlof Johansson 	_SYSDEV_ATTR(tsr2, 0600, show_tsr2, store_tsr2),
3402e1957fdSOlof Johansson 	_SYSDEV_ATTR(tsr3, 0600, show_tsr3, store_tsr3),
3412e1957fdSOlof Johansson #endif /* CONFIG_DEBUG_KERNEL */
3426529c13dSOlof Johansson };
343b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_PA6T */
344b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_CLASSIC */
3456529c13dSOlof Johansson 
346124c27d3SNathan Lynch struct cache_desc {
347124c27d3SNathan Lynch 	struct kobject kobj;
348124c27d3SNathan Lynch 	struct cache_desc *next;
349124c27d3SNathan Lynch 	const char *type;	/* Instruction, Data, or Unified */
350124c27d3SNathan Lynch 	u32 size;		/* total cache size in KB */
351124c27d3SNathan Lynch 	u32 line_size;		/* in bytes */
352124c27d3SNathan Lynch 	u32 nr_sets;		/* number of sets */
353124c27d3SNathan Lynch 	u32 level;		/* e.g. 1, 2, 3... */
354124c27d3SNathan Lynch 	u32 associativity;	/* e.g. 8-way... 0 is fully associative */
355124c27d3SNathan Lynch };
356124c27d3SNathan Lynch 
357124c27d3SNathan Lynch DEFINE_PER_CPU(struct cache_desc *, cache_desc);
358124c27d3SNathan Lynch 
359124c27d3SNathan Lynch static struct cache_desc *kobj_to_cache_desc(struct kobject *k)
360124c27d3SNathan Lynch {
361124c27d3SNathan Lynch 	return container_of(k, struct cache_desc, kobj);
362124c27d3SNathan Lynch }
363124c27d3SNathan Lynch 
364124c27d3SNathan Lynch static void cache_desc_release(struct kobject *k)
365124c27d3SNathan Lynch {
366124c27d3SNathan Lynch 	struct cache_desc *desc = kobj_to_cache_desc(k);
367124c27d3SNathan Lynch 
368124c27d3SNathan Lynch 	pr_debug("%s: releasing %s\n", __func__, kobject_name(k));
369124c27d3SNathan Lynch 
370124c27d3SNathan Lynch 	if (desc->next)
371124c27d3SNathan Lynch 		kobject_put(&desc->next->kobj);
372124c27d3SNathan Lynch 
373124c27d3SNathan Lynch 	kfree(kobj_to_cache_desc(k));
374124c27d3SNathan Lynch }
375124c27d3SNathan Lynch 
376124c27d3SNathan Lynch static ssize_t cache_desc_show(struct kobject *k, struct attribute *attr, char *buf)
377124c27d3SNathan Lynch {
378124c27d3SNathan Lynch 	struct kobj_attribute *kobj_attr;
379124c27d3SNathan Lynch 
380124c27d3SNathan Lynch 	kobj_attr = container_of(attr, struct kobj_attribute, attr);
381124c27d3SNathan Lynch 
382124c27d3SNathan Lynch 	return kobj_attr->show(k, kobj_attr, buf);
383124c27d3SNathan Lynch }
384124c27d3SNathan Lynch 
385124c27d3SNathan Lynch static struct sysfs_ops cache_desc_sysfs_ops = {
386124c27d3SNathan Lynch 	.show = cache_desc_show,
387124c27d3SNathan Lynch };
388124c27d3SNathan Lynch 
389124c27d3SNathan Lynch static struct kobj_type cache_desc_type = {
390124c27d3SNathan Lynch 	.release = cache_desc_release,
391124c27d3SNathan Lynch 	.sysfs_ops = &cache_desc_sysfs_ops,
392124c27d3SNathan Lynch };
393124c27d3SNathan Lynch 
394124c27d3SNathan Lynch static ssize_t cache_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
395124c27d3SNathan Lynch {
396124c27d3SNathan Lynch 	struct cache_desc *cache = kobj_to_cache_desc(k);
397124c27d3SNathan Lynch 
398124c27d3SNathan Lynch 	return sprintf(buf, "%uK\n", cache->size);
399124c27d3SNathan Lynch }
400124c27d3SNathan Lynch 
401124c27d3SNathan Lynch static struct kobj_attribute cache_size_attr =
402124c27d3SNathan Lynch 	__ATTR(size, 0444, cache_size_show, NULL);
403124c27d3SNathan Lynch 
404124c27d3SNathan Lynch static ssize_t cache_line_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
405124c27d3SNathan Lynch {
406124c27d3SNathan Lynch 	struct cache_desc *cache = kobj_to_cache_desc(k);
407124c27d3SNathan Lynch 
408124c27d3SNathan Lynch 	return sprintf(buf, "%u\n", cache->line_size);
409124c27d3SNathan Lynch }
410124c27d3SNathan Lynch 
411124c27d3SNathan Lynch static struct kobj_attribute cache_line_size_attr =
412124c27d3SNathan Lynch 	__ATTR(coherency_line_size, 0444, cache_line_size_show, NULL);
413124c27d3SNathan Lynch 
414124c27d3SNathan Lynch static ssize_t cache_nr_sets_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
415124c27d3SNathan Lynch {
416124c27d3SNathan Lynch 	struct cache_desc *cache = kobj_to_cache_desc(k);
417124c27d3SNathan Lynch 
418124c27d3SNathan Lynch 	return sprintf(buf, "%u\n", cache->nr_sets);
419124c27d3SNathan Lynch }
420124c27d3SNathan Lynch 
421124c27d3SNathan Lynch static struct kobj_attribute cache_nr_sets_attr =
422124c27d3SNathan Lynch 	__ATTR(number_of_sets, 0444, cache_nr_sets_show, NULL);
423124c27d3SNathan Lynch 
424124c27d3SNathan Lynch static ssize_t cache_type_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
425124c27d3SNathan Lynch {
426124c27d3SNathan Lynch 	struct cache_desc *cache = kobj_to_cache_desc(k);
427124c27d3SNathan Lynch 
428124c27d3SNathan Lynch 	return sprintf(buf, "%s\n", cache->type);
429124c27d3SNathan Lynch }
430124c27d3SNathan Lynch 
431124c27d3SNathan Lynch static struct kobj_attribute cache_type_attr =
432124c27d3SNathan Lynch 	__ATTR(type, 0444, cache_type_show, NULL);
433124c27d3SNathan Lynch 
434124c27d3SNathan Lynch static ssize_t cache_level_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
435124c27d3SNathan Lynch {
436124c27d3SNathan Lynch 	struct cache_desc *cache = kobj_to_cache_desc(k);
437124c27d3SNathan Lynch 
438124c27d3SNathan Lynch 	return sprintf(buf, "%u\n", cache->level);
439124c27d3SNathan Lynch }
440124c27d3SNathan Lynch 
441124c27d3SNathan Lynch static struct kobj_attribute cache_level_attr =
442124c27d3SNathan Lynch 	__ATTR(level, 0444, cache_level_show, NULL);
443124c27d3SNathan Lynch 
444124c27d3SNathan Lynch static ssize_t cache_assoc_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
445124c27d3SNathan Lynch {
446124c27d3SNathan Lynch 	struct cache_desc *cache = kobj_to_cache_desc(k);
447124c27d3SNathan Lynch 
448124c27d3SNathan Lynch 	return sprintf(buf, "%u\n", cache->associativity);
449124c27d3SNathan Lynch }
450124c27d3SNathan Lynch 
451124c27d3SNathan Lynch static struct kobj_attribute cache_assoc_attr =
452124c27d3SNathan Lynch 	__ATTR(ways_of_associativity, 0444, cache_assoc_show, NULL);
453124c27d3SNathan Lynch 
454124c27d3SNathan Lynch struct cache_desc_info {
455124c27d3SNathan Lynch 	const char *type;
456124c27d3SNathan Lynch 	const char *size_prop;
457124c27d3SNathan Lynch 	const char *line_size_prop;
458124c27d3SNathan Lynch 	const char *nr_sets_prop;
459124c27d3SNathan Lynch };
460124c27d3SNathan Lynch 
461124c27d3SNathan Lynch /* PowerPC Processor binding says the [di]-cache-* must be equal on
462124c27d3SNathan Lynch  * unified caches, so just use d-cache properties. */
463124c27d3SNathan Lynch static struct cache_desc_info ucache_info = {
464124c27d3SNathan Lynch 	.type = "Unified",
465124c27d3SNathan Lynch 	.size_prop = "d-cache-size",
466124c27d3SNathan Lynch 	.line_size_prop = "d-cache-line-size",
467124c27d3SNathan Lynch 	.nr_sets_prop = "d-cache-sets",
468124c27d3SNathan Lynch };
469124c27d3SNathan Lynch 
470124c27d3SNathan Lynch static struct cache_desc_info dcache_info = {
471124c27d3SNathan Lynch 	.type = "Data",
472124c27d3SNathan Lynch 	.size_prop = "d-cache-size",
473124c27d3SNathan Lynch 	.line_size_prop = "d-cache-line-size",
474124c27d3SNathan Lynch 	.nr_sets_prop = "d-cache-sets",
475124c27d3SNathan Lynch };
476124c27d3SNathan Lynch 
477124c27d3SNathan Lynch static struct cache_desc_info icache_info = {
478124c27d3SNathan Lynch 	.type = "Instruction",
479124c27d3SNathan Lynch 	.size_prop = "i-cache-size",
480124c27d3SNathan Lynch 	.line_size_prop = "i-cache-line-size",
481124c27d3SNathan Lynch 	.nr_sets_prop = "i-cache-sets",
482124c27d3SNathan Lynch };
483124c27d3SNathan Lynch 
484124c27d3SNathan Lynch static struct cache_desc * __cpuinit create_cache_desc(struct device_node *np, struct kobject *parent, int index, int level, struct cache_desc_info *info)
485124c27d3SNathan Lynch {
486124c27d3SNathan Lynch 	const u32 *cache_line_size;
487124c27d3SNathan Lynch 	struct cache_desc *new;
488124c27d3SNathan Lynch 	const u32 *cache_size;
489124c27d3SNathan Lynch 	const u32 *nr_sets;
490124c27d3SNathan Lynch 	int rc;
491124c27d3SNathan Lynch 
492124c27d3SNathan Lynch 	new = kzalloc(sizeof(*new), GFP_KERNEL);
493124c27d3SNathan Lynch 	if (!new)
494124c27d3SNathan Lynch 		return NULL;
495124c27d3SNathan Lynch 
496124c27d3SNathan Lynch 	rc = kobject_init_and_add(&new->kobj, &cache_desc_type, parent,
497124c27d3SNathan Lynch 				  "index%d", index);
498124c27d3SNathan Lynch 	if (rc)
499124c27d3SNathan Lynch 		goto err;
500124c27d3SNathan Lynch 
501124c27d3SNathan Lynch 	/* type */
502124c27d3SNathan Lynch 	new->type = info->type;
503124c27d3SNathan Lynch 	rc = sysfs_create_file(&new->kobj, &cache_type_attr.attr);
504124c27d3SNathan Lynch 	WARN_ON(rc);
505124c27d3SNathan Lynch 
506124c27d3SNathan Lynch 	/* level */
507124c27d3SNathan Lynch 	new->level = level;
508124c27d3SNathan Lynch 	rc = sysfs_create_file(&new->kobj, &cache_level_attr.attr);
509124c27d3SNathan Lynch 	WARN_ON(rc);
510124c27d3SNathan Lynch 
511124c27d3SNathan Lynch 	/* size */
512124c27d3SNathan Lynch 	cache_size = of_get_property(np, info->size_prop, NULL);
513124c27d3SNathan Lynch 	if (cache_size) {
514124c27d3SNathan Lynch 		new->size = *cache_size / 1024;
515124c27d3SNathan Lynch 		rc = sysfs_create_file(&new->kobj,
516124c27d3SNathan Lynch 				       &cache_size_attr.attr);
517124c27d3SNathan Lynch 		WARN_ON(rc);
518124c27d3SNathan Lynch 	}
519124c27d3SNathan Lynch 
520124c27d3SNathan Lynch 	/* coherency_line_size */
521124c27d3SNathan Lynch 	cache_line_size = of_get_property(np, info->line_size_prop, NULL);
522124c27d3SNathan Lynch 	if (cache_line_size) {
523124c27d3SNathan Lynch 		new->line_size = *cache_line_size;
524124c27d3SNathan Lynch 		rc = sysfs_create_file(&new->kobj,
525124c27d3SNathan Lynch 				       &cache_line_size_attr.attr);
526124c27d3SNathan Lynch 		WARN_ON(rc);
527124c27d3SNathan Lynch 	}
528124c27d3SNathan Lynch 
529124c27d3SNathan Lynch 	/* number_of_sets */
530124c27d3SNathan Lynch 	nr_sets = of_get_property(np, info->nr_sets_prop, NULL);
531124c27d3SNathan Lynch 	if (nr_sets) {
532124c27d3SNathan Lynch 		new->nr_sets = *nr_sets;
533124c27d3SNathan Lynch 		rc = sysfs_create_file(&new->kobj,
534124c27d3SNathan Lynch 				       &cache_nr_sets_attr.attr);
535124c27d3SNathan Lynch 		WARN_ON(rc);
536124c27d3SNathan Lynch 	}
537124c27d3SNathan Lynch 
538124c27d3SNathan Lynch 	/* ways_of_associativity */
539124c27d3SNathan Lynch 	if (new->nr_sets == 1) {
540124c27d3SNathan Lynch 		/* fully associative */
541124c27d3SNathan Lynch 		new->associativity = 0;
542124c27d3SNathan Lynch 		goto create_assoc;
543124c27d3SNathan Lynch 	}
544124c27d3SNathan Lynch 
545124c27d3SNathan Lynch 	if (new->nr_sets && new->size && new->line_size) {
546124c27d3SNathan Lynch 		/* If we have values for all of these we can derive
547124c27d3SNathan Lynch 		 * the associativity. */
548124c27d3SNathan Lynch 		new->associativity =
549124c27d3SNathan Lynch 			((new->size * 1024) / new->nr_sets) / new->line_size;
550124c27d3SNathan Lynch create_assoc:
551124c27d3SNathan Lynch 		rc = sysfs_create_file(&new->kobj,
552124c27d3SNathan Lynch 				       &cache_assoc_attr.attr);
553124c27d3SNathan Lynch 		WARN_ON(rc);
554124c27d3SNathan Lynch 	}
555124c27d3SNathan Lynch 
556124c27d3SNathan Lynch 	return new;
557124c27d3SNathan Lynch err:
558124c27d3SNathan Lynch 	kfree(new);
559124c27d3SNathan Lynch 	return NULL;
560124c27d3SNathan Lynch }
561124c27d3SNathan Lynch 
562124c27d3SNathan Lynch static bool cache_is_unified(struct device_node *np)
563124c27d3SNathan Lynch {
564124c27d3SNathan Lynch 	return of_get_property(np, "cache-unified", NULL);
565124c27d3SNathan Lynch }
566124c27d3SNathan Lynch 
567124c27d3SNathan Lynch static struct cache_desc * __cpuinit create_cache_index_info(struct device_node *np, struct kobject *parent, int index, int level)
568124c27d3SNathan Lynch {
569124c27d3SNathan Lynch 	const phandle *next_cache_phandle;
570124c27d3SNathan Lynch 	struct device_node *next_cache;
571124c27d3SNathan Lynch 	struct cache_desc *new, **end;
572124c27d3SNathan Lynch 
573124c27d3SNathan Lynch 	pr_debug("%s(node = %s, index = %d)\n", __func__, np->full_name, index);
574124c27d3SNathan Lynch 
575124c27d3SNathan Lynch 	if (cache_is_unified(np)) {
576124c27d3SNathan Lynch 		new = create_cache_desc(np, parent, index, level,
577124c27d3SNathan Lynch 					&ucache_info);
578124c27d3SNathan Lynch 	} else {
579124c27d3SNathan Lynch 		new = create_cache_desc(np, parent, index, level,
580124c27d3SNathan Lynch 					&dcache_info);
581124c27d3SNathan Lynch 		if (new) {
582124c27d3SNathan Lynch 			index++;
583124c27d3SNathan Lynch 			new->next = create_cache_desc(np, parent, index, level,
584124c27d3SNathan Lynch 						      &icache_info);
585124c27d3SNathan Lynch 		}
586124c27d3SNathan Lynch 	}
587124c27d3SNathan Lynch 	if (!new)
588124c27d3SNathan Lynch 		return NULL;
589124c27d3SNathan Lynch 
590124c27d3SNathan Lynch 	end = &new->next;
591124c27d3SNathan Lynch 	while (*end)
592124c27d3SNathan Lynch 		end = &(*end)->next;
593124c27d3SNathan Lynch 
594124c27d3SNathan Lynch 	next_cache_phandle = of_get_property(np, "l2-cache", NULL);
595124c27d3SNathan Lynch 	if (!next_cache_phandle)
596124c27d3SNathan Lynch 		goto out;
597124c27d3SNathan Lynch 
598124c27d3SNathan Lynch 	next_cache = of_find_node_by_phandle(*next_cache_phandle);
599124c27d3SNathan Lynch 	if (!next_cache)
600124c27d3SNathan Lynch 		goto out;
601124c27d3SNathan Lynch 
602124c27d3SNathan Lynch 	*end = create_cache_index_info(next_cache, parent, ++index, ++level);
603124c27d3SNathan Lynch 
604124c27d3SNathan Lynch 	of_node_put(next_cache);
605124c27d3SNathan Lynch out:
606124c27d3SNathan Lynch 	return new;
607124c27d3SNathan Lynch }
608124c27d3SNathan Lynch 
609124c27d3SNathan Lynch static void __cpuinit create_cache_info(struct sys_device *sysdev)
610124c27d3SNathan Lynch {
611124c27d3SNathan Lynch 	struct kobject *cache_toplevel;
612124c27d3SNathan Lynch 	struct device_node *np = NULL;
613124c27d3SNathan Lynch 	int cpu = sysdev->id;
614124c27d3SNathan Lynch 
615124c27d3SNathan Lynch 	cache_toplevel = kobject_create_and_add("cache", &sysdev->kobj);
616124c27d3SNathan Lynch 	if (!cache_toplevel)
617124c27d3SNathan Lynch 		return;
618124c27d3SNathan Lynch 	per_cpu(cache_toplevel, cpu) = cache_toplevel;
619124c27d3SNathan Lynch 	np = of_get_cpu_node(cpu, NULL);
620124c27d3SNathan Lynch 	if (np != NULL) {
621124c27d3SNathan Lynch 		per_cpu(cache_desc, cpu) =
622124c27d3SNathan Lynch 			create_cache_index_info(np, cache_toplevel, 0, 1);
623124c27d3SNathan Lynch 		of_node_put(np);
624124c27d3SNathan Lynch 	}
625124c27d3SNathan Lynch 	return;
626124c27d3SNathan Lynch }
627d3d2176aSDavid Gibson 
6289ba1984eSNathan Lynch static void __cpuinit register_cpu_online(unsigned int cpu)
629d3d2176aSDavid Gibson {
630d3d2176aSDavid Gibson 	struct cpu *c = &per_cpu(cpu_devices, cpu);
631d3d2176aSDavid Gibson 	struct sys_device *s = &c->sysdev;
6326529c13dSOlof Johansson 	struct sysdev_attribute *attrs, *pmc_attrs;
6336529c13dSOlof Johansson 	int i, nattrs;
634d3d2176aSDavid Gibson 
635b950bdd0SBenjamin Herrenschmidt #ifdef CONFIG_PPC64
636ad5cb17fSStephen Rothwell 	if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
637ad5cb17fSStephen Rothwell 			cpu_has_feature(CPU_FTR_SMT))
638d3d2176aSDavid Gibson 		sysdev_create_file(s, &attr_smt_snooze_delay);
639b950bdd0SBenjamin Herrenschmidt #endif
640d3d2176aSDavid Gibson 
641d3d2176aSDavid Gibson 	/* PMC stuff */
6426529c13dSOlof Johansson 	switch (cur_cpu_spec->pmc_type) {
643b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_IBM
6446529c13dSOlof Johansson 	case PPC_PMC_IBM:
6456529c13dSOlof Johansson 		attrs = ibm_common_attrs;
6466529c13dSOlof Johansson 		nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute);
647b950bdd0SBenjamin Herrenschmidt 		pmc_attrs = classic_pmc_attrs;
6486529c13dSOlof Johansson 		break;
649b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_IBM */
650b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_G4
651b950bdd0SBenjamin Herrenschmidt 	case PPC_PMC_G4:
652b950bdd0SBenjamin Herrenschmidt 		attrs = g4_common_attrs;
653b950bdd0SBenjamin Herrenschmidt 		nattrs = sizeof(g4_common_attrs) / sizeof(struct sysdev_attribute);
654b950bdd0SBenjamin Herrenschmidt 		pmc_attrs = classic_pmc_attrs;
655b950bdd0SBenjamin Herrenschmidt 		break;
656b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_G4 */
657b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_PA6T
6586529c13dSOlof Johansson 	case PPC_PMC_PA6T:
6596529c13dSOlof Johansson 		/* PA Semi starts counting at PMC0 */
6606529c13dSOlof Johansson 		attrs = pa6t_attrs;
6616529c13dSOlof Johansson 		nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute);
6626529c13dSOlof Johansson 		pmc_attrs = NULL;
6636529c13dSOlof Johansson 		break;
664b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_PA6T */
6656529c13dSOlof Johansson 	default:
6666529c13dSOlof Johansson 		attrs = NULL;
6676529c13dSOlof Johansson 		nattrs = 0;
6686529c13dSOlof Johansson 		pmc_attrs = NULL;
6696529c13dSOlof Johansson 	}
670d3d2176aSDavid Gibson 
6716529c13dSOlof Johansson 	for (i = 0; i < nattrs; i++)
6726529c13dSOlof Johansson 		sysdev_create_file(s, &attrs[i]);
6736529c13dSOlof Johansson 
6746529c13dSOlof Johansson 	if (pmc_attrs)
6756529c13dSOlof Johansson 		for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
6766529c13dSOlof Johansson 			sysdev_create_file(s, &pmc_attrs[i]);
677d3d2176aSDavid Gibson 
678b950bdd0SBenjamin Herrenschmidt #ifdef CONFIG_PPC64
679d3d2176aSDavid Gibson 	if (cpu_has_feature(CPU_FTR_MMCRA))
680d3d2176aSDavid Gibson 		sysdev_create_file(s, &attr_mmcra);
681d3d2176aSDavid Gibson 
682afd05423SMichael Neuling 	if (cpu_has_feature(CPU_FTR_PURR))
683d3d2176aSDavid Gibson 		sysdev_create_file(s, &attr_purr);
6844c198557SAnton Blanchard 
685f050982aSAnton Blanchard 	if (cpu_has_feature(CPU_FTR_SPURR))
686f050982aSAnton Blanchard 		sysdev_create_file(s, &attr_spurr);
687f050982aSAnton Blanchard 
6884c198557SAnton Blanchard 	if (cpu_has_feature(CPU_FTR_DSCR))
6894c198557SAnton Blanchard 		sysdev_create_file(s, &attr_dscr);
690b950bdd0SBenjamin Herrenschmidt #endif /* CONFIG_PPC64 */
691124c27d3SNathan Lynch 
692124c27d3SNathan Lynch 	create_cache_info(s);
693d3d2176aSDavid Gibson }
694d3d2176aSDavid Gibson 
695d3d2176aSDavid Gibson #ifdef CONFIG_HOTPLUG_CPU
696124c27d3SNathan Lynch static void remove_cache_info(struct sys_device *sysdev)
697124c27d3SNathan Lynch {
698124c27d3SNathan Lynch 	struct kobject *cache_toplevel;
699124c27d3SNathan Lynch 	struct cache_desc *cache_desc;
700124c27d3SNathan Lynch 	int cpu = sysdev->id;
701124c27d3SNathan Lynch 
702124c27d3SNathan Lynch 	cache_desc = per_cpu(cache_desc, cpu);
703f3d3d307SNathan Lynch 	if (cache_desc != NULL)
704124c27d3SNathan Lynch 		kobject_put(&cache_desc->kobj);
705f3d3d307SNathan Lynch 
706124c27d3SNathan Lynch 	cache_toplevel = per_cpu(cache_toplevel, cpu);
707124c27d3SNathan Lynch 	if (cache_toplevel != NULL)
708124c27d3SNathan Lynch 		kobject_put(cache_toplevel);
709124c27d3SNathan Lynch }
710124c27d3SNathan Lynch 
711d3d2176aSDavid Gibson static void unregister_cpu_online(unsigned int cpu)
712d3d2176aSDavid Gibson {
713d3d2176aSDavid Gibson 	struct cpu *c = &per_cpu(cpu_devices, cpu);
714d3d2176aSDavid Gibson 	struct sys_device *s = &c->sysdev;
7156529c13dSOlof Johansson 	struct sysdev_attribute *attrs, *pmc_attrs;
7166529c13dSOlof Johansson 	int i, nattrs;
717d3d2176aSDavid Gibson 
71872486f1fSSiddha, Suresh B 	BUG_ON(!c->hotpluggable);
719d3d2176aSDavid Gibson 
720*a1e0eb10SMilton Miller #ifdef CONFIG_PPC64
721ad5cb17fSStephen Rothwell 	if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
722ad5cb17fSStephen Rothwell 			cpu_has_feature(CPU_FTR_SMT))
723d3d2176aSDavid Gibson 		sysdev_remove_file(s, &attr_smt_snooze_delay);
724*a1e0eb10SMilton Miller #endif
725d3d2176aSDavid Gibson 
726d3d2176aSDavid Gibson 	/* PMC stuff */
7276529c13dSOlof Johansson 	switch (cur_cpu_spec->pmc_type) {
728b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_IBM
7296529c13dSOlof Johansson 	case PPC_PMC_IBM:
7306529c13dSOlof Johansson 		attrs = ibm_common_attrs;
7316529c13dSOlof Johansson 		nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute);
732b950bdd0SBenjamin Herrenschmidt 		pmc_attrs = classic_pmc_attrs;
7336529c13dSOlof Johansson 		break;
734b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_IBM */
735b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_G4
736b950bdd0SBenjamin Herrenschmidt 	case PPC_PMC_G4:
737b950bdd0SBenjamin Herrenschmidt 		attrs = g4_common_attrs;
738b950bdd0SBenjamin Herrenschmidt 		nattrs = sizeof(g4_common_attrs) / sizeof(struct sysdev_attribute);
739b950bdd0SBenjamin Herrenschmidt 		pmc_attrs = classic_pmc_attrs;
740b950bdd0SBenjamin Herrenschmidt 		break;
741b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_G4 */
742b950bdd0SBenjamin Herrenschmidt #ifdef HAS_PPC_PMC_PA6T
7436529c13dSOlof Johansson 	case PPC_PMC_PA6T:
7446529c13dSOlof Johansson 		/* PA Semi starts counting at PMC0 */
7456529c13dSOlof Johansson 		attrs = pa6t_attrs;
7466529c13dSOlof Johansson 		nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute);
7476529c13dSOlof Johansson 		pmc_attrs = NULL;
7486529c13dSOlof Johansson 		break;
749b950bdd0SBenjamin Herrenschmidt #endif /* HAS_PPC_PMC_PA6T */
7506529c13dSOlof Johansson 	default:
7516529c13dSOlof Johansson 		attrs = NULL;
7526529c13dSOlof Johansson 		nattrs = 0;
7536529c13dSOlof Johansson 		pmc_attrs = NULL;
7546529c13dSOlof Johansson 	}
755d3d2176aSDavid Gibson 
7566529c13dSOlof Johansson 	for (i = 0; i < nattrs; i++)
7576529c13dSOlof Johansson 		sysdev_remove_file(s, &attrs[i]);
7586529c13dSOlof Johansson 
7596529c13dSOlof Johansson 	if (pmc_attrs)
7606529c13dSOlof Johansson 		for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
7616529c13dSOlof Johansson 			sysdev_remove_file(s, &pmc_attrs[i]);
762d3d2176aSDavid Gibson 
763b950bdd0SBenjamin Herrenschmidt #ifdef CONFIG_PPC64
764d3d2176aSDavid Gibson 	if (cpu_has_feature(CPU_FTR_MMCRA))
765d3d2176aSDavid Gibson 		sysdev_remove_file(s, &attr_mmcra);
766d3d2176aSDavid Gibson 
767afd05423SMichael Neuling 	if (cpu_has_feature(CPU_FTR_PURR))
768d3d2176aSDavid Gibson 		sysdev_remove_file(s, &attr_purr);
7694c198557SAnton Blanchard 
770f050982aSAnton Blanchard 	if (cpu_has_feature(CPU_FTR_SPURR))
771f050982aSAnton Blanchard 		sysdev_remove_file(s, &attr_spurr);
772f050982aSAnton Blanchard 
7734c198557SAnton Blanchard 	if (cpu_has_feature(CPU_FTR_DSCR))
7744c198557SAnton Blanchard 		sysdev_remove_file(s, &attr_dscr);
775b950bdd0SBenjamin Herrenschmidt #endif /* CONFIG_PPC64 */
776124c27d3SNathan Lynch 
777124c27d3SNathan Lynch 	remove_cache_info(s);
778d3d2176aSDavid Gibson }
779d3d2176aSDavid Gibson #endif /* CONFIG_HOTPLUG_CPU */
780d3d2176aSDavid Gibson 
7818c78f307SChandra Seetharaman static int __cpuinit sysfs_cpu_notify(struct notifier_block *self,
782d3d2176aSDavid Gibson 				      unsigned long action, void *hcpu)
783d3d2176aSDavid Gibson {
784d3d2176aSDavid Gibson 	unsigned int cpu = (unsigned int)(long)hcpu;
785d3d2176aSDavid Gibson 
786d3d2176aSDavid Gibson 	switch (action) {
787d3d2176aSDavid Gibson 	case CPU_ONLINE:
7888bb78442SRafael J. Wysocki 	case CPU_ONLINE_FROZEN:
789d3d2176aSDavid Gibson 		register_cpu_online(cpu);
790d3d2176aSDavid Gibson 		break;
791d3d2176aSDavid Gibson #ifdef CONFIG_HOTPLUG_CPU
792d3d2176aSDavid Gibson 	case CPU_DEAD:
7938bb78442SRafael J. Wysocki 	case CPU_DEAD_FROZEN:
794d3d2176aSDavid Gibson 		unregister_cpu_online(cpu);
795d3d2176aSDavid Gibson 		break;
796d3d2176aSDavid Gibson #endif
797d3d2176aSDavid Gibson 	}
798d3d2176aSDavid Gibson 	return NOTIFY_OK;
799d3d2176aSDavid Gibson }
800d3d2176aSDavid Gibson 
8018c78f307SChandra Seetharaman static struct notifier_block __cpuinitdata sysfs_cpu_nb = {
802d3d2176aSDavid Gibson 	.notifier_call	= sysfs_cpu_notify,
803d3d2176aSDavid Gibson };
804d3d2176aSDavid Gibson 
8050344c6c5SChristian Krafft static DEFINE_MUTEX(cpu_mutex);
8060344c6c5SChristian Krafft 
8070344c6c5SChristian Krafft int cpu_add_sysdev_attr(struct sysdev_attribute *attr)
8080344c6c5SChristian Krafft {
8090344c6c5SChristian Krafft 	int cpu;
8100344c6c5SChristian Krafft 
8110344c6c5SChristian Krafft 	mutex_lock(&cpu_mutex);
8120344c6c5SChristian Krafft 
8130344c6c5SChristian Krafft 	for_each_possible_cpu(cpu) {
8140344c6c5SChristian Krafft 		sysdev_create_file(get_cpu_sysdev(cpu), attr);
8150344c6c5SChristian Krafft 	}
8160344c6c5SChristian Krafft 
8170344c6c5SChristian Krafft 	mutex_unlock(&cpu_mutex);
8180344c6c5SChristian Krafft 	return 0;
8190344c6c5SChristian Krafft }
8200344c6c5SChristian Krafft EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr);
8210344c6c5SChristian Krafft 
8220344c6c5SChristian Krafft int cpu_add_sysdev_attr_group(struct attribute_group *attrs)
8230344c6c5SChristian Krafft {
8240344c6c5SChristian Krafft 	int cpu;
8250344c6c5SChristian Krafft 	struct sys_device *sysdev;
8266bcc4c01SOlof Johansson 	int ret;
8270344c6c5SChristian Krafft 
8280344c6c5SChristian Krafft 	mutex_lock(&cpu_mutex);
8290344c6c5SChristian Krafft 
8300344c6c5SChristian Krafft 	for_each_possible_cpu(cpu) {
8310344c6c5SChristian Krafft 		sysdev = get_cpu_sysdev(cpu);
8326bcc4c01SOlof Johansson 		ret = sysfs_create_group(&sysdev->kobj, attrs);
8336bcc4c01SOlof Johansson 		WARN_ON(ret != 0);
8340344c6c5SChristian Krafft 	}
8350344c6c5SChristian Krafft 
8360344c6c5SChristian Krafft 	mutex_unlock(&cpu_mutex);
8370344c6c5SChristian Krafft 	return 0;
8380344c6c5SChristian Krafft }
8390344c6c5SChristian Krafft EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr_group);
8400344c6c5SChristian Krafft 
8410344c6c5SChristian Krafft 
8420344c6c5SChristian Krafft void cpu_remove_sysdev_attr(struct sysdev_attribute *attr)
8430344c6c5SChristian Krafft {
8440344c6c5SChristian Krafft 	int cpu;
8450344c6c5SChristian Krafft 
8460344c6c5SChristian Krafft 	mutex_lock(&cpu_mutex);
8470344c6c5SChristian Krafft 
8480344c6c5SChristian Krafft 	for_each_possible_cpu(cpu) {
8490344c6c5SChristian Krafft 		sysdev_remove_file(get_cpu_sysdev(cpu), attr);
8500344c6c5SChristian Krafft 	}
8510344c6c5SChristian Krafft 
8520344c6c5SChristian Krafft 	mutex_unlock(&cpu_mutex);
8530344c6c5SChristian Krafft }
8540344c6c5SChristian Krafft EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr);
8550344c6c5SChristian Krafft 
8560344c6c5SChristian Krafft void cpu_remove_sysdev_attr_group(struct attribute_group *attrs)
8570344c6c5SChristian Krafft {
8580344c6c5SChristian Krafft 	int cpu;
8590344c6c5SChristian Krafft 	struct sys_device *sysdev;
8600344c6c5SChristian Krafft 
8610344c6c5SChristian Krafft 	mutex_lock(&cpu_mutex);
8620344c6c5SChristian Krafft 
8630344c6c5SChristian Krafft 	for_each_possible_cpu(cpu) {
8640344c6c5SChristian Krafft 		sysdev = get_cpu_sysdev(cpu);
8650344c6c5SChristian Krafft 		sysfs_remove_group(&sysdev->kobj, attrs);
8660344c6c5SChristian Krafft 	}
8670344c6c5SChristian Krafft 
8680344c6c5SChristian Krafft 	mutex_unlock(&cpu_mutex);
8690344c6c5SChristian Krafft }
8700344c6c5SChristian Krafft EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr_group);
8710344c6c5SChristian Krafft 
8720344c6c5SChristian Krafft 
873d3d2176aSDavid Gibson /* NUMA stuff */
874d3d2176aSDavid Gibson 
875d3d2176aSDavid Gibson #ifdef CONFIG_NUMA
876d3d2176aSDavid Gibson static void register_nodes(void)
877d3d2176aSDavid Gibson {
878d3d2176aSDavid Gibson 	int i;
879d3d2176aSDavid Gibson 
8800fc44159SYasunori Goto 	for (i = 0; i < MAX_NUMNODES; i++)
8810fc44159SYasunori Goto 		register_one_node(i);
882d3d2176aSDavid Gibson }
883953039c8SJeremy Kerr 
884953039c8SJeremy Kerr int sysfs_add_device_to_node(struct sys_device *dev, int nid)
885953039c8SJeremy Kerr {
886953039c8SJeremy Kerr 	struct node *node = &node_devices[nid];
887953039c8SJeremy Kerr 	return sysfs_create_link(&node->sysdev.kobj, &dev->kobj,
888953039c8SJeremy Kerr 			kobject_name(&dev->kobj));
889953039c8SJeremy Kerr }
89012654f77SJohannes Berg EXPORT_SYMBOL_GPL(sysfs_add_device_to_node);
891953039c8SJeremy Kerr 
892953039c8SJeremy Kerr void sysfs_remove_device_from_node(struct sys_device *dev, int nid)
893953039c8SJeremy Kerr {
894953039c8SJeremy Kerr 	struct node *node = &node_devices[nid];
895953039c8SJeremy Kerr 	sysfs_remove_link(&node->sysdev.kobj, kobject_name(&dev->kobj));
896953039c8SJeremy Kerr }
89712654f77SJohannes Berg EXPORT_SYMBOL_GPL(sysfs_remove_device_from_node);
898953039c8SJeremy Kerr 
899d3d2176aSDavid Gibson #else
900d3d2176aSDavid Gibson static void register_nodes(void)
901d3d2176aSDavid Gibson {
902d3d2176aSDavid Gibson 	return;
903d3d2176aSDavid Gibson }
904953039c8SJeremy Kerr 
905d3d2176aSDavid Gibson #endif
906d3d2176aSDavid Gibson 
907d3d2176aSDavid Gibson /* Only valid if CPU is present. */
90800bf6e90SStephen Rothwell static ssize_t show_physical_id(struct sys_device *dev,
90900bf6e90SStephen Rothwell 				struct sysdev_attribute *attr, char *buf)
910d3d2176aSDavid Gibson {
911d3d2176aSDavid Gibson 	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
912d3d2176aSDavid Gibson 
913d3d2176aSDavid Gibson 	return sprintf(buf, "%d\n", get_hard_smp_processor_id(cpu->sysdev.id));
914d3d2176aSDavid Gibson }
915d3d2176aSDavid Gibson static SYSDEV_ATTR(physical_id, 0444, show_physical_id, NULL);
916d3d2176aSDavid Gibson 
917d3d2176aSDavid Gibson static int __init topology_init(void)
918d3d2176aSDavid Gibson {
919d3d2176aSDavid Gibson 	int cpu;
920d3d2176aSDavid Gibson 
921d3d2176aSDavid Gibson 	register_nodes();
922d3d2176aSDavid Gibson 	register_cpu_notifier(&sysfs_cpu_nb);
923d3d2176aSDavid Gibson 
9240e551954SKAMEZAWA Hiroyuki 	for_each_possible_cpu(cpu) {
925d3d2176aSDavid Gibson 		struct cpu *c = &per_cpu(cpu_devices, cpu);
926d3d2176aSDavid Gibson 
927d3d2176aSDavid Gibson 		/*
928d3d2176aSDavid Gibson 		 * For now, we just see if the system supports making
929d3d2176aSDavid Gibson 		 * the RTAS calls for CPU hotplug.  But, there may be a
930d3d2176aSDavid Gibson 		 * more comprehensive way to do this for an individual
931d3d2176aSDavid Gibson 		 * CPU.  For instance, the boot cpu might never be valid
932d3d2176aSDavid Gibson 		 * for hotplugging.
933d3d2176aSDavid Gibson 		 */
93472486f1fSSiddha, Suresh B 		if (ppc_md.cpu_die)
93572486f1fSSiddha, Suresh B 			c->hotpluggable = 1;
936d3d2176aSDavid Gibson 
93772486f1fSSiddha, Suresh B 		if (cpu_online(cpu) || c->hotpluggable) {
93876b67ed9SKAMEZAWA Hiroyuki 			register_cpu(c, cpu);
939d3d2176aSDavid Gibson 
940d3d2176aSDavid Gibson 			sysdev_create_file(&c->sysdev, &attr_physical_id);
941d3d2176aSDavid Gibson 		}
942d3d2176aSDavid Gibson 
943d3d2176aSDavid Gibson 		if (cpu_online(cpu))
944d3d2176aSDavid Gibson 			register_cpu_online(cpu);
945d3d2176aSDavid Gibson 	}
946d3d2176aSDavid Gibson 
947d3d2176aSDavid Gibson 	return 0;
948d3d2176aSDavid Gibson }
949e9e77ce8SKevin Corry subsys_initcall(topology_init);
950