Deleted Added
full compact
hwpmc_ppro.c (184205) hwpmc_ppro.c (184802)
1/*-
2 * Copyright (c) 2003-2005,2008 Joseph Koshy
3 * Copyright (c) 2007 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * Portions of this software were developed by A. Joseph Koshy under
7 * sponsorship from the FreeBSD Foundation and Google, Inc.
8 *

--- 15 unchanged lines hidden (view full) ---

24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2003-2005,2008 Joseph Koshy
3 * Copyright (c) 2007 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * Portions of this software were developed by A. Joseph Koshy under
7 * sponsorship from the FreeBSD Foundation and Google, Inc.
8 *

--- 15 unchanged lines hidden (view full) ---

24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_ppro.c 184205 2008-10-23 15:53:51Z des $");
32__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_ppro.c 184802 2008-11-09 17:37:54Z jkoshy $");
33
34#include <sys/param.h>
35#include <sys/lock.h>
36#include <sys/mutex.h>
37#include <sys/pmc.h>
38#include <sys/pmckern.h>
39#include <sys/smp.h>
40#include <sys/systm.h>

--- 27 unchanged lines hidden (view full) ---

68struct p6pmc_descr {
69 struct pmc_descr pm_descr; /* common information */
70 uint32_t pm_pmc_msr;
71 uint32_t pm_evsel_msr;
72};
73
74static struct p6pmc_descr p6_pmcdesc[P6_NPMCS] = {
75
33
34#include <sys/param.h>
35#include <sys/lock.h>
36#include <sys/mutex.h>
37#include <sys/pmc.h>
38#include <sys/pmckern.h>
39#include <sys/smp.h>
40#include <sys/systm.h>

--- 27 unchanged lines hidden (view full) ---

68struct p6pmc_descr {
69 struct pmc_descr pm_descr; /* common information */
70 uint32_t pm_pmc_msr;
71 uint32_t pm_evsel_msr;
72};
73
74static struct p6pmc_descr p6_pmcdesc[P6_NPMCS] = {
75
76 /* TSC */
77 {
78 .pm_descr =
79 {
80 .pd_name = "TSC",
81 .pd_class = PMC_CLASS_TSC,
82 .pd_caps = PMC_CAP_READ,
83 .pd_width = 64
84 },
85 .pm_pmc_msr = 0x10,
86 .pm_evsel_msr = ~0
87 },
88
89#define P6_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | PMC_CAP_SYSTEM | \
90 PMC_CAP_EDGE | PMC_CAP_THRESHOLD | PMC_CAP_READ | PMC_CAP_WRITE | \
91 PMC_CAP_INVERT | PMC_CAP_QUALIFIER)
92
93 /* PMC 0 */
94 {
95 .pm_descr =
96 {

--- 204 unchanged lines hidden (view full) ---

301 *
302 * [common stuff]
303 * [flags for maintaining PMC start/stop state]
304 * [3 struct pmc_hw pointers]
305 * [3 struct pmc_hw structures]
306 */
307
308struct p6_cpu {
76#define P6_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | PMC_CAP_SYSTEM | \
77 PMC_CAP_EDGE | PMC_CAP_THRESHOLD | PMC_CAP_READ | PMC_CAP_WRITE | \
78 PMC_CAP_INVERT | PMC_CAP_QUALIFIER)
79
80 /* PMC 0 */
81 {
82 .pm_descr =
83 {

--- 204 unchanged lines hidden (view full) ---

288 *
289 * [common stuff]
290 * [flags for maintaining PMC start/stop state]
291 * [3 struct pmc_hw pointers]
292 * [3 struct pmc_hw structures]
293 */
294
295struct p6_cpu {
309 struct pmc_cpu pc_common;
310 struct pmc_hw *pc_hwpmcs[P6_NPMCS];
311 struct pmc_hw pc_p6pmcs[P6_NPMCS];
312 uint32_t pc_state;
313};
314
296 struct pmc_hw pc_p6pmcs[P6_NPMCS];
297 uint32_t pc_state;
298};
299
300static struct p6_cpu **p6_pcpu;
301
315/*
316 * If CTR1 is active, we need to keep the 'EN' bit if CTR0 set,
317 * with the rest of CTR0 being zero'ed out.
318 */
319#define P6_SYNC_CTR_STATE(PC) do { \
320 uint32_t _config, _enable; \
321 _enable = 0; \
322 if ((PC)->pc_state & 0x02) \

--- 10 unchanged lines hidden (view full) ---

333 (PC)->pc_state |= (1 << ((RI)-1)); \
334 } while (0)
335
336#define P6_MARK_STOPPED(PC,RI) do { \
337 (PC)->pc_state &= ~(1<< ((RI)-1)); \
338 } while (0)
339
340static int
302/*
303 * If CTR1 is active, we need to keep the 'EN' bit if CTR0 set,
304 * with the rest of CTR0 being zero'ed out.
305 */
306#define P6_SYNC_CTR_STATE(PC) do { \
307 uint32_t _config, _enable; \
308 _enable = 0; \
309 if ((PC)->pc_state & 0x02) \

--- 10 unchanged lines hidden (view full) ---

320 (PC)->pc_state |= (1 << ((RI)-1)); \
321 } while (0)
322
323#define P6_MARK_STOPPED(PC,RI) do { \
324 (PC)->pc_state &= ~(1<< ((RI)-1)); \
325 } while (0)
326
327static int
341p6_init(int cpu)
328p6_pcpu_init(struct pmc_mdep *md, int cpu)
342{
329{
343 int n;
344 struct p6_cpu *pcs;
330 int first_ri, n;
331 struct p6_cpu *p6c;
332 struct pmc_cpu *pc;
345 struct pmc_hw *phw;
346
347 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
348 ("[p6,%d] bad cpu %d", __LINE__, cpu));
349
350 PMCDBG(MDP,INI,0,"p6-init cpu=%d", cpu);
351
333 struct pmc_hw *phw;
334
335 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
336 ("[p6,%d] bad cpu %d", __LINE__, cpu));
337
338 PMCDBG(MDP,INI,0,"p6-init cpu=%d", cpu);
339
352 pcs = malloc(sizeof(struct p6_cpu), M_PMC,
353 M_WAITOK|M_ZERO);
340 p6c = malloc(sizeof (struct p6_cpu), M_PMC, M_WAITOK|M_ZERO);
341 pc = pmc_pcpu[cpu];
354
342
355 phw = pcs->pc_p6pmcs;
343 KASSERT(pc != NULL, ("[p6,%d] cpu %d null per-cpu", __LINE__, cpu));
356
344
345 phw = p6c->pc_p6pmcs;
346 p6_pcpu[cpu] = p6c;
347
348 first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_P6].pcd_ri;
349
357 for (n = 0; n < P6_NPMCS; n++, phw++) {
358 phw->phw_state = PMC_PHW_FLAG_IS_ENABLED |
359 PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(n);
360 phw->phw_pmc = NULL;
350 for (n = 0; n < P6_NPMCS; n++, phw++) {
351 phw->phw_state = PMC_PHW_FLAG_IS_ENABLED |
352 PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(n);
353 phw->phw_pmc = NULL;
361 pcs->pc_hwpmcs[n] = phw;
354 pc->pc_hwpmcs[n + first_ri] = phw;
362 }
363
355 }
356
364 /* Mark the TSC as shareable */
365 pcs->pc_hwpmcs[0]->phw_state |= PMC_PHW_FLAG_IS_SHAREABLE;
366
367 pmc_pcpu[cpu] = (struct pmc_cpu *) pcs;
368
369 return 0;
357 return (0);
370}
371
372static int
358}
359
360static int
373p6_cleanup(int cpu)
361p6_pcpu_fini(struct pmc_mdep *md, int cpu)
374{
362{
375 struct pmc_cpu *pcs;
363 int first_ri, n;
364 struct p6_cpu *p6c;
365 struct pmc_cpu *pc;
376
377 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
378 ("[p6,%d] bad cpu %d", __LINE__, cpu));
379
380 PMCDBG(MDP,INI,0,"p6-cleanup cpu=%d", cpu);
381
366
367 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
368 ("[p6,%d] bad cpu %d", __LINE__, cpu));
369
370 PMCDBG(MDP,INI,0,"p6-cleanup cpu=%d", cpu);
371
382 if ((pcs = pmc_pcpu[cpu]) != NULL)
383 free(pcs, M_PMC);
384 pmc_pcpu[cpu] = NULL;
372 p6c = p6_pcpu[cpu];
373 p6_pcpu[cpu] = NULL;
385
374
386 return 0;
387}
375 KASSERT(p6c != NULL, ("[p6,%d] null pcpu", __LINE__));
388
376
389static int
390p6_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
391{
392 (void) pc;
377 free(p6c, M_PMC);
393
378
394 PMCDBG(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp,
395 pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS);
379 first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_P6].pcd_ri;
380 pc = pmc_pcpu[cpu];
381 for (n = 0; n < P6_NPMCS; n++)
382 pc->pc_hwpmcs[n + first_ri] = NULL;
396
383
397 /* allow the RDPMC instruction if needed */
398 if (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS)
399 load_cr4(rcr4() | CR4_PCE);
400
401 PMCDBG(MDP,SWI,1, "cr4=0x%x", rcr4());
402
403 return 0;
384 return (0);
404}
405
406static int
385}
386
387static int
407p6_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
408{
409 (void) pc;
410 (void) pp; /* can be NULL */
411
412 PMCDBG(MDP,SWO,1, "pc=%p pp=%p cr4=0x%x", pc, pp, rcr4());
413
414 /* always turn off the RDPMC instruction */
415 load_cr4(rcr4() & ~CR4_PCE);
416
417 return 0;
418}
419
420static int
421p6_read_pmc(int cpu, int ri, pmc_value_t *v)
422{
388p6_read_pmc(int cpu, int ri, pmc_value_t *v)
389{
423 struct pmc_hw *phw;
424 struct pmc *pm;
425 struct p6pmc_descr *pd;
426 pmc_value_t tmp;
427
390 struct pmc *pm;
391 struct p6pmc_descr *pd;
392 pmc_value_t tmp;
393
428 phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
429 pm = phw->phw_pmc;
430 pd = &p6_pmcdesc[ri];
394 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
395 ("[p6,%d] illegal cpu value %d", __LINE__, cpu));
396 KASSERT(ri >= 0 && ri < P6_NPMCS,
397 ("[p6,%d] illegal row-index %d", __LINE__, ri));
431
398
399 pm = p6_pcpu[cpu]->pc_p6pmcs[ri].phw_pmc;
400 pd = &p6_pmcdesc[ri];
401
432 KASSERT(pm,
433 ("[p6,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri));
434
402 KASSERT(pm,
403 ("[p6,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri));
404
435 if (pd->pm_descr.pd_class == PMC_CLASS_TSC) {
436 *v = rdtsc();
437 return 0;
438 }
439
440 tmp = rdmsr(pd->pm_pmc_msr) & P6_PERFCTR_READ_MASK;
441 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
442 *v = P6_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp);
443 else
444 *v = tmp;
445
446 PMCDBG(MDP,REA,1, "p6-read cpu=%d ri=%d msr=0x%x -> v=%jx", cpu, ri,
447 pd->pm_pmc_msr, *v);
448
405 tmp = rdmsr(pd->pm_pmc_msr) & P6_PERFCTR_READ_MASK;
406 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
407 *v = P6_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp);
408 else
409 *v = tmp;
410
411 PMCDBG(MDP,REA,1, "p6-read cpu=%d ri=%d msr=0x%x -> v=%jx", cpu, ri,
412 pd->pm_pmc_msr, *v);
413
449 return 0;
414 return (0);
450}
451
452static int
453p6_write_pmc(int cpu, int ri, pmc_value_t v)
454{
415}
416
417static int
418p6_write_pmc(int cpu, int ri, pmc_value_t v)
419{
455 struct pmc_hw *phw;
456 struct pmc *pm;
457 struct p6pmc_descr *pd;
458
420 struct pmc *pm;
421 struct p6pmc_descr *pd;
422
459 phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
460 pm = phw->phw_pmc;
461 pd = &p6_pmcdesc[ri];
423 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
424 ("[p6,%d] illegal cpu value %d", __LINE__, cpu));
425 KASSERT(ri >= 0 && ri < P6_NPMCS,
426 ("[p6,%d] illegal row-index %d", __LINE__, ri));
462
427
428 pm = p6_pcpu[cpu]->pc_p6pmcs[ri].phw_pmc;
429 pd = &p6_pmcdesc[ri];
430
463 KASSERT(pm,
464 ("[p6,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri));
465
431 KASSERT(pm,
432 ("[p6,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri));
433
466 if (pd->pm_descr.pd_class == PMC_CLASS_TSC)
467 return 0;
468
469 PMCDBG(MDP,WRI,1, "p6-write cpu=%d ri=%d msr=0x%x v=%jx", cpu, ri,
470 pd->pm_pmc_msr, v);
471
472 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
473 v = P6_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
474
475 wrmsr(pd->pm_pmc_msr, v & P6_PERFCTR_WRITE_MASK);
476
434 PMCDBG(MDP,WRI,1, "p6-write cpu=%d ri=%d msr=0x%x v=%jx", cpu, ri,
435 pd->pm_pmc_msr, v);
436
437 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
438 v = P6_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
439
440 wrmsr(pd->pm_pmc_msr, v & P6_PERFCTR_WRITE_MASK);
441
477 return 0;
442 return (0);
478}
479
480static int
481p6_config_pmc(int cpu, int ri, struct pmc *pm)
482{
443}
444
445static int
446p6_config_pmc(int cpu, int ri, struct pmc *pm)
447{
483 struct pmc_hw *phw;
448 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
449 ("[p6,%d] illegal CPU %d", __LINE__, cpu));
484
450
451 KASSERT(ri >= 0 && ri < P6_NPMCS,
452 ("[p6,%d] illegal row-index %d", __LINE__, ri));
453
485 PMCDBG(MDP,CFG,1, "p6-config cpu=%d ri=%d pm=%p", cpu, ri, pm);
486
454 PMCDBG(MDP,CFG,1, "p6-config cpu=%d ri=%d pm=%p", cpu, ri, pm);
455
487 phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
488 phw->phw_pmc = pm;
456 KASSERT(p6_pcpu[cpu] != NULL, ("[p6,%d] null per-cpu %d", __LINE__,
457 cpu));
489
458
490 return 0;
459 p6_pcpu[cpu]->pc_p6pmcs[ri].phw_pmc = pm;
460
461 return (0);
491}
492
493/*
494 * Retrieve a configured PMC pointer from hardware state.
495 */
496
497static int
498p6_get_config(int cpu, int ri, struct pmc **ppm)
499{
462}
463
464/*
465 * Retrieve a configured PMC pointer from hardware state.
466 */
467
468static int
469p6_get_config(int cpu, int ri, struct pmc **ppm)
470{
500 *ppm = pmc_pcpu[cpu]->pc_hwpmcs[ri]->phw_pmc;
501
471
502 return 0;
472 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
473 ("[p6,%d] illegal CPU %d", __LINE__, cpu));
474 KASSERT(ri >= 0 && ri < P6_NPMCS,
475 ("[p6,%d] illegal row-index %d", __LINE__, ri));
476
477 *ppm = p6_pcpu[cpu]->pc_p6pmcs[ri].phw_pmc;
478
479 return (0);
503}
504
505
506/*
507 * A pmc may be allocated to a given row index if:
508 * - the event is valid for this CPU
509 * - the event is valid for this counter index
510 */

--- 5 unchanged lines hidden (view full) ---

516 uint32_t allowed_unitmask, caps, config, unitmask;
517 const struct p6pmc_descr *pd;
518 const struct p6_event_descr *pevent;
519 enum pmc_event ev;
520
521 (void) cpu;
522
523 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
480}
481
482
483/*
484 * A pmc may be allocated to a given row index if:
485 * - the event is valid for this CPU
486 * - the event is valid for this counter index
487 */

--- 5 unchanged lines hidden (view full) ---

493 uint32_t allowed_unitmask, caps, config, unitmask;
494 const struct p6pmc_descr *pd;
495 const struct p6_event_descr *pevent;
496 enum pmc_event ev;
497
498 (void) cpu;
499
500 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
524 ("[p4,%d] illegal CPU %d", __LINE__, cpu));
501 ("[p6,%d] illegal CPU %d", __LINE__, cpu));
525 KASSERT(ri >= 0 && ri < P6_NPMCS,
502 KASSERT(ri >= 0 && ri < P6_NPMCS,
526 ("[p4,%d] illegal row-index value %d", __LINE__, ri));
503 ("[p6,%d] illegal row-index value %d", __LINE__, ri));
527
528 pd = &p6_pmcdesc[ri];
529
530 PMCDBG(MDP,ALL,1, "p6-allocate ri=%d class=%d pmccaps=0x%x "
531 "reqcaps=0x%x", ri, pd->pm_descr.pd_class, pd->pm_descr.pd_caps,
532 pm->pm_caps);
533
534 /* check class */
535 if (pd->pm_descr.pd_class != a->pm_class)
504
505 pd = &p6_pmcdesc[ri];
506
507 PMCDBG(MDP,ALL,1, "p6-allocate ri=%d class=%d pmccaps=0x%x "
508 "reqcaps=0x%x", ri, pd->pm_descr.pd_class, pd->pm_descr.pd_caps,
509 pm->pm_caps);
510
511 /* check class */
512 if (pd->pm_descr.pd_class != a->pm_class)
536 return EINVAL;
513 return (EINVAL);
537
538 /* check requested capabilities */
539 caps = a->pm_caps;
540 if ((pd->pm_descr.pd_caps & caps) != caps)
514
515 /* check requested capabilities */
516 caps = a->pm_caps;
517 if ((pd->pm_descr.pd_caps & caps) != caps)
541 return EPERM;
518 return (EPERM);
542
519
543 if (pd->pm_descr.pd_class == PMC_CLASS_TSC) {
544 /* TSC's are always allocated in system-wide counting mode */
545 if (a->pm_ev != PMC_EV_TSC_TSC ||
546 a->pm_mode != PMC_MODE_SC)
547 return EINVAL;
548 return 0;
549 }
550
551 /*
552 * P6 class events
553 */
554
555 ev = pm->pm_event;
556
557 if (ev < PMC_EV_P6_FIRST || ev > PMC_EV_P6_LAST)
520 ev = pm->pm_event;
521
522 if (ev < PMC_EV_P6_FIRST || ev > PMC_EV_P6_LAST)
558 return EINVAL;
523 return (EINVAL);
559
560 if ((pevent = p6_find_event(ev)) == NULL)
524
525 if ((pevent = p6_find_event(ev)) == NULL)
561 return ESRCH;
526 return (ESRCH);
562
563 if (!P6_EVENT_VALID_FOR_CPU(pevent, p6_cputype) ||
564 !P6_EVENT_VALID_FOR_CTR(pevent, (ri-1)))
527
528 if (!P6_EVENT_VALID_FOR_CPU(pevent, p6_cputype) ||
529 !P6_EVENT_VALID_FOR_CTR(pevent, (ri-1)))
565 return EINVAL;
530 return (EINVAL);
566
567 /* For certain events, Pentium M differs from the stock P6 */
568 allowed_unitmask = 0;
569 if (p6_cputype == PMC_CPU_INTEL_PM) {
570 if (ev == PMC_EV_P6_L2_LD || ev == PMC_EV_P6_L2_LINES_IN ||
571 ev == PMC_EV_P6_L2_LINES_OUT)
572 allowed_unitmask = P6_EVSEL_TO_UMASK(0x3F);
573 else if (ev == PMC_EV_P6_L2_M_LINES_OUTM)
574 allowed_unitmask = P6_EVSEL_TO_UMASK(0x30);
575 } else
576 allowed_unitmask = P6_EVSEL_TO_UMASK(pevent->pm_unitmask);
577
578 unitmask = a->pm_md.pm_ppro.pm_ppro_config & P6_EVSEL_UMASK_MASK;
579 if (unitmask & ~allowed_unitmask) /* disallow reserved bits */
531
532 /* For certain events, Pentium M differs from the stock P6 */
533 allowed_unitmask = 0;
534 if (p6_cputype == PMC_CPU_INTEL_PM) {
535 if (ev == PMC_EV_P6_L2_LD || ev == PMC_EV_P6_L2_LINES_IN ||
536 ev == PMC_EV_P6_L2_LINES_OUT)
537 allowed_unitmask = P6_EVSEL_TO_UMASK(0x3F);
538 else if (ev == PMC_EV_P6_L2_M_LINES_OUTM)
539 allowed_unitmask = P6_EVSEL_TO_UMASK(0x30);
540 } else
541 allowed_unitmask = P6_EVSEL_TO_UMASK(pevent->pm_unitmask);
542
543 unitmask = a->pm_md.pm_ppro.pm_ppro_config & P6_EVSEL_UMASK_MASK;
544 if (unitmask & ~allowed_unitmask) /* disallow reserved bits */
580 return EINVAL;
545 return (EINVAL);
581
582 if (ev == PMC_EV_P6_MMX_UOPS_EXEC) /* hardcoded mask */
583 unitmask = P6_EVSEL_TO_UMASK(0x0F);
584
585 config = 0;
586
587 config |= P6_EVSEL_EVENT_SELECT(pevent->pm_evsel);
588

--- 18 unchanged lines hidden (view full) ---

607 config |= P6_EVSEL_INV;
608 if (caps & PMC_CAP_INTERRUPT)
609 config |= P6_EVSEL_INT;
610
611 pm->pm_md.pm_ppro.pm_ppro_evsel = config;
612
613 PMCDBG(MDP,ALL,2, "p6-allocate config=0x%x", config);
614
546
547 if (ev == PMC_EV_P6_MMX_UOPS_EXEC) /* hardcoded mask */
548 unitmask = P6_EVSEL_TO_UMASK(0x0F);
549
550 config = 0;
551
552 config |= P6_EVSEL_EVENT_SELECT(pevent->pm_evsel);
553

--- 18 unchanged lines hidden (view full) ---

572 config |= P6_EVSEL_INV;
573 if (caps & PMC_CAP_INTERRUPT)
574 config |= P6_EVSEL_INT;
575
576 pm->pm_md.pm_ppro.pm_ppro_evsel = config;
577
578 PMCDBG(MDP,ALL,2, "p6-allocate config=0x%x", config);
579
615 return 0;
580 return (0);
616}
617
618static int
619p6_release_pmc(int cpu, int ri, struct pmc *pm)
620{
581}
582
583static int
584p6_release_pmc(int cpu, int ri, struct pmc *pm)
585{
621 struct pmc_hw *phw;
622
623 (void) pm;
624
625 PMCDBG(MDP,REL,1, "p6-release cpu=%d ri=%d pm=%p", cpu, ri, pm);
626
627 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
628 ("[p6,%d] illegal CPU value %d", __LINE__, cpu));
629 KASSERT(ri >= 0 && ri < P6_NPMCS,
630 ("[p6,%d] illegal row-index %d", __LINE__, ri));
631
586 (void) pm;
587
588 PMCDBG(MDP,REL,1, "p6-release cpu=%d ri=%d pm=%p", cpu, ri, pm);
589
590 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
591 ("[p6,%d] illegal CPU value %d", __LINE__, cpu));
592 KASSERT(ri >= 0 && ri < P6_NPMCS,
593 ("[p6,%d] illegal row-index %d", __LINE__, ri));
594
632 phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
595 KASSERT(p6_pcpu[cpu]->pc_p6pmcs[ri].phw_pmc == NULL,
596 ("[p6,%d] PHW pmc non-NULL", __LINE__));
633
597
634 KASSERT(phw->phw_pmc == NULL,
635 ("[p6,%d] PHW pmc %p != pmc %p", __LINE__, phw->phw_pmc, pm));
636
637 return 0;
598 return (0);
638}
639
640static int
641p6_start_pmc(int cpu, int ri)
642{
643 uint32_t config;
644 struct pmc *pm;
645 struct p6_cpu *pc;
599}
600
601static int
602p6_start_pmc(int cpu, int ri)
603{
604 uint32_t config;
605 struct pmc *pm;
606 struct p6_cpu *pc;
646 struct pmc_hw *phw;
647 const struct p6pmc_descr *pd;
648
649 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
650 ("[p6,%d] illegal CPU value %d", __LINE__, cpu));
651 KASSERT(ri >= 0 && ri < P6_NPMCS,
652 ("[p6,%d] illegal row-index %d", __LINE__, ri));
653
607 const struct p6pmc_descr *pd;
608
609 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
610 ("[p6,%d] illegal CPU value %d", __LINE__, cpu));
611 KASSERT(ri >= 0 && ri < P6_NPMCS,
612 ("[p6,%d] illegal row-index %d", __LINE__, ri));
613
654 pc = (struct p6_cpu *) pmc_pcpu[cpu];
655 phw = pc->pc_common.pc_hwpmcs[ri];
656 pm = phw->phw_pmc;
657 pd = &p6_pmcdesc[ri];
614 pc = p6_pcpu[cpu];
615 pm = pc->pc_p6pmcs[ri].phw_pmc;
616 pd = &p6_pmcdesc[ri];
658
659 KASSERT(pm,
660 ("[p6,%d] starting cpu%d,ri%d with no pmc configured",
661 __LINE__, cpu, ri));
662
663 PMCDBG(MDP,STA,1, "p6-start cpu=%d ri=%d", cpu, ri);
664
617
618 KASSERT(pm,
619 ("[p6,%d] starting cpu%d,ri%d with no pmc configured",
620 __LINE__, cpu, ri));
621
622 PMCDBG(MDP,STA,1, "p6-start cpu=%d ri=%d", cpu, ri);
623
665 if (pd->pm_descr.pd_class == PMC_CLASS_TSC)
666 return 0; /* TSC are always running */
667
668 KASSERT(pd->pm_descr.pd_class == PMC_CLASS_P6,
669 ("[p6,%d] unknown PMC class %d", __LINE__,
670 pd->pm_descr.pd_class));
671
672 config = pm->pm_md.pm_ppro.pm_ppro_evsel;
673
674 PMCDBG(MDP,STA,2, "p6-start/2 cpu=%d ri=%d evselmsr=0x%x config=0x%x",
675 cpu, ri, pd->pm_evsel_msr, config);
676
677 P6_MARK_STARTED(pc, ri);
678 wrmsr(pd->pm_evsel_msr, config);
679
680 P6_SYNC_CTR_STATE(pc);
681
624 config = pm->pm_md.pm_ppro.pm_ppro_evsel;
625
626 PMCDBG(MDP,STA,2, "p6-start/2 cpu=%d ri=%d evselmsr=0x%x config=0x%x",
627 cpu, ri, pd->pm_evsel_msr, config);
628
629 P6_MARK_STARTED(pc, ri);
630 wrmsr(pd->pm_evsel_msr, config);
631
632 P6_SYNC_CTR_STATE(pc);
633
682 return 0;
634 return (0);
683}
684
685static int
686p6_stop_pmc(int cpu, int ri)
687{
688 struct pmc *pm;
689 struct p6_cpu *pc;
635}
636
637static int
638p6_stop_pmc(int cpu, int ri)
639{
640 struct pmc *pm;
641 struct p6_cpu *pc;
690 struct pmc_hw *phw;
691 struct p6pmc_descr *pd;
692
693 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
694 ("[p6,%d] illegal cpu value %d", __LINE__, cpu));
695 KASSERT(ri >= 0 && ri < P6_NPMCS,
696 ("[p6,%d] illegal row index %d", __LINE__, ri));
697
642 struct p6pmc_descr *pd;
643
644 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
645 ("[p6,%d] illegal cpu value %d", __LINE__, cpu));
646 KASSERT(ri >= 0 && ri < P6_NPMCS,
647 ("[p6,%d] illegal row index %d", __LINE__, ri));
648
698 pc = (struct p6_cpu *) pmc_pcpu[cpu];
699 phw = pc->pc_common.pc_hwpmcs[ri];
700 pm = phw->phw_pmc;
701 pd = &p6_pmcdesc[ri];
649 pc = p6_pcpu[cpu];
650 pm = pc->pc_p6pmcs[ri].phw_pmc;
651 pd = &p6_pmcdesc[ri];
702
703 KASSERT(pm,
704 ("[p6,%d] cpu%d ri%d no configured PMC to stop", __LINE__,
705 cpu, ri));
706
652
653 KASSERT(pm,
654 ("[p6,%d] cpu%d ri%d no configured PMC to stop", __LINE__,
655 cpu, ri));
656
707 if (pd->pm_descr.pd_class == PMC_CLASS_TSC)
708 return 0;
709
710 KASSERT(pd->pm_descr.pd_class == PMC_CLASS_P6,
711 ("[p6,%d] unknown PMC class %d", __LINE__,
712 pd->pm_descr.pd_class));
713
714 PMCDBG(MDP,STO,1, "p6-stop cpu=%d ri=%d", cpu, ri);
715
716 wrmsr(pd->pm_evsel_msr, 0); /* stop hw */
717 P6_MARK_STOPPED(pc, ri); /* update software state */
718
719 P6_SYNC_CTR_STATE(pc); /* restart CTR1 if need be */
720
721 PMCDBG(MDP,STO,2, "p6-stop/2 cpu=%d ri=%d", cpu, ri);
657 PMCDBG(MDP,STO,1, "p6-stop cpu=%d ri=%d", cpu, ri);
658
659 wrmsr(pd->pm_evsel_msr, 0); /* stop hw */
660 P6_MARK_STOPPED(pc, ri); /* update software state */
661
662 P6_SYNC_CTR_STATE(pc); /* restart CTR1 if need be */
663
664 PMCDBG(MDP,STO,2, "p6-stop/2 cpu=%d ri=%d", cpu, ri);
722 return 0;
665
666 return (0);
723}
724
725static int
726p6_intr(int cpu, struct trapframe *tf)
727{
667}
668
669static int
670p6_intr(int cpu, struct trapframe *tf)
671{
728 int i, error, retval, ri;
672 int error, retval, ri;
729 uint32_t perf0cfg;
730 struct pmc *pm;
731 struct p6_cpu *pc;
673 uint32_t perf0cfg;
674 struct pmc *pm;
675 struct p6_cpu *pc;
732 struct pmc_hw *phw;
733 pmc_value_t v;
734
735 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
736 ("[p6,%d] CPU %d out of range", __LINE__, cpu));
737
738 retval = 0;
676 pmc_value_t v;
677
678 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
679 ("[p6,%d] CPU %d out of range", __LINE__, cpu));
680
681 retval = 0;
739 pc = (struct p6_cpu *) pmc_pcpu[cpu];
682 pc = p6_pcpu[cpu];
740
741 /* stop both PMCs */
742 perf0cfg = rdmsr(P6_MSR_EVSEL0);
743 wrmsr(P6_MSR_EVSEL0, perf0cfg & ~P6_EVSEL_EN);
744
683
684 /* stop both PMCs */
685 perf0cfg = rdmsr(P6_MSR_EVSEL0);
686 wrmsr(P6_MSR_EVSEL0, perf0cfg & ~P6_EVSEL_EN);
687
745 for (i = 0; i < P6_NPMCS-1; i++) {
746 ri = i + 1;
688 for (ri = 0; ri < P6_NPMCS; ri++) {
747
689
748 if (!P6_PMC_HAS_OVERFLOWED(i))
690 if (!P6_PMC_HAS_OVERFLOWED(ri))
749 continue;
750
691 continue;
692
751 phw = pc->pc_common.pc_hwpmcs[ri];
752
753 if ((pm = phw->phw_pmc) == NULL ||
693 if ((pm = pc->pc_p6pmcs[ri].phw_pmc) == NULL ||
754 pm->pm_state != PMC_STATE_RUNNING ||
755 !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
756 continue;
757 }
758
759 retval = 1;
760
761 error = pmc_process_interrupt(cpu, pm, tf,
762 TRAPF_USERMODE(tf));
763 if (error)
764 P6_MARK_STOPPED(pc,ri);
765
766 /* reload sampling count */
767 v = pm->pm_sc.pm_reloadcount;
694 pm->pm_state != PMC_STATE_RUNNING ||
695 !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
696 continue;
697 }
698
699 retval = 1;
700
701 error = pmc_process_interrupt(cpu, pm, tf,
702 TRAPF_USERMODE(tf));
703 if (error)
704 P6_MARK_STOPPED(pc,ri);
705
706 /* reload sampling count */
707 v = pm->pm_sc.pm_reloadcount;
768 wrmsr(P6_MSR_PERFCTR0 + i,
708 wrmsr(P6_MSR_PERFCTR0 + ri,
769 P6_RELOAD_COUNT_TO_PERFCTR_VALUE(v));
770
771 }
772
773 /*
774 * On P6 processors, the LAPIC needs to have its PMC interrupt
775 * unmasked after a PMC interrupt.
776 */
777 if (retval)
778 pmc_x86_lapic_enable_pmc_interrupt();
779
780 atomic_add_int(retval ? &pmc_stats.pm_intr_processed :
781 &pmc_stats.pm_intr_ignored, 1);
782
783 /* restart counters that can be restarted */
784 P6_SYNC_CTR_STATE(pc);
785
709 P6_RELOAD_COUNT_TO_PERFCTR_VALUE(v));
710
711 }
712
713 /*
714 * On P6 processors, the LAPIC needs to have its PMC interrupt
715 * unmasked after a PMC interrupt.
716 */
717 if (retval)
718 pmc_x86_lapic_enable_pmc_interrupt();
719
720 atomic_add_int(retval ? &pmc_stats.pm_intr_processed :
721 &pmc_stats.pm_intr_ignored, 1);
722
723 /* restart counters that can be restarted */
724 P6_SYNC_CTR_STATE(pc);
725
786 return retval;
726 return (retval);
787}
788
789static int
790p6_describe(int cpu, int ri, struct pmc_info *pi,
791 struct pmc **ppmc)
792{
793 int error;
794 size_t copied;
795 struct pmc_hw *phw;
796 struct p6pmc_descr *pd;
797
727}
728
729static int
730p6_describe(int cpu, int ri, struct pmc_info *pi,
731 struct pmc **ppmc)
732{
733 int error;
734 size_t copied;
735 struct pmc_hw *phw;
736 struct p6pmc_descr *pd;
737
738 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
739 ("[p6,%d] illegal CPU %d", __LINE__, cpu));
740 KASSERT(ri >= 0 && ri < P6_NPMCS,
741 ("[p6,%d] row-index %d out of range", __LINE__, ri));
742
798 phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
799 pd = &p6_pmcdesc[ri];
800
743 phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
744 pd = &p6_pmcdesc[ri];
745
746 KASSERT(phw == &p6_pcpu[cpu]->pc_p6pmcs[ri],
747 ("[p6,%d] phw mismatch", __LINE__));
748
801 if ((error = copystr(pd->pm_descr.pd_name, pi->pm_name,
802 PMC_NAME_MAX, &copied)) != 0)
749 if ((error = copystr(pd->pm_descr.pd_name, pi->pm_name,
750 PMC_NAME_MAX, &copied)) != 0)
803 return error;
751 return (error);
804
805 pi->pm_class = pd->pm_descr.pd_class;
806
807 if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
808 pi->pm_enabled = TRUE;
809 *ppmc = phw->phw_pmc;
810 } else {
811 pi->pm_enabled = FALSE;
812 *ppmc = NULL;
813 }
814
752
753 pi->pm_class = pd->pm_descr.pd_class;
754
755 if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
756 pi->pm_enabled = TRUE;
757 *ppmc = phw->phw_pmc;
758 } else {
759 pi->pm_enabled = FALSE;
760 *ppmc = NULL;
761 }
762
815 return 0;
763 return (0);
816}
817
818static int
819p6_get_msr(int ri, uint32_t *msr)
820{
821 KASSERT(ri >= 0 && ri < P6_NPMCS,
822 ("[p6,%d ri %d out of range", __LINE__, ri));
823
824 *msr = p6_pmcdesc[ri].pm_pmc_msr - P6_MSR_PERFCTR0;
764}
765
766static int
767p6_get_msr(int ri, uint32_t *msr)
768{
769 KASSERT(ri >= 0 && ri < P6_NPMCS,
770 ("[p6,%d ri %d out of range", __LINE__, ri));
771
772 *msr = p6_pmcdesc[ri].pm_pmc_msr - P6_MSR_PERFCTR0;
825 return 0;
773
774 return (0);
826}
827
828int
775}
776
777int
829pmc_initialize_p6(struct pmc_mdep *pmc_mdep)
778pmc_p6_initialize(struct pmc_mdep *md, int ncpus)
830{
779{
780 struct pmc_classdep *pcd;
781
831 KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0,
832 ("[p6,%d] Initializing non-intel processor", __LINE__));
833
834 PMCDBG(MDP,INI,1, "%s", "p6-initialize");
835
782 KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0,
783 ("[p6,%d] Initializing non-intel processor", __LINE__));
784
785 PMCDBG(MDP,INI,1, "%s", "p6-initialize");
786
836 switch (pmc_mdep->pmd_cputype) {
787 /* Allocate space for pointers to per-cpu descriptors. */
788 p6_pcpu = malloc(sizeof(struct p6_cpu **) * ncpus, M_PMC,
789 M_ZERO|M_WAITOK);
837
790
791 /* Fill in the class dependent descriptor. */
792 pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_P6];
793
794 switch (md->pmd_cputype) {
795
838 /*
839 * P6 Family Processors
840 */
796 /*
797 * P6 Family Processors
798 */
841
842 case PMC_CPU_INTEL_P6:
843 case PMC_CPU_INTEL_CL:
844 case PMC_CPU_INTEL_PII:
845 case PMC_CPU_INTEL_PIII:
846 case PMC_CPU_INTEL_PM:
847
799 case PMC_CPU_INTEL_P6:
800 case PMC_CPU_INTEL_CL:
801 case PMC_CPU_INTEL_PII:
802 case PMC_CPU_INTEL_PIII:
803 case PMC_CPU_INTEL_PM:
804
848 p6_cputype = pmc_mdep->pmd_cputype;
805 p6_cputype = md->pmd_cputype;
849
806
850 pmc_mdep->pmd_npmc = P6_NPMCS;
851 pmc_mdep->pmd_classes[1].pm_class = PMC_CLASS_P6;
852 pmc_mdep->pmd_classes[1].pm_caps = P6_PMC_CAPS;
853 pmc_mdep->pmd_classes[1].pm_width = 40;
854 pmc_mdep->pmd_nclasspmcs[1] = 2;
807 pcd->pcd_caps = P6_PMC_CAPS;
808 pcd->pcd_class = PMC_CLASS_P6;
809 pcd->pcd_num = P6_NPMCS;
810 pcd->pcd_ri = md->pmd_npmc;
811 pcd->pcd_width = 40;
855
812
856 pmc_mdep->pmd_init = p6_init;
857 pmc_mdep->pmd_cleanup = p6_cleanup;
858 pmc_mdep->pmd_switch_in = p6_switch_in;
859 pmc_mdep->pmd_switch_out = p6_switch_out;
860 pmc_mdep->pmd_read_pmc = p6_read_pmc;
861 pmc_mdep->pmd_write_pmc = p6_write_pmc;
862 pmc_mdep->pmd_config_pmc = p6_config_pmc;
863 pmc_mdep->pmd_get_config = p6_get_config;
864 pmc_mdep->pmd_allocate_pmc = p6_allocate_pmc;
865 pmc_mdep->pmd_release_pmc = p6_release_pmc;
866 pmc_mdep->pmd_start_pmc = p6_start_pmc;
867 pmc_mdep->pmd_stop_pmc = p6_stop_pmc;
868 pmc_mdep->pmd_intr = p6_intr;
869 pmc_mdep->pmd_describe = p6_describe;
870 pmc_mdep->pmd_get_msr = p6_get_msr; /* i386 */
813 pcd->pcd_allocate_pmc = p6_allocate_pmc;
814 pcd->pcd_config_pmc = p6_config_pmc;
815 pcd->pcd_describe = p6_describe;
816 pcd->pcd_get_config = p6_get_config;
817 pcd->pcd_get_msr = p6_get_msr;
818 pcd->pcd_pcpu_fini = p6_pcpu_fini;
819 pcd->pcd_pcpu_init = p6_pcpu_init;
820 pcd->pcd_read_pmc = p6_read_pmc;
821 pcd->pcd_release_pmc = p6_release_pmc;
822 pcd->pcd_start_pmc = p6_start_pmc;
823 pcd->pcd_stop_pmc = p6_stop_pmc;
824 pcd->pcd_write_pmc = p6_write_pmc;
871
825
826 md->pmd_pcpu_fini = NULL;
827 md->pmd_pcpu_init = NULL;
828 md->pmd_intr = p6_intr;
829
830 md->pmd_npmc += P6_NPMCS;
831
872 break;
832 break;
833
873 default:
874 KASSERT(0,("[p6,%d] Unknown CPU type", __LINE__));
875 return ENOSYS;
876 }
877
834 default:
835 KASSERT(0,("[p6,%d] Unknown CPU type", __LINE__));
836 return ENOSYS;
837 }
838
878 return 0;
839 return (0);
879}
840}
841
842void
843pmc_p6_finalize(struct pmc_mdep *md)
844{
845#if defined(INVARIANTS)
846 int i, ncpus;
847#endif
848
849 KASSERT(p6_pcpu != NULL, ("[p6,%d] NULL p6_pcpu", __LINE__));
850
851#if defined(INVARIANTS)
852 ncpus = pmc_cpu_max();
853 for (i = 0; i < ncpus; i++)
854 KASSERT(p6_pcpu[i] == NULL, ("[p6,%d] non-null pcpu %d",
855 __LINE__, i));
856#endif
857
858 free(p6_pcpu, M_PMC);
859 p6_pcpu = NULL;
860}