| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | #include <linux/sysdev.h> | 
|  | 2 | #include <linux/cpu.h> | 
|  | 3 | #include <linux/smp.h> | 
|  | 4 | #include <linux/percpu.h> | 
|  | 5 | #include <linux/init.h> | 
|  | 6 | #include <linux/sched.h> | 
|  | 7 | #include <linux/module.h> | 
|  | 8 | #include <linux/nodemask.h> | 
|  | 9 | #include <linux/cpumask.h> | 
|  | 10 | #include <linux/notifier.h> | 
|  | 11 |  | 
|  | 12 | #include <asm/current.h> | 
|  | 13 | #include <asm/processor.h> | 
|  | 14 | #include <asm/cputable.h> | 
| Stephen Rothwell | 1ababe1 | 2005-08-03 14:35:25 +1000 | [diff] [blame] | 15 | #include <asm/firmware.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 16 | #include <asm/hvcall.h> | 
|  | 17 | #include <asm/prom.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 | #include <asm/paca.h> | 
|  | 19 | #include <asm/lppaca.h> | 
|  | 20 | #include <asm/machdep.h> | 
| Paul Mackerras | 2249ca9 | 2005-11-07 13:18:13 +1100 | [diff] [blame] | 21 | #include <asm/smp.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 |  | 
|  | 23 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 
|  | 24 |  | 
|  | 25 | /* SMT stuff */ | 
|  | 26 |  | 
|  | 27 | #ifdef CONFIG_PPC_MULTIPLATFORM | 
| Anton Blanchard | 0ddd3e7 | 2006-09-22 20:30:14 +1000 | [diff] [blame] | 28 | /* Time in microseconds we delay before sleeping in the idle loop */ | 
|  | 29 | DEFINE_PER_CPU(unsigned long, smt_snooze_delay) = { 100 }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 |  | 
|  | 31 | static ssize_t store_smt_snooze_delay(struct sys_device *dev, const char *buf, | 
|  | 32 | size_t count) | 
|  | 33 | { | 
|  | 34 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); | 
|  | 35 | ssize_t ret; | 
|  | 36 | unsigned long snooze; | 
|  | 37 |  | 
|  | 38 | ret = sscanf(buf, "%lu", &snooze); | 
|  | 39 | if (ret != 1) | 
|  | 40 | return -EINVAL; | 
|  | 41 |  | 
|  | 42 | per_cpu(smt_snooze_delay, cpu->sysdev.id) = snooze; | 
|  | 43 |  | 
|  | 44 | return count; | 
|  | 45 | } | 
|  | 46 |  | 
|  | 47 | static ssize_t show_smt_snooze_delay(struct sys_device *dev, char *buf) | 
|  | 48 | { | 
|  | 49 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); | 
|  | 50 |  | 
|  | 51 | return sprintf(buf, "%lu\n", per_cpu(smt_snooze_delay, cpu->sysdev.id)); | 
|  | 52 | } | 
|  | 53 |  | 
|  | 54 | static SYSDEV_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay, | 
|  | 55 | store_smt_snooze_delay); | 
|  | 56 |  | 
|  | 57 | /* Only parse OF options if the matching cmdline option was not specified */ | 
|  | 58 | static int smt_snooze_cmdline; | 
|  | 59 |  | 
|  | 60 | static int __init smt_setup(void) | 
|  | 61 | { | 
|  | 62 | struct device_node *options; | 
| Jeremy Kerr | a7f67bd | 2006-07-12 15:35:54 +1000 | [diff] [blame] | 63 | const unsigned int *val; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 64 | unsigned int cpu; | 
|  | 65 |  | 
|  | 66 | if (!cpu_has_feature(CPU_FTR_SMT)) | 
| Anton Blanchard | 69ed332 | 2006-03-28 14:08:39 +1100 | [diff] [blame] | 67 | return -ENODEV; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 68 |  | 
| Stephen Rothwell | 8c8dc32 | 2007-04-24 13:50:55 +1000 | [diff] [blame] | 69 | options = of_find_node_by_path("/options"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 70 | if (!options) | 
| Anton Blanchard | 69ed332 | 2006-03-28 14:08:39 +1100 | [diff] [blame] | 71 | return -ENODEV; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 |  | 
| Stephen Rothwell | e2eb639 | 2007-04-03 22:26:41 +1000 | [diff] [blame] | 73 | val = of_get_property(options, "ibm,smt-snooze-delay", NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | if (!smt_snooze_cmdline && val) { | 
| KAMEZAWA Hiroyuki | 0e55195 | 2006-03-28 14:50:51 -0800 | [diff] [blame] | 75 | for_each_possible_cpu(cpu) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 | per_cpu(smt_snooze_delay, cpu) = *val; | 
|  | 77 | } | 
|  | 78 |  | 
| Stephen Rothwell | 8c8dc32 | 2007-04-24 13:50:55 +1000 | [diff] [blame] | 79 | of_node_put(options); | 
| Anton Blanchard | 69ed332 | 2006-03-28 14:08:39 +1100 | [diff] [blame] | 80 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 | } | 
|  | 82 | __initcall(smt_setup); | 
|  | 83 |  | 
|  | 84 | static int __init setup_smt_snooze_delay(char *str) | 
|  | 85 | { | 
|  | 86 | unsigned int cpu; | 
|  | 87 | int snooze; | 
|  | 88 |  | 
|  | 89 | if (!cpu_has_feature(CPU_FTR_SMT)) | 
|  | 90 | return 1; | 
|  | 91 |  | 
|  | 92 | smt_snooze_cmdline = 1; | 
|  | 93 |  | 
|  | 94 | if (get_option(&str, &snooze)) { | 
| KAMEZAWA Hiroyuki | 0e55195 | 2006-03-28 14:50:51 -0800 | [diff] [blame] | 95 | for_each_possible_cpu(cpu) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 | per_cpu(smt_snooze_delay, cpu) = snooze; | 
|  | 97 | } | 
|  | 98 |  | 
|  | 99 | return 1; | 
|  | 100 | } | 
|  | 101 | __setup("smt-snooze-delay=", setup_smt_snooze_delay); | 
|  | 102 |  | 
| Michael Ellerman | 180a336 | 2005-08-09 11:13:36 +1000 | [diff] [blame] | 103 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 
|  | 104 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | /* | 
|  | 106 | * Enabling PMCs will slow partition context switch times so we only do | 
|  | 107 | * it the first time we write to the PMCs. | 
|  | 108 | */ | 
|  | 109 |  | 
|  | 110 | static DEFINE_PER_CPU(char, pmcs_enabled); | 
|  | 111 |  | 
|  | 112 | void ppc64_enable_pmcs(void) | 
|  | 113 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 | /* Only need to enable them once */ | 
|  | 115 | if (__get_cpu_var(pmcs_enabled)) | 
|  | 116 | return; | 
|  | 117 |  | 
|  | 118 | __get_cpu_var(pmcs_enabled) = 1; | 
|  | 119 |  | 
| Michael Ellerman | 180a336 | 2005-08-09 11:13:36 +1000 | [diff] [blame] | 120 | if (ppc_md.enable_pmcs) | 
|  | 121 | ppc_md.enable_pmcs(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 123 | EXPORT_SYMBOL(ppc64_enable_pmcs); | 
|  | 124 |  | 
|  | 125 | /* XXX convert to rusty's on_one_cpu */ | 
|  | 126 | static unsigned long run_on_cpu(unsigned long cpu, | 
|  | 127 | unsigned long (*func)(unsigned long), | 
|  | 128 | unsigned long arg) | 
|  | 129 | { | 
|  | 130 | cpumask_t old_affinity = current->cpus_allowed; | 
|  | 131 | unsigned long ret; | 
|  | 132 |  | 
|  | 133 | /* should return -EINVAL to userspace */ | 
|  | 134 | if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) | 
|  | 135 | return 0; | 
|  | 136 |  | 
|  | 137 | ret = func(arg); | 
|  | 138 |  | 
|  | 139 | set_cpus_allowed(current, old_affinity); | 
|  | 140 |  | 
|  | 141 | return ret; | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | #define SYSFS_PMCSETUP(NAME, ADDRESS) \ | 
|  | 145 | static unsigned long read_##NAME(unsigned long junk) \ | 
|  | 146 | { \ | 
|  | 147 | return mfspr(ADDRESS); \ | 
|  | 148 | } \ | 
|  | 149 | static unsigned long write_##NAME(unsigned long val) \ | 
|  | 150 | { \ | 
|  | 151 | ppc64_enable_pmcs(); \ | 
|  | 152 | mtspr(ADDRESS, val); \ | 
|  | 153 | return 0; \ | 
|  | 154 | } \ | 
|  | 155 | static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ | 
|  | 156 | { \ | 
|  | 157 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ | 
|  | 158 | unsigned long val = run_on_cpu(cpu->sysdev.id, read_##NAME, 0); \ | 
|  | 159 | return sprintf(buf, "%lx\n", val); \ | 
|  | 160 | } \ | 
|  | 161 | static ssize_t __attribute_used__ \ | 
|  | 162 | store_##NAME(struct sys_device *dev, const char *buf, size_t count) \ | 
|  | 163 | { \ | 
|  | 164 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ | 
|  | 165 | unsigned long val; \ | 
|  | 166 | int ret = sscanf(buf, "%lx", &val); \ | 
|  | 167 | if (ret != 1) \ | 
|  | 168 | return -EINVAL; \ | 
|  | 169 | run_on_cpu(cpu->sysdev.id, write_##NAME, val); \ | 
|  | 170 | return count; \ | 
|  | 171 | } | 
|  | 172 |  | 
| Olof Johansson | 6529c13 | 2007-01-28 21:25:57 -0600 | [diff] [blame] | 173 |  | 
|  | 174 | /* Let's define all possible registers, we'll only hook up the ones | 
|  | 175 | * that are implemented on the current processor | 
|  | 176 | */ | 
|  | 177 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 178 | SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0); | 
|  | 179 | SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1); | 
|  | 180 | SYSFS_PMCSETUP(mmcra, SPRN_MMCRA); | 
|  | 181 | SYSFS_PMCSETUP(pmc1, SPRN_PMC1); | 
|  | 182 | SYSFS_PMCSETUP(pmc2, SPRN_PMC2); | 
|  | 183 | SYSFS_PMCSETUP(pmc3, SPRN_PMC3); | 
|  | 184 | SYSFS_PMCSETUP(pmc4, SPRN_PMC4); | 
|  | 185 | SYSFS_PMCSETUP(pmc5, SPRN_PMC5); | 
|  | 186 | SYSFS_PMCSETUP(pmc6, SPRN_PMC6); | 
|  | 187 | SYSFS_PMCSETUP(pmc7, SPRN_PMC7); | 
|  | 188 | SYSFS_PMCSETUP(pmc8, SPRN_PMC8); | 
|  | 189 | SYSFS_PMCSETUP(purr, SPRN_PURR); | 
| Anton Blanchard | f050982 | 2006-12-08 17:51:13 +1100 | [diff] [blame] | 190 | SYSFS_PMCSETUP(spurr, SPRN_SPURR); | 
| Anton Blanchard | 4c198557 | 2006-12-08 17:46:58 +1100 | [diff] [blame] | 191 | SYSFS_PMCSETUP(dscr, SPRN_DSCR); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 192 |  | 
| Olof Johansson | 25fc530 | 2007-04-18 16:38:21 +1000 | [diff] [blame] | 193 | SYSFS_PMCSETUP(pa6t_pmc0, SPRN_PA6T_PMC0); | 
|  | 194 | SYSFS_PMCSETUP(pa6t_pmc1, SPRN_PA6T_PMC1); | 
|  | 195 | SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2); | 
|  | 196 | SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3); | 
|  | 197 | SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4); | 
|  | 198 | SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5); | 
| Olof Johansson | 6529c13 | 2007-01-28 21:25:57 -0600 | [diff] [blame] | 199 |  | 
|  | 200 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 201 | static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra); | 
| Anton Blanchard | f050982 | 2006-12-08 17:51:13 +1100 | [diff] [blame] | 202 | static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL); | 
| Anton Blanchard | 4c198557 | 2006-12-08 17:46:58 +1100 | [diff] [blame] | 203 | static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr); | 
| Olof Johansson | 6529c13 | 2007-01-28 21:25:57 -0600 | [diff] [blame] | 204 | static SYSDEV_ATTR(purr, 0600, show_purr, store_purr); | 
|  | 205 |  | 
|  | 206 | static struct sysdev_attribute ibm_common_attrs[] = { | 
|  | 207 | _SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0), | 
|  | 208 | _SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1), | 
|  | 209 | }; | 
|  | 210 |  | 
|  | 211 | static struct sysdev_attribute ibm_pmc_attrs[] = { | 
|  | 212 | _SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1), | 
|  | 213 | _SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2), | 
|  | 214 | _SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3), | 
|  | 215 | _SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4), | 
|  | 216 | _SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5), | 
|  | 217 | _SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6), | 
|  | 218 | _SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7), | 
|  | 219 | _SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8), | 
|  | 220 | }; | 
|  | 221 |  | 
|  | 222 | static struct sysdev_attribute pa6t_attrs[] = { | 
|  | 223 | _SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0), | 
|  | 224 | _SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1), | 
|  | 225 | _SYSDEV_ATTR(pmc0, 0600, show_pa6t_pmc0, store_pa6t_pmc0), | 
|  | 226 | _SYSDEV_ATTR(pmc1, 0600, show_pa6t_pmc1, store_pa6t_pmc1), | 
|  | 227 | _SYSDEV_ATTR(pmc2, 0600, show_pa6t_pmc2, store_pa6t_pmc2), | 
|  | 228 | _SYSDEV_ATTR(pmc3, 0600, show_pa6t_pmc3, store_pa6t_pmc3), | 
|  | 229 | _SYSDEV_ATTR(pmc4, 0600, show_pa6t_pmc4, store_pa6t_pmc4), | 
|  | 230 | _SYSDEV_ATTR(pmc5, 0600, show_pa6t_pmc5, store_pa6t_pmc5), | 
|  | 231 | }; | 
|  | 232 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 233 |  | 
|  | 234 | static void register_cpu_online(unsigned int cpu) | 
|  | 235 | { | 
|  | 236 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 
|  | 237 | struct sys_device *s = &c->sysdev; | 
| Olof Johansson | 6529c13 | 2007-01-28 21:25:57 -0600 | [diff] [blame] | 238 | struct sysdev_attribute *attrs, *pmc_attrs; | 
|  | 239 | int i, nattrs; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 240 |  | 
| Stephen Rothwell | ad5cb17 | 2006-11-13 14:46:04 +1100 | [diff] [blame] | 241 | if (!firmware_has_feature(FW_FEATURE_ISERIES) && | 
|  | 242 | cpu_has_feature(CPU_FTR_SMT)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 243 | sysdev_create_file(s, &attr_smt_snooze_delay); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 244 |  | 
|  | 245 | /* PMC stuff */ | 
| Olof Johansson | 6529c13 | 2007-01-28 21:25:57 -0600 | [diff] [blame] | 246 | switch (cur_cpu_spec->pmc_type) { | 
|  | 247 | case PPC_PMC_IBM: | 
|  | 248 | attrs = ibm_common_attrs; | 
|  | 249 | nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute); | 
|  | 250 | pmc_attrs = ibm_pmc_attrs; | 
|  | 251 | break; | 
|  | 252 | case PPC_PMC_PA6T: | 
|  | 253 | /* PA Semi starts counting at PMC0 */ | 
|  | 254 | attrs = pa6t_attrs; | 
|  | 255 | nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute); | 
|  | 256 | pmc_attrs = NULL; | 
|  | 257 | break; | 
|  | 258 | default: | 
|  | 259 | attrs = NULL; | 
|  | 260 | nattrs = 0; | 
|  | 261 | pmc_attrs = NULL; | 
|  | 262 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 263 |  | 
| Olof Johansson | 6529c13 | 2007-01-28 21:25:57 -0600 | [diff] [blame] | 264 | for (i = 0; i < nattrs; i++) | 
|  | 265 | sysdev_create_file(s, &attrs[i]); | 
|  | 266 |  | 
|  | 267 | if (pmc_attrs) | 
|  | 268 | for (i = 0; i < cur_cpu_spec->num_pmcs; i++) | 
|  | 269 | sysdev_create_file(s, &pmc_attrs[i]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 270 |  | 
|  | 271 | if (cpu_has_feature(CPU_FTR_MMCRA)) | 
|  | 272 | sysdev_create_file(s, &attr_mmcra); | 
|  | 273 |  | 
| Michael Neuling | afd0542 | 2006-07-28 13:58:37 +1000 | [diff] [blame] | 274 | if (cpu_has_feature(CPU_FTR_PURR)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 275 | sysdev_create_file(s, &attr_purr); | 
| Anton Blanchard | 4c198557 | 2006-12-08 17:46:58 +1100 | [diff] [blame] | 276 |  | 
| Anton Blanchard | f050982 | 2006-12-08 17:51:13 +1100 | [diff] [blame] | 277 | if (cpu_has_feature(CPU_FTR_SPURR)) | 
|  | 278 | sysdev_create_file(s, &attr_spurr); | 
|  | 279 |  | 
| Anton Blanchard | 4c198557 | 2006-12-08 17:46:58 +1100 | [diff] [blame] | 280 | if (cpu_has_feature(CPU_FTR_DSCR)) | 
|  | 281 | sysdev_create_file(s, &attr_dscr); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 282 | } | 
|  | 283 |  | 
|  | 284 | #ifdef CONFIG_HOTPLUG_CPU | 
|  | 285 | static void unregister_cpu_online(unsigned int cpu) | 
|  | 286 | { | 
|  | 287 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 
|  | 288 | struct sys_device *s = &c->sysdev; | 
| Olof Johansson | 6529c13 | 2007-01-28 21:25:57 -0600 | [diff] [blame] | 289 | struct sysdev_attribute *attrs, *pmc_attrs; | 
|  | 290 | int i, nattrs; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 291 |  | 
| Siddha, Suresh B | 72486f1 | 2006-12-07 02:14:10 +0100 | [diff] [blame] | 292 | BUG_ON(!c->hotpluggable); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 293 |  | 
| Stephen Rothwell | ad5cb17 | 2006-11-13 14:46:04 +1100 | [diff] [blame] | 294 | if (!firmware_has_feature(FW_FEATURE_ISERIES) && | 
|  | 295 | cpu_has_feature(CPU_FTR_SMT)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 296 | sysdev_remove_file(s, &attr_smt_snooze_delay); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 297 |  | 
|  | 298 | /* PMC stuff */ | 
| Olof Johansson | 6529c13 | 2007-01-28 21:25:57 -0600 | [diff] [blame] | 299 | switch (cur_cpu_spec->pmc_type) { | 
|  | 300 | case PPC_PMC_IBM: | 
|  | 301 | attrs = ibm_common_attrs; | 
|  | 302 | nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute); | 
|  | 303 | pmc_attrs = ibm_pmc_attrs; | 
|  | 304 | break; | 
|  | 305 | case PPC_PMC_PA6T: | 
|  | 306 | /* PA Semi starts counting at PMC0 */ | 
|  | 307 | attrs = pa6t_attrs; | 
|  | 308 | nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute); | 
|  | 309 | pmc_attrs = NULL; | 
|  | 310 | break; | 
|  | 311 | default: | 
|  | 312 | attrs = NULL; | 
|  | 313 | nattrs = 0; | 
|  | 314 | pmc_attrs = NULL; | 
|  | 315 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 316 |  | 
| Olof Johansson | 6529c13 | 2007-01-28 21:25:57 -0600 | [diff] [blame] | 317 | for (i = 0; i < nattrs; i++) | 
|  | 318 | sysdev_remove_file(s, &attrs[i]); | 
|  | 319 |  | 
|  | 320 | if (pmc_attrs) | 
|  | 321 | for (i = 0; i < cur_cpu_spec->num_pmcs; i++) | 
|  | 322 | sysdev_remove_file(s, &pmc_attrs[i]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 323 |  | 
|  | 324 | if (cpu_has_feature(CPU_FTR_MMCRA)) | 
|  | 325 | sysdev_remove_file(s, &attr_mmcra); | 
|  | 326 |  | 
| Michael Neuling | afd0542 | 2006-07-28 13:58:37 +1000 | [diff] [blame] | 327 | if (cpu_has_feature(CPU_FTR_PURR)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 328 | sysdev_remove_file(s, &attr_purr); | 
| Anton Blanchard | 4c198557 | 2006-12-08 17:46:58 +1100 | [diff] [blame] | 329 |  | 
| Anton Blanchard | f050982 | 2006-12-08 17:51:13 +1100 | [diff] [blame] | 330 | if (cpu_has_feature(CPU_FTR_SPURR)) | 
|  | 331 | sysdev_remove_file(s, &attr_spurr); | 
|  | 332 |  | 
| Anton Blanchard | 4c198557 | 2006-12-08 17:46:58 +1100 | [diff] [blame] | 333 | if (cpu_has_feature(CPU_FTR_DSCR)) | 
|  | 334 | sysdev_remove_file(s, &attr_dscr); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 335 | } | 
|  | 336 | #endif /* CONFIG_HOTPLUG_CPU */ | 
|  | 337 |  | 
| Chandra Seetharaman | 8c78f30 | 2006-07-30 03:03:35 -0700 | [diff] [blame] | 338 | static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 339 | unsigned long action, void *hcpu) | 
|  | 340 | { | 
|  | 341 | unsigned int cpu = (unsigned int)(long)hcpu; | 
|  | 342 |  | 
|  | 343 | switch (action) { | 
|  | 344 | case CPU_ONLINE: | 
| Rafael J. Wysocki | 8bb7844 | 2007-05-09 02:35:10 -0700 | [diff] [blame] | 345 | case CPU_ONLINE_FROZEN: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 346 | register_cpu_online(cpu); | 
|  | 347 | break; | 
|  | 348 | #ifdef CONFIG_HOTPLUG_CPU | 
|  | 349 | case CPU_DEAD: | 
| Rafael J. Wysocki | 8bb7844 | 2007-05-09 02:35:10 -0700 | [diff] [blame] | 350 | case CPU_DEAD_FROZEN: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 351 | unregister_cpu_online(cpu); | 
|  | 352 | break; | 
|  | 353 | #endif | 
|  | 354 | } | 
|  | 355 | return NOTIFY_OK; | 
|  | 356 | } | 
|  | 357 |  | 
| Chandra Seetharaman | 8c78f30 | 2006-07-30 03:03:35 -0700 | [diff] [blame] | 358 | static struct notifier_block __cpuinitdata sysfs_cpu_nb = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 359 | .notifier_call	= sysfs_cpu_notify, | 
|  | 360 | }; | 
|  | 361 |  | 
| Christian Krafft | 0344c6c | 2006-10-24 18:31:24 +0200 | [diff] [blame] | 362 | static DEFINE_MUTEX(cpu_mutex); | 
|  | 363 |  | 
|  | 364 | int cpu_add_sysdev_attr(struct sysdev_attribute *attr) | 
|  | 365 | { | 
|  | 366 | int cpu; | 
|  | 367 |  | 
|  | 368 | mutex_lock(&cpu_mutex); | 
|  | 369 |  | 
|  | 370 | for_each_possible_cpu(cpu) { | 
|  | 371 | sysdev_create_file(get_cpu_sysdev(cpu), attr); | 
|  | 372 | } | 
|  | 373 |  | 
|  | 374 | mutex_unlock(&cpu_mutex); | 
|  | 375 | return 0; | 
|  | 376 | } | 
|  | 377 | EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr); | 
|  | 378 |  | 
|  | 379 | int cpu_add_sysdev_attr_group(struct attribute_group *attrs) | 
|  | 380 | { | 
|  | 381 | int cpu; | 
|  | 382 | struct sys_device *sysdev; | 
|  | 383 |  | 
|  | 384 | mutex_lock(&cpu_mutex); | 
|  | 385 |  | 
|  | 386 | for_each_possible_cpu(cpu) { | 
|  | 387 | sysdev = get_cpu_sysdev(cpu); | 
|  | 388 | sysfs_create_group(&sysdev->kobj, attrs); | 
|  | 389 | } | 
|  | 390 |  | 
|  | 391 | mutex_unlock(&cpu_mutex); | 
|  | 392 | return 0; | 
|  | 393 | } | 
|  | 394 | EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr_group); | 
|  | 395 |  | 
|  | 396 |  | 
|  | 397 | void cpu_remove_sysdev_attr(struct sysdev_attribute *attr) | 
|  | 398 | { | 
|  | 399 | int cpu; | 
|  | 400 |  | 
|  | 401 | mutex_lock(&cpu_mutex); | 
|  | 402 |  | 
|  | 403 | for_each_possible_cpu(cpu) { | 
|  | 404 | sysdev_remove_file(get_cpu_sysdev(cpu), attr); | 
|  | 405 | } | 
|  | 406 |  | 
|  | 407 | mutex_unlock(&cpu_mutex); | 
|  | 408 | } | 
|  | 409 | EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr); | 
|  | 410 |  | 
|  | 411 | void cpu_remove_sysdev_attr_group(struct attribute_group *attrs) | 
|  | 412 | { | 
|  | 413 | int cpu; | 
|  | 414 | struct sys_device *sysdev; | 
|  | 415 |  | 
|  | 416 | mutex_lock(&cpu_mutex); | 
|  | 417 |  | 
|  | 418 | for_each_possible_cpu(cpu) { | 
|  | 419 | sysdev = get_cpu_sysdev(cpu); | 
|  | 420 | sysfs_remove_group(&sysdev->kobj, attrs); | 
|  | 421 | } | 
|  | 422 |  | 
|  | 423 | mutex_unlock(&cpu_mutex); | 
|  | 424 | } | 
|  | 425 | EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr_group); | 
|  | 426 |  | 
|  | 427 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 428 | /* NUMA stuff */ | 
|  | 429 |  | 
|  | 430 | #ifdef CONFIG_NUMA | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 431 | static void register_nodes(void) | 
|  | 432 | { | 
|  | 433 | int i; | 
|  | 434 |  | 
| Yasunori Goto | 0fc4415 | 2006-06-27 02:53:38 -0700 | [diff] [blame] | 435 | for (i = 0; i < MAX_NUMNODES; i++) | 
|  | 436 | register_one_node(i); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 437 | } | 
| Jeremy Kerr | 953039c | 2006-05-01 12:16:12 -0700 | [diff] [blame] | 438 |  | 
|  | 439 | int sysfs_add_device_to_node(struct sys_device *dev, int nid) | 
|  | 440 | { | 
|  | 441 | struct node *node = &node_devices[nid]; | 
|  | 442 | return sysfs_create_link(&node->sysdev.kobj, &dev->kobj, | 
|  | 443 | kobject_name(&dev->kobj)); | 
|  | 444 | } | 
| Johannes Berg | 12654f7 | 2007-07-05 19:35:33 +1000 | [diff] [blame] | 445 | EXPORT_SYMBOL_GPL(sysfs_add_device_to_node); | 
| Jeremy Kerr | 953039c | 2006-05-01 12:16:12 -0700 | [diff] [blame] | 446 |  | 
|  | 447 | void sysfs_remove_device_from_node(struct sys_device *dev, int nid) | 
|  | 448 | { | 
|  | 449 | struct node *node = &node_devices[nid]; | 
|  | 450 | sysfs_remove_link(&node->sysdev.kobj, kobject_name(&dev->kobj)); | 
|  | 451 | } | 
| Johannes Berg | 12654f7 | 2007-07-05 19:35:33 +1000 | [diff] [blame] | 452 | EXPORT_SYMBOL_GPL(sysfs_remove_device_from_node); | 
| Jeremy Kerr | 953039c | 2006-05-01 12:16:12 -0700 | [diff] [blame] | 453 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 454 | #else | 
|  | 455 | static void register_nodes(void) | 
|  | 456 | { | 
|  | 457 | return; | 
|  | 458 | } | 
| Jeremy Kerr | 953039c | 2006-05-01 12:16:12 -0700 | [diff] [blame] | 459 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 460 | #endif | 
|  | 461 |  | 
|  | 462 | /* Only valid if CPU is present. */ | 
|  | 463 | static ssize_t show_physical_id(struct sys_device *dev, char *buf) | 
|  | 464 | { | 
|  | 465 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); | 
|  | 466 |  | 
|  | 467 | return sprintf(buf, "%d\n", get_hard_smp_processor_id(cpu->sysdev.id)); | 
|  | 468 | } | 
|  | 469 | static SYSDEV_ATTR(physical_id, 0444, show_physical_id, NULL); | 
|  | 470 |  | 
|  | 471 | static int __init topology_init(void) | 
|  | 472 | { | 
|  | 473 | int cpu; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 474 |  | 
|  | 475 | register_nodes(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 476 | register_cpu_notifier(&sysfs_cpu_nb); | 
|  | 477 |  | 
| KAMEZAWA Hiroyuki | 0e55195 | 2006-03-28 14:50:51 -0800 | [diff] [blame] | 478 | for_each_possible_cpu(cpu) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 479 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 
|  | 480 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 481 | /* | 
|  | 482 | * For now, we just see if the system supports making | 
|  | 483 | * the RTAS calls for CPU hotplug.  But, there may be a | 
|  | 484 | * more comprehensive way to do this for an individual | 
|  | 485 | * CPU.  For instance, the boot cpu might never be valid | 
|  | 486 | * for hotplugging. | 
|  | 487 | */ | 
| Siddha, Suresh B | 72486f1 | 2006-12-07 02:14:10 +0100 | [diff] [blame] | 488 | if (ppc_md.cpu_die) | 
|  | 489 | c->hotpluggable = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 490 |  | 
| Siddha, Suresh B | 72486f1 | 2006-12-07 02:14:10 +0100 | [diff] [blame] | 491 | if (cpu_online(cpu) || c->hotpluggable) { | 
| KAMEZAWA Hiroyuki | 76b67ed | 2006-06-27 02:53:41 -0700 | [diff] [blame] | 492 | register_cpu(c, cpu); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 493 |  | 
|  | 494 | sysdev_create_file(&c->sysdev, &attr_physical_id); | 
|  | 495 | } | 
|  | 496 |  | 
|  | 497 | if (cpu_online(cpu)) | 
|  | 498 | register_cpu_online(cpu); | 
|  | 499 | } | 
|  | 500 |  | 
|  | 501 | return 0; | 
|  | 502 | } | 
| Kevin Corry | e9e77ce | 2007-05-03 03:11:49 +1000 | [diff] [blame] | 503 | subsys_initcall(topology_init); |