Home | History | Annotate | Download | only in x86
      1 /**
      2  * @file op_nmi.c
      3  * Setup and handling of NMI PMC interrupts
      4  *
      5  * @remark Copyright 2002 OProfile authors
      6  * @remark Read the file COPYING
      7  *
      8  * @author John Levon
      9  * @author Philippe Elie
     10  */
     11 
     12 #include "oprofile.h"
     13 #include "op_msr.h"
     14 #include "op_apic.h"
     15 #include "op_util.h"
     16 #include "op_x86_model.h"
     17 
     18 static struct op_msrs cpu_msrs[NR_CPUS];
     19 static struct op_x86_model_spec const * model = NULL;
     20 
     21 static struct op_x86_model_spec const * get_model(void)
     22 {
     23 	if (!model) {
     24 		/* pick out our per-model function table */
     25 		switch (sysctl.cpu_type) {
     26 		case CPU_ATHLON:
     27 		case CPU_HAMMER:
     28 			model = &op_athlon_spec;
     29 			break;
     30 		case CPU_P4:
     31 			model = &op_p4_spec;
     32 			break;
     33 #ifdef HT_SUPPORT
     34 		case CPU_P4_HT2:
     35 			model = &op_p4_ht2_spec;
     36 			break;
     37 #endif
     38 		default:
     39 			model = &op_ppro_spec;
     40 			break;
     41 		}
     42 	}
     43 	return model;
     44 }
     45 
     46 asmlinkage void op_do_nmi(struct pt_regs * regs)
     47 {
     48 	uint const cpu = op_cpu_id();
     49 	struct op_msrs const * const msrs = &cpu_msrs[cpu];
     50 
     51 	model->check_ctrs(cpu, msrs, regs);
     52 }
     53 
     54 /* ---------------- PMC setup ------------------ */
     55 
     56 static void pmc_setup_ctr(void * dummy)
     57 {
     58 	uint const cpu = op_cpu_id();
     59 	struct op_msrs const * const msrs = &cpu_msrs[cpu];
     60 	get_model()->setup_ctrs(msrs);
     61 }
     62 
     63 
     64 static int pmc_setup_all(void)
     65 {
     66 	if (smp_call_function(pmc_setup_ctr, NULL, 0, 1))
     67 		return -EFAULT;
     68 	pmc_setup_ctr(NULL);
     69 	return 0;
     70 }
     71 
     72 
     73 static void pmc_start(void * info)
     74 {
     75 	uint const cpu = op_cpu_id();
     76 	struct op_msrs const * const msrs = &cpu_msrs[cpu];
     77 
     78 	if (info && (*((uint *)info) != cpu))
     79 		return;
     80 
     81 	get_model()->start(msrs);
     82 }
     83 
     84 
     85 static void pmc_stop(void * info)
     86 {
     87 	uint const cpu = op_cpu_id();
     88 	struct op_msrs const * const msrs = &cpu_msrs[cpu];
     89 
     90 	if (info && (*((uint *)info) != cpu))
     91 		return;
     92 
     93 	get_model()->stop(msrs);
     94 }
     95 
     96 
     97 static void pmc_select_start(uint cpu)
     98 {
     99 	if (cpu == op_cpu_id())
    100 		pmc_start(NULL);
    101 	else
    102 		smp_call_function(pmc_start, &cpu, 0, 1);
    103 }
    104 
    105 
    106 static void pmc_select_stop(uint cpu)
    107 {
    108 	if (cpu == op_cpu_id())
    109 		pmc_stop(NULL);
    110 	else
    111 		smp_call_function(pmc_stop, &cpu, 0, 1);
    112 }
    113 
    114 
    115 static void pmc_start_all(void)
    116 {
    117 	int cpu, i;
    118 
    119 	for (cpu = 0 ; cpu < smp_num_cpus; cpu++) {
    120 		struct _oprof_data * data = &oprof_data[cpu];
    121 
    122 		for (i = 0 ; i < get_model()->num_counters ; ++i) {
    123 			if (sysctl.ctr[i].enabled)
    124 				data->ctr_count[i] = sysctl.ctr[i].count;
    125 			else
    126 				data->ctr_count[i] = 0;
    127 		}
    128 	}
    129 
    130 	install_nmi();
    131 	smp_call_function(pmc_start, NULL, 0, 1);
    132 	pmc_start(NULL);
    133 }
    134 
    135 
    136 static void pmc_stop_all(void)
    137 {
    138 	smp_call_function(pmc_stop, NULL, 0, 1);
    139 	pmc_stop(NULL);
    140 	restore_nmi();
    141 }
    142 
    143 
    144 static int pmc_check_params(void)
    145 {
    146 	int i;
    147 	int enabled = 0;
    148 
    149 	for (i = 0; i < get_model()->num_counters; i++) {
    150 		if (!sysctl.ctr[i].enabled)
    151 			continue;
    152 
    153 		enabled = 1;
    154 
    155 		if (!sysctl.ctr[i].user && !sysctl.ctr[i].kernel) {
    156 			printk(KERN_ERR "oprofile: neither kernel nor user "
    157 			       "set for counter %d\n", i);
    158 			return -EINVAL;
    159 		}
    160 
    161 		if (check_range(sysctl.ctr[i].count, 1, OP_MAX_PERF_COUNT,
    162 			"ctr count value %d not in range (%d %ld)\n"))
    163 			return -EINVAL;
    164 
    165 	}
    166 
    167 	if (!enabled) {
    168 		printk(KERN_ERR "oprofile: no counters have been enabled.\n");
    169 		return -EINVAL;
    170 	}
    171 
    172 	return 0;
    173 }
    174 
    175 
    176 static void free_msr_group(struct op_msr_group * group)
    177 {
    178 	if (group->addrs)
    179 		kfree(group->addrs);
    180 	if (group->saved)
    181 		kfree(group->saved);
    182 	group->addrs = NULL;
    183 	group->saved = NULL;
    184 }
    185 
    186 
    187 static void pmc_save_registers(void * dummy)
    188 {
    189 	uint i;
    190 	uint const cpu = op_cpu_id();
    191 	uint const nr_ctrs = get_model()->num_counters;
    192 	uint const nr_ctrls = get_model()->num_controls;
    193 	struct op_msr_group * counters = &cpu_msrs[cpu].counters;
    194 	struct op_msr_group * controls = &cpu_msrs[cpu].controls;
    195 
    196 	counters->addrs = NULL;
    197 	counters->saved = NULL;
    198 	controls->addrs = NULL;
    199 	controls->saved = NULL;
    200 
    201 	counters->addrs = kmalloc(nr_ctrs * sizeof(uint), GFP_KERNEL);
    202 	if (!counters->addrs)
    203 		goto fault;
    204 
    205 	counters->saved = kmalloc(
    206 		nr_ctrs * sizeof(struct op_saved_msr), GFP_KERNEL);
    207 	if (!counters->saved)
    208 		goto fault;
    209 
    210 	controls->addrs = kmalloc(nr_ctrls * sizeof(uint), GFP_KERNEL);
    211 	if (!controls->addrs)
    212 		goto fault;
    213 
    214 	controls->saved = kmalloc(
    215 		nr_ctrls * sizeof(struct op_saved_msr), GFP_KERNEL);
    216 	if (!controls->saved)
    217 		goto fault;
    218 
    219 	model->fill_in_addresses(&cpu_msrs[cpu]);
    220 
    221 	for (i = 0; i < nr_ctrs; ++i) {
    222 		rdmsr(counters->addrs[i],
    223 			counters->saved[i].low,
    224 			counters->saved[i].high);
    225 	}
    226 
    227 	for (i = 0; i < nr_ctrls; ++i) {
    228 		rdmsr(controls->addrs[i],
    229 			controls->saved[i].low,
    230 			controls->saved[i].high);
    231 	}
    232 	return;
    233 
    234 fault:
    235 	free_msr_group(counters);
    236 	free_msr_group(controls);
    237 }
    238 
    239 
    240 static void pmc_restore_registers(void * dummy)
    241 {
    242 	uint i;
    243 	uint const cpu = op_cpu_id();
    244 	uint const nr_ctrs = get_model()->num_counters;
    245 	uint const nr_ctrls = get_model()->num_controls;
    246 	struct op_msr_group * counters = &cpu_msrs[cpu].counters;
    247 	struct op_msr_group * controls = &cpu_msrs[cpu].controls;
    248 
    249 	if (controls->addrs) {
    250 		for (i = 0; i < nr_ctrls; ++i) {
    251 			wrmsr(controls->addrs[i],
    252 				controls->saved[i].low,
    253 				controls->saved[i].high);
    254 		}
    255 	}
    256 
    257 	if (counters->addrs) {
    258 		for (i = 0; i < nr_ctrs; ++i) {
    259 			wrmsr(counters->addrs[i],
    260 				counters->saved[i].low,
    261 				counters->saved[i].high);
    262 		}
    263 	}
    264 
    265 	free_msr_group(counters);
    266 	free_msr_group(controls);
    267 }
    268 
    269 
    270 static int pmc_init(void)
    271 {
    272 	int err = 0;
    273 
    274 	if ((err = smp_call_function(pmc_save_registers, NULL, 0, 1)))
    275 		goto out;
    276 
    277 	pmc_save_registers(NULL);
    278 
    279 	if ((err = apic_setup()))
    280 		goto out_restore;
    281 
    282 	if ((err = smp_call_function(lvtpc_apic_setup, NULL, 0, 1))) {
    283 		lvtpc_apic_restore(NULL);
    284 		goto out_restore;
    285 	}
    286 
    287 out:
    288 	return err;
    289 out_restore:
    290 	smp_call_function(pmc_restore_registers, NULL, 0, 1);
    291 	pmc_restore_registers(NULL);
    292 	goto out;
    293 }
    294 
    295 
    296 static void pmc_deinit(void)
    297 {
    298 	smp_call_function(lvtpc_apic_restore, NULL, 0, 1);
    299 	lvtpc_apic_restore(NULL);
    300 
    301 	apic_restore();
    302 
    303 	smp_call_function(pmc_restore_registers, NULL, 0, 1);
    304 	pmc_restore_registers(NULL);
    305 }
    306 
    307 
    308 static char * names[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8"};
    309 
    310 static int pmc_add_sysctls(ctl_table * next)
    311 {
    312 	ctl_table * start = next;
    313 	ctl_table * tab;
    314 	int i, j;
    315 
    316 	/* now init the sysctls */
    317 	for (i=0; i < get_model()->num_counters; i++) {
    318 		next->ctl_name = 1;
    319 		next->procname = names[i];
    320 		next->mode = 0755;
    321 
    322 		if (!(tab = kmalloc(sizeof(ctl_table)*7, GFP_KERNEL)))
    323 			goto cleanup;
    324 
    325 		next->child = tab;
    326 
    327 		memset(tab, 0, sizeof(ctl_table)*7);
    328 		tab[0] = ((ctl_table) { 1, "enabled", &sysctl_parms.ctr[i].enabled, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
    329 		tab[1] = ((ctl_table) { 1, "event", &sysctl_parms.ctr[i].event, sizeof(int), 0644, NULL, lproc_dointvec, NULL,  });
    330 		tab[2] = ((ctl_table) { 1, "count", &sysctl_parms.ctr[i].count, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
    331 		tab[3] = ((ctl_table) { 1, "unit_mask", &sysctl_parms.ctr[i].unit_mask, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
    332 		tab[4] = ((ctl_table) { 1, "kernel", &sysctl_parms.ctr[i].kernel, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
    333 		tab[5] = ((ctl_table) { 1, "user", &sysctl_parms.ctr[i].user, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
    334 		next++;
    335 	}
    336 
    337 	return 0;
    338 
    339 cleanup:
    340 	next = start;
    341 	for (j = 0; j < i; j++) {
    342 		kfree(next->child);
    343 		next++;
    344 	}
    345 	return -EFAULT;
    346 }
    347 
    348 
    349 static void pmc_remove_sysctls(ctl_table * next)
    350 {
    351 	int i;
    352 	for (i=0; i < get_model()->num_counters; i++) {
    353 		kfree(next->child);
    354 		next++;
    355 	}
    356 }
    357 
    358 
    359 static struct op_int_operations op_nmi_ops = {
    360 	init: pmc_init,
    361 	deinit: pmc_deinit,
    362 	add_sysctls: pmc_add_sysctls,
    363 	remove_sysctls: pmc_remove_sysctls,
    364 	check_params: pmc_check_params,
    365 	setup: pmc_setup_all,
    366 	start: pmc_start_all,
    367 	stop: pmc_stop_all,
    368 	start_cpu: pmc_select_start,
    369 	stop_cpu: pmc_select_stop,
    370 };
    371 
    372 
    373 struct op_int_operations const * op_int_interface()
    374 {
    375 	return &op_nmi_ops;
    376 }
    377