159191f35SAleksandr Rybalko /*-
2753c7fc9SAndrew Turner * SPDX-License-Identifier: BSD-2-Clause
359191f35SAleksandr Rybalko *
459191f35SAleksandr Rybalko * Copyright (c) 2003-2008 Joseph Koshy
559191f35SAleksandr Rybalko * Copyright (c) 2007 The FreeBSD Foundation
6d90188efSJohn Baldwin * Copyright (c) 2021 ARM Ltd
759191f35SAleksandr Rybalko *
859191f35SAleksandr Rybalko * Portions of this software were developed by A. Joseph Koshy under
959191f35SAleksandr Rybalko * sponsorship from the FreeBSD Foundation and Google, Inc.
1059191f35SAleksandr Rybalko *
1159191f35SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without
1259191f35SAleksandr Rybalko * modification, are permitted provided that the following conditions
1359191f35SAleksandr Rybalko * are met:
1459191f35SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright
1559191f35SAleksandr Rybalko * notice, this list of conditions and the following disclaimer.
1659191f35SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright
1759191f35SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the
1859191f35SAleksandr Rybalko * documentation and/or other materials provided with the distribution.
1959191f35SAleksandr Rybalko *
2059191f35SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2159191f35SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2259191f35SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2359191f35SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2459191f35SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2559191f35SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2659191f35SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2759191f35SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2859191f35SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2959191f35SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3059191f35SAleksandr Rybalko * SUCH DAMAGE.
3159191f35SAleksandr Rybalko */
3259191f35SAleksandr Rybalko
3359191f35SAleksandr Rybalko /* Arm CoreLink CMN-600 Coherent Mesh Network PMU Driver */
3459191f35SAleksandr Rybalko
3559191f35SAleksandr Rybalko #include <sys/param.h>
3659191f35SAleksandr Rybalko #include <sys/lock.h>
3759191f35SAleksandr Rybalko #include <sys/malloc.h>
3859191f35SAleksandr Rybalko #include <sys/module.h>
3959191f35SAleksandr Rybalko #include <sys/mutex.h>
4059191f35SAleksandr Rybalko #include <sys/pmc.h>
4159191f35SAleksandr Rybalko #include <sys/pmckern.h>
4259191f35SAleksandr Rybalko #include <sys/systm.h>
4359191f35SAleksandr Rybalko
4459191f35SAleksandr Rybalko #include <machine/cmn600_reg.h>
4559191f35SAleksandr Rybalko
4659191f35SAleksandr Rybalko struct cmn600_descr {
4759191f35SAleksandr Rybalko struct pmc_descr pd_descr; /* "base class" */
4859191f35SAleksandr Rybalko void *pd_rw_arg; /* Argument to use with read/write */
4959191f35SAleksandr Rybalko struct pmc *pd_pmc;
5059191f35SAleksandr Rybalko struct pmc_hw *pd_phw;
5159191f35SAleksandr Rybalko uint32_t pd_nodeid;
5259191f35SAleksandr Rybalko int32_t pd_node_type;
5359191f35SAleksandr Rybalko int pd_local_counter;
5459191f35SAleksandr Rybalko
5559191f35SAleksandr Rybalko };
5659191f35SAleksandr Rybalko
5759191f35SAleksandr Rybalko static struct cmn600_descr **cmn600_pmcdesc;
5859191f35SAleksandr Rybalko
5959191f35SAleksandr Rybalko static struct cmn600_pmc cmn600_pmcs[CMN600_UNIT_MAX];
6059191f35SAleksandr Rybalko static int cmn600_units = 0;
6159191f35SAleksandr Rybalko
6259191f35SAleksandr Rybalko static inline struct cmn600_descr *
cmn600desc(int ri)6359191f35SAleksandr Rybalko cmn600desc(int ri)
6459191f35SAleksandr Rybalko {
6559191f35SAleksandr Rybalko
6659191f35SAleksandr Rybalko return (cmn600_pmcdesc[ri]);
6759191f35SAleksandr Rybalko }
6859191f35SAleksandr Rybalko
6959191f35SAleksandr Rybalko static inline int
class_ri2unit(int ri)7059191f35SAleksandr Rybalko class_ri2unit(int ri)
7159191f35SAleksandr Rybalko {
7259191f35SAleksandr Rybalko
7359191f35SAleksandr Rybalko return (ri / CMN600_COUNTERS_N);
7459191f35SAleksandr Rybalko }
7559191f35SAleksandr Rybalko
7659191f35SAleksandr Rybalko #define EVENCNTR(x) (((x) >> POR_DT_PMEVCNT_EVENCNT_SHIFT) << \
7759191f35SAleksandr Rybalko POR_DTM_PMEVCNT_CNTR_WIDTH)
7859191f35SAleksandr Rybalko #define ODDCNTR(x) (((x) >> POR_DT_PMEVCNT_ODDCNT_SHIFT) << \
7959191f35SAleksandr Rybalko POR_DTM_PMEVCNT_CNTR_WIDTH)
8059191f35SAleksandr Rybalko
8159191f35SAleksandr Rybalko static uint64_t
cmn600_pmu_readcntr(void * arg,u_int nodeid,u_int xpcntr,u_int dtccntr,u_int width)8259191f35SAleksandr Rybalko cmn600_pmu_readcntr(void *arg, u_int nodeid, u_int xpcntr, u_int dtccntr,
8359191f35SAleksandr Rybalko u_int width)
8459191f35SAleksandr Rybalko {
8559191f35SAleksandr Rybalko uint64_t dtcval, xpval;
8659191f35SAleksandr Rybalko
8759191f35SAleksandr Rybalko KASSERT(xpcntr < 4, ("[cmn600,%d] XP counter number %d is too big."
8859191f35SAleksandr Rybalko " Max: 3", __LINE__, xpcntr));
8959191f35SAleksandr Rybalko KASSERT(dtccntr < 8, ("[cmn600,%d] Global counter number %d is too"
9059191f35SAleksandr Rybalko " big. Max: 7", __LINE__, dtccntr));
9159191f35SAleksandr Rybalko
9259191f35SAleksandr Rybalko dtcval = pmu_cmn600_rd8(arg, nodeid, NODE_TYPE_DTC,
9359191f35SAleksandr Rybalko POR_DT_PMEVCNT(dtccntr >> 1));
9459191f35SAleksandr Rybalko if (width == 4) {
9559191f35SAleksandr Rybalko dtcval = (dtccntr & 1) ? ODDCNTR(dtcval) : EVENCNTR(dtcval);
9659191f35SAleksandr Rybalko dtcval &= 0xffffffff0000UL;
9759191f35SAleksandr Rybalko } else
9859191f35SAleksandr Rybalko dtcval <<= POR_DTM_PMEVCNT_CNTR_WIDTH;
9959191f35SAleksandr Rybalko
10059191f35SAleksandr Rybalko xpval = pmu_cmn600_rd8(arg, nodeid, NODE_TYPE_XP, POR_DTM_PMEVCNT);
10159191f35SAleksandr Rybalko xpval >>= xpcntr * POR_DTM_PMEVCNT_CNTR_WIDTH;
10259191f35SAleksandr Rybalko xpval &= 0xffffUL;
10359191f35SAleksandr Rybalko return (dtcval | xpval);
10459191f35SAleksandr Rybalko }
10559191f35SAleksandr Rybalko
10659191f35SAleksandr Rybalko static void
cmn600_pmu_writecntr(void * arg,u_int nodeid,u_int xpcntr,u_int dtccntr,u_int width,uint64_t val)10759191f35SAleksandr Rybalko cmn600_pmu_writecntr(void *arg, u_int nodeid, u_int xpcntr, u_int dtccntr,
10859191f35SAleksandr Rybalko u_int width, uint64_t val)
10959191f35SAleksandr Rybalko {
11059191f35SAleksandr Rybalko int shift;
11159191f35SAleksandr Rybalko
11259191f35SAleksandr Rybalko KASSERT(xpcntr < 4, ("[cmn600,%d] XP counter number %d is too big."
11359191f35SAleksandr Rybalko " Max: 3", __LINE__, xpcntr));
11459191f35SAleksandr Rybalko KASSERT(dtccntr < 8, ("[cmn600,%d] Global counter number %d is too"
11559191f35SAleksandr Rybalko " big. Max: 7", __LINE__, dtccntr));
11659191f35SAleksandr Rybalko
11759191f35SAleksandr Rybalko if (width == 4) {
11859191f35SAleksandr Rybalko shift = (dtccntr & 1) ? POR_DT_PMEVCNT_ODDCNT_SHIFT :
11959191f35SAleksandr Rybalko POR_DT_PMEVCNT_EVENCNT_SHIFT;
12059191f35SAleksandr Rybalko pmu_cmn600_md8(arg, nodeid, NODE_TYPE_DTC,
12159191f35SAleksandr Rybalko POR_DT_PMEVCNT(dtccntr >> 1), 0xffffffffUL << shift,
12259191f35SAleksandr Rybalko ((val >> POR_DTM_PMEVCNT_CNTR_WIDTH) & 0xffffffff) << shift);
12359191f35SAleksandr Rybalko } else
12459191f35SAleksandr Rybalko pmu_cmn600_wr8(arg, nodeid, NODE_TYPE_DTC,
12559191f35SAleksandr Rybalko POR_DT_PMEVCNT(dtccntr & ~0x1), val >>
12659191f35SAleksandr Rybalko POR_DTM_PMEVCNT_CNTR_WIDTH);
12759191f35SAleksandr Rybalko
12859191f35SAleksandr Rybalko shift = xpcntr * POR_DTM_PMEVCNT_CNTR_WIDTH;
12959191f35SAleksandr Rybalko val &= 0xffffUL;
13059191f35SAleksandr Rybalko pmu_cmn600_md8(arg, nodeid, NODE_TYPE_XP, POR_DTM_PMEVCNT,
13159191f35SAleksandr Rybalko 0xffffUL << shift, val << shift);
13259191f35SAleksandr Rybalko }
13359191f35SAleksandr Rybalko
13459191f35SAleksandr Rybalko #undef EVENCNTR
13559191f35SAleksandr Rybalko #undef ODDCNTR
13659191f35SAleksandr Rybalko
13759191f35SAleksandr Rybalko /*
13859191f35SAleksandr Rybalko * read a pmc register
13959191f35SAleksandr Rybalko */
14059191f35SAleksandr Rybalko static int
cmn600_read_pmc(int cpu,int ri,struct pmc * pm,pmc_value_t * v)141*39f92a76SMitchell Horne cmn600_read_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t *v)
14259191f35SAleksandr Rybalko {
14359191f35SAleksandr Rybalko int counter, local_counter, nodeid;
14459191f35SAleksandr Rybalko struct cmn600_descr *desc;
14559191f35SAleksandr Rybalko void *arg;
14659191f35SAleksandr Rybalko
14759191f35SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
14859191f35SAleksandr Rybalko ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu));
14959191f35SAleksandr Rybalko KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__,
15059191f35SAleksandr Rybalko ri));
15159191f35SAleksandr Rybalko
15259191f35SAleksandr Rybalko counter = ri % CMN600_COUNTERS_N;
15359191f35SAleksandr Rybalko desc = cmn600desc(ri);
15459191f35SAleksandr Rybalko arg = desc->pd_rw_arg;
15559191f35SAleksandr Rybalko nodeid = pm->pm_md.pm_cmn600.pm_cmn600_nodeid;
15659191f35SAleksandr Rybalko local_counter = pm->pm_md.pm_cmn600.pm_cmn600_local_counter;
15759191f35SAleksandr Rybalko
15859191f35SAleksandr Rybalko *v = cmn600_pmu_readcntr(arg, nodeid, local_counter, counter, 4);
15959191f35SAleksandr Rybalko PMCDBG3(MDP, REA, 2, "%s id=%d -> %jd", __func__, ri, *v);
16059191f35SAleksandr Rybalko
16159191f35SAleksandr Rybalko return (0);
16259191f35SAleksandr Rybalko }
16359191f35SAleksandr Rybalko
16459191f35SAleksandr Rybalko /*
16559191f35SAleksandr Rybalko * Write a pmc register.
16659191f35SAleksandr Rybalko */
16759191f35SAleksandr Rybalko static int
cmn600_write_pmc(int cpu,int ri,struct pmc * pm,pmc_value_t v)168*39f92a76SMitchell Horne cmn600_write_pmc(int cpu, int ri, struct pmc *pm, pmc_value_t v)
16959191f35SAleksandr Rybalko {
17059191f35SAleksandr Rybalko int counter, local_counter, nodeid;
17159191f35SAleksandr Rybalko struct cmn600_descr *desc;
17259191f35SAleksandr Rybalko void *arg;
17359191f35SAleksandr Rybalko
17459191f35SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
17559191f35SAleksandr Rybalko ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu));
17659191f35SAleksandr Rybalko KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__,
17759191f35SAleksandr Rybalko ri));
17859191f35SAleksandr Rybalko
17959191f35SAleksandr Rybalko counter = ri % CMN600_COUNTERS_N;
18059191f35SAleksandr Rybalko desc = cmn600desc(ri);
18159191f35SAleksandr Rybalko arg = desc->pd_rw_arg;
18259191f35SAleksandr Rybalko nodeid = pm->pm_md.pm_cmn600.pm_cmn600_nodeid;
18359191f35SAleksandr Rybalko local_counter = pm->pm_md.pm_cmn600.pm_cmn600_local_counter;
18459191f35SAleksandr Rybalko
18559191f35SAleksandr Rybalko KASSERT(pm != NULL,
18659191f35SAleksandr Rybalko ("[cmn600,%d] PMC not owned (cpu%d,pmc%d)", __LINE__,
18759191f35SAleksandr Rybalko cpu, ri));
18859191f35SAleksandr Rybalko
18959191f35SAleksandr Rybalko PMCDBG4(MDP, WRI, 1, "%s cpu=%d ri=%d v=%jx", __func__, cpu, ri, v);
19059191f35SAleksandr Rybalko
19159191f35SAleksandr Rybalko cmn600_pmu_writecntr(arg, nodeid, local_counter, counter, 4, v);
19259191f35SAleksandr Rybalko return (0);
19359191f35SAleksandr Rybalko }
19459191f35SAleksandr Rybalko
19559191f35SAleksandr Rybalko /*
19659191f35SAleksandr Rybalko * configure hardware pmc according to the configuration recorded in
19759191f35SAleksandr Rybalko * pmc 'pm'.
19859191f35SAleksandr Rybalko */
19959191f35SAleksandr Rybalko static int
cmn600_config_pmc(int cpu,int ri,struct pmc * pm)20059191f35SAleksandr Rybalko cmn600_config_pmc(int cpu, int ri, struct pmc *pm)
20159191f35SAleksandr Rybalko {
20259191f35SAleksandr Rybalko struct pmc_hw *phw;
20359191f35SAleksandr Rybalko
20459191f35SAleksandr Rybalko PMCDBG4(MDP, CFG, 1, "%s cpu=%d ri=%d pm=%p", __func__, cpu, ri, pm);
20559191f35SAleksandr Rybalko
20659191f35SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
20759191f35SAleksandr Rybalko ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu));
20859191f35SAleksandr Rybalko KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__,
20959191f35SAleksandr Rybalko ri));
21059191f35SAleksandr Rybalko
21159191f35SAleksandr Rybalko phw = cmn600desc(ri)->pd_phw;
21259191f35SAleksandr Rybalko
21359191f35SAleksandr Rybalko KASSERT(pm == NULL || phw->phw_pmc == NULL,
21459191f35SAleksandr Rybalko ("[cmn600,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
21559191f35SAleksandr Rybalko __LINE__, pm, phw->phw_pmc));
21659191f35SAleksandr Rybalko
21759191f35SAleksandr Rybalko phw->phw_pmc = pm;
21859191f35SAleksandr Rybalko return (0);
21959191f35SAleksandr Rybalko }
22059191f35SAleksandr Rybalko
22159191f35SAleksandr Rybalko /*
22259191f35SAleksandr Rybalko * Retrieve a configured PMC pointer from hardware state.
22359191f35SAleksandr Rybalko */
22459191f35SAleksandr Rybalko static int
cmn600_get_config(int cpu,int ri,struct pmc ** ppm)22559191f35SAleksandr Rybalko cmn600_get_config(int cpu, int ri, struct pmc **ppm)
22659191f35SAleksandr Rybalko {
22759191f35SAleksandr Rybalko
22859191f35SAleksandr Rybalko *ppm = cmn600desc(ri)->pd_phw->phw_pmc;
22959191f35SAleksandr Rybalko
23059191f35SAleksandr Rybalko return (0);
23159191f35SAleksandr Rybalko }
23259191f35SAleksandr Rybalko
23359191f35SAleksandr Rybalko #define CASE_DN_VER_EVT(n, id) case PMC_EV_CMN600_PMU_ ## n: { *event = id; \
23459191f35SAleksandr Rybalko return (0); }
23559191f35SAleksandr Rybalko static int
cmn600_map_ev2event(int ev,int rev,int * node_type,uint8_t * event)23659191f35SAleksandr Rybalko cmn600_map_ev2event(int ev, int rev, int *node_type, uint8_t *event)
23759191f35SAleksandr Rybalko {
23859191f35SAleksandr Rybalko if (ev < PMC_EV_CMN600_PMU_dn_rxreq_dvmop ||
23959191f35SAleksandr Rybalko ev > PMC_EV_CMN600_PMU_rni_rdb_ord)
24059191f35SAleksandr Rybalko return (EINVAL);
24159191f35SAleksandr Rybalko if (ev <= PMC_EV_CMN600_PMU_dn_rxreq_trk_full) {
24259191f35SAleksandr Rybalko *node_type = NODE_TYPE_DVM;
24359191f35SAleksandr Rybalko if (rev < 0x200) {
24459191f35SAleksandr Rybalko switch (ev) {
24559191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_dvmop, 1);
24659191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_dvmsync, 2);
24759191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_dvmop_vmid_filtered, 3);
24859191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_retried, 4);
24959191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_trk_occupancy, 5);
25059191f35SAleksandr Rybalko }
25159191f35SAleksandr Rybalko } else {
25259191f35SAleksandr Rybalko switch (ev) {
25359191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_tlbi_dvmop, 0x01);
25459191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_bpi_dvmop, 0x02);
25559191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_pici_dvmop, 0x03);
25659191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_vivi_dvmop, 0x04);
25759191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_dvmsync, 0x05);
25859191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_dvmop_vmid_filtered, 0x06);
25959191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_dvmop_other_filtered, 0x07);
26059191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_retried, 0x08);
26159191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_snp_sent, 0x09);
26259191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_snp_stalled, 0x0a);
26359191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_trk_full, 0x0b);
26459191f35SAleksandr Rybalko CASE_DN_VER_EVT(dn_rxreq_trk_occupancy, 0x0c);
26559191f35SAleksandr Rybalko }
26659191f35SAleksandr Rybalko }
26759191f35SAleksandr Rybalko return (EINVAL);
26859191f35SAleksandr Rybalko } else if (ev <= PMC_EV_CMN600_PMU_hnf_snp_fwded) {
26959191f35SAleksandr Rybalko *node_type = NODE_TYPE_HN_F;
27059191f35SAleksandr Rybalko *event = ev - PMC_EV_CMN600_PMU_hnf_cache_miss;
27159191f35SAleksandr Rybalko return (0);
27259191f35SAleksandr Rybalko } else if (ev <= PMC_EV_CMN600_PMU_hni_pcie_serialization) {
27359191f35SAleksandr Rybalko *node_type = NODE_TYPE_HN_I;
27459191f35SAleksandr Rybalko *event = ev - PMC_EV_CMN600_PMU_hni_rrt_rd_occ_cnt_ovfl;
27559191f35SAleksandr Rybalko return (0);
27659191f35SAleksandr Rybalko } else if (ev <= PMC_EV_CMN600_PMU_xp_partial_dat_flit) {
27759191f35SAleksandr Rybalko *node_type = NODE_TYPE_XP;
27859191f35SAleksandr Rybalko *event = ev - PMC_EV_CMN600_PMU_xp_txflit_valid;
27959191f35SAleksandr Rybalko return (0);
28059191f35SAleksandr Rybalko } else if (ev <= PMC_EV_CMN600_PMU_sbsx_txrsp_stall) {
28159191f35SAleksandr Rybalko *node_type = NODE_TYPE_SBSX;
28259191f35SAleksandr Rybalko *event = ev - PMC_EV_CMN600_PMU_sbsx_rd_req;
28359191f35SAleksandr Rybalko return (0);
28459191f35SAleksandr Rybalko } else if (ev <= PMC_EV_CMN600_PMU_rnd_rdb_ord) {
28559191f35SAleksandr Rybalko *node_type = NODE_TYPE_RN_D;
28659191f35SAleksandr Rybalko *event = ev - PMC_EV_CMN600_PMU_rnd_s0_rdata_beats;
28759191f35SAleksandr Rybalko return (0);
28859191f35SAleksandr Rybalko } else if (ev <= PMC_EV_CMN600_PMU_rni_rdb_ord) {
28959191f35SAleksandr Rybalko *node_type = NODE_TYPE_RN_I;
29059191f35SAleksandr Rybalko *event = ev - PMC_EV_CMN600_PMU_rni_s0_rdata_beats;
29159191f35SAleksandr Rybalko return (0);
29259191f35SAleksandr Rybalko } else if (ev <= PMC_EV_CMN600_PMU_cxha_snphaz_occ) {
29359191f35SAleksandr Rybalko *node_type = NODE_TYPE_CXHA;
29459191f35SAleksandr Rybalko *event = ev - PMC_EV_CMN600_PMU_cxha_rddatbyp;
29559191f35SAleksandr Rybalko return (0);
29659191f35SAleksandr Rybalko } else if (ev <= PMC_EV_CMN600_PMU_cxra_ext_dat_stall) {
29759191f35SAleksandr Rybalko *node_type = NODE_TYPE_CXRA;
29859191f35SAleksandr Rybalko *event = ev - PMC_EV_CMN600_PMU_cxra_req_trk_occ;
29959191f35SAleksandr Rybalko return (0);
30059191f35SAleksandr Rybalko } else if (ev <= PMC_EV_CMN600_PMU_cxla_avg_latency_form_tx_tlp) {
30159191f35SAleksandr Rybalko *node_type = NODE_TYPE_CXLA;
30259191f35SAleksandr Rybalko *event = ev - PMC_EV_CMN600_PMU_cxla_rx_tlp_link0;
30359191f35SAleksandr Rybalko return (0);
30459191f35SAleksandr Rybalko }
30559191f35SAleksandr Rybalko return (EINVAL);
30659191f35SAleksandr Rybalko }
30759191f35SAleksandr Rybalko
30859191f35SAleksandr Rybalko /*
30959191f35SAleksandr Rybalko * Check if a given allocation is feasible.
31059191f35SAleksandr Rybalko */
31159191f35SAleksandr Rybalko
31259191f35SAleksandr Rybalko static int
cmn600_allocate_pmc(int cpu,int ri,struct pmc * pm,const struct pmc_op_pmcallocate * a)31359191f35SAleksandr Rybalko cmn600_allocate_pmc(int cpu, int ri, struct pmc *pm,
31459191f35SAleksandr Rybalko const struct pmc_op_pmcallocate *a)
31559191f35SAleksandr Rybalko {
31659191f35SAleksandr Rybalko struct cmn600_descr *desc;
31759191f35SAleksandr Rybalko const struct pmc_descr *pd;
31859191f35SAleksandr Rybalko uint64_t caps __unused;
31959191f35SAleksandr Rybalko int local_counter, node_type;
32059191f35SAleksandr Rybalko enum pmc_event pe;
32159191f35SAleksandr Rybalko void *arg;
32259191f35SAleksandr Rybalko uint8_t e;
32359191f35SAleksandr Rybalko int err;
32459191f35SAleksandr Rybalko
32559191f35SAleksandr Rybalko (void) cpu;
32659191f35SAleksandr Rybalko
32759191f35SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
32859191f35SAleksandr Rybalko ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu));
32959191f35SAleksandr Rybalko KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__,
33059191f35SAleksandr Rybalko ri));
33159191f35SAleksandr Rybalko
33259191f35SAleksandr Rybalko desc = cmn600desc(ri);
33359191f35SAleksandr Rybalko arg = desc->pd_rw_arg;
33459191f35SAleksandr Rybalko pd = &desc->pd_descr;
33559191f35SAleksandr Rybalko if (cmn600_pmcs[class_ri2unit(ri)].domain != pcpu_find(cpu)->pc_domain)
33659191f35SAleksandr Rybalko return (EINVAL);
33759191f35SAleksandr Rybalko
33859191f35SAleksandr Rybalko /* check class match */
33959191f35SAleksandr Rybalko if (pd->pd_class != a->pm_class)
34059191f35SAleksandr Rybalko return (EINVAL);
34159191f35SAleksandr Rybalko
34259191f35SAleksandr Rybalko caps = pm->pm_caps;
34359191f35SAleksandr Rybalko
34459191f35SAleksandr Rybalko PMCDBG3(MDP, ALL, 1, "%s ri=%d caps=0x%x", __func__, ri, caps);
34559191f35SAleksandr Rybalko
34659191f35SAleksandr Rybalko pe = a->pm_ev;
34759191f35SAleksandr Rybalko err = cmn600_map_ev2event(pe, pmu_cmn600_rev(arg), &node_type, &e);
34859191f35SAleksandr Rybalko if (err != 0)
34959191f35SAleksandr Rybalko return (err);
35059191f35SAleksandr Rybalko err = pmu_cmn600_alloc_localpmc(arg,
35159191f35SAleksandr Rybalko a->pm_md.pm_cmn600.pma_cmn600_nodeid, node_type, &local_counter);
35259191f35SAleksandr Rybalko if (err != 0)
35359191f35SAleksandr Rybalko return (err);
35459191f35SAleksandr Rybalko
35559191f35SAleksandr Rybalko pm->pm_md.pm_cmn600.pm_cmn600_config =
35659191f35SAleksandr Rybalko a->pm_md.pm_cmn600.pma_cmn600_config;
35759191f35SAleksandr Rybalko pm->pm_md.pm_cmn600.pm_cmn600_occupancy =
35859191f35SAleksandr Rybalko a->pm_md.pm_cmn600.pma_cmn600_occupancy;
35959191f35SAleksandr Rybalko desc->pd_nodeid = pm->pm_md.pm_cmn600.pm_cmn600_nodeid =
36059191f35SAleksandr Rybalko a->pm_md.pm_cmn600.pma_cmn600_nodeid;
36159191f35SAleksandr Rybalko desc->pd_node_type = pm->pm_md.pm_cmn600.pm_cmn600_node_type =
36259191f35SAleksandr Rybalko node_type;
36359191f35SAleksandr Rybalko pm->pm_md.pm_cmn600.pm_cmn600_event = e;
36459191f35SAleksandr Rybalko desc->pd_local_counter = pm->pm_md.pm_cmn600.pm_cmn600_local_counter =
36559191f35SAleksandr Rybalko local_counter;
36659191f35SAleksandr Rybalko
36759191f35SAleksandr Rybalko return (0);
36859191f35SAleksandr Rybalko }
36959191f35SAleksandr Rybalko
37059191f35SAleksandr Rybalko /* Release machine dependent state associated with a PMC. */
37159191f35SAleksandr Rybalko
37259191f35SAleksandr Rybalko static int
cmn600_release_pmc(int cpu,int ri,struct pmc * pmc)37359191f35SAleksandr Rybalko cmn600_release_pmc(int cpu, int ri, struct pmc *pmc)
37459191f35SAleksandr Rybalko {
37559191f35SAleksandr Rybalko struct cmn600_descr *desc;
37659191f35SAleksandr Rybalko struct pmc_hw *phw;
377d78bef0eSBjoern A. Zeeb struct pmc *pm __diagused;
37859191f35SAleksandr Rybalko int err;
37959191f35SAleksandr Rybalko
38059191f35SAleksandr Rybalko (void) pmc;
38159191f35SAleksandr Rybalko
38259191f35SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
38359191f35SAleksandr Rybalko ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu));
38459191f35SAleksandr Rybalko KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__,
38559191f35SAleksandr Rybalko ri));
38659191f35SAleksandr Rybalko
38759191f35SAleksandr Rybalko desc = cmn600desc(ri);
38859191f35SAleksandr Rybalko phw = desc->pd_phw;
38959191f35SAleksandr Rybalko pm = phw->phw_pmc;
39059191f35SAleksandr Rybalko err = pmu_cmn600_free_localpmc(desc->pd_rw_arg, desc->pd_nodeid,
39159191f35SAleksandr Rybalko desc->pd_node_type, desc->pd_local_counter);
39259191f35SAleksandr Rybalko if (err != 0)
39359191f35SAleksandr Rybalko return (err);
39459191f35SAleksandr Rybalko
39559191f35SAleksandr Rybalko KASSERT(pm == NULL, ("[cmn600,%d] PHW pmc %p non-NULL", __LINE__, pm));
39659191f35SAleksandr Rybalko
39759191f35SAleksandr Rybalko return (0);
39859191f35SAleksandr Rybalko }
39959191f35SAleksandr Rybalko
40059191f35SAleksandr Rybalko static inline uint64_t
cmn600_encode_source(int node_type,int counter,int port,int sub)40159191f35SAleksandr Rybalko cmn600_encode_source(int node_type, int counter, int port, int sub)
40259191f35SAleksandr Rybalko {
40359191f35SAleksandr Rybalko
40459191f35SAleksandr Rybalko /* Calculate pmevcnt0_input_sel based on list in Table 3-794. */
40559191f35SAleksandr Rybalko if (node_type == NODE_TYPE_XP)
40659191f35SAleksandr Rybalko return (0x4 | counter);
40759191f35SAleksandr Rybalko
40859191f35SAleksandr Rybalko return (((port + 1) << 4) | (sub << 2) | counter);
40959191f35SAleksandr Rybalko }
41059191f35SAleksandr Rybalko
41159191f35SAleksandr Rybalko /*
41259191f35SAleksandr Rybalko * start a PMC.
41359191f35SAleksandr Rybalko */
41459191f35SAleksandr Rybalko
41559191f35SAleksandr Rybalko static int
cmn600_start_pmc(int cpu,int ri,struct pmc * pm)416*39f92a76SMitchell Horne cmn600_start_pmc(int cpu, int ri, struct pmc *pm)
41759191f35SAleksandr Rybalko {
41859191f35SAleksandr Rybalko int counter, local_counter, node_type, shift;
41959191f35SAleksandr Rybalko uint64_t config, occupancy, source, xp_pmucfg;
42059191f35SAleksandr Rybalko struct cmn600_descr *desc;
42159191f35SAleksandr Rybalko uint8_t event, port, sub;
42259191f35SAleksandr Rybalko uint16_t nodeid;
42359191f35SAleksandr Rybalko void *arg;
42459191f35SAleksandr Rybalko
42559191f35SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
42659191f35SAleksandr Rybalko ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu));
42759191f35SAleksandr Rybalko KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__,
42859191f35SAleksandr Rybalko ri));
42959191f35SAleksandr Rybalko
43059191f35SAleksandr Rybalko counter = ri % CMN600_COUNTERS_N;
43159191f35SAleksandr Rybalko desc = cmn600desc(ri);
43259191f35SAleksandr Rybalko arg = desc->pd_rw_arg;
43359191f35SAleksandr Rybalko
43459191f35SAleksandr Rybalko PMCDBG3(MDP, STA, 1, "%s cpu=%d ri=%d", __func__, cpu, ri);
43559191f35SAleksandr Rybalko
43659191f35SAleksandr Rybalko config = pm->pm_md.pm_cmn600.pm_cmn600_config;
43759191f35SAleksandr Rybalko occupancy = pm->pm_md.pm_cmn600.pm_cmn600_occupancy;
43859191f35SAleksandr Rybalko node_type = pm->pm_md.pm_cmn600.pm_cmn600_node_type;
43959191f35SAleksandr Rybalko event = pm->pm_md.pm_cmn600.pm_cmn600_event;
44059191f35SAleksandr Rybalko nodeid = pm->pm_md.pm_cmn600.pm_cmn600_nodeid;
44159191f35SAleksandr Rybalko local_counter = pm->pm_md.pm_cmn600.pm_cmn600_local_counter;
44259191f35SAleksandr Rybalko port = (nodeid >> 2) & 1;
44359191f35SAleksandr Rybalko sub = nodeid & 3;
44459191f35SAleksandr Rybalko
44559191f35SAleksandr Rybalko switch (node_type) {
44659191f35SAleksandr Rybalko case NODE_TYPE_DVM:
44759191f35SAleksandr Rybalko case NODE_TYPE_HN_F:
44859191f35SAleksandr Rybalko case NODE_TYPE_CXHA:
44959191f35SAleksandr Rybalko case NODE_TYPE_CXRA:
45059191f35SAleksandr Rybalko pmu_cmn600_md8(arg, nodeid, node_type,
45159191f35SAleksandr Rybalko CMN600_COMMON_PMU_EVENT_SEL,
45259191f35SAleksandr Rybalko CMN600_COMMON_PMU_EVENT_SEL_OCC_MASK,
45359191f35SAleksandr Rybalko occupancy << CMN600_COMMON_PMU_EVENT_SEL_OCC_SHIFT);
45459191f35SAleksandr Rybalko break;
45559191f35SAleksandr Rybalko case NODE_TYPE_XP:
45659191f35SAleksandr Rybalko /* Set PC and Interface.*/
45759191f35SAleksandr Rybalko event |= config;
45859191f35SAleksandr Rybalko }
45959191f35SAleksandr Rybalko
46059191f35SAleksandr Rybalko /*
46159191f35SAleksandr Rybalko * 5.5.1 Set up PMU counters
46259191f35SAleksandr Rybalko * 1. Ensure that the NIDEN input is asserted. HW side. */
46359191f35SAleksandr Rybalko /* 2. Select event of target node for one of four outputs. */
46459191f35SAleksandr Rybalko pmu_cmn600_md8(arg, nodeid, node_type, CMN600_COMMON_PMU_EVENT_SEL,
46559191f35SAleksandr Rybalko 0xff << (local_counter * 8),
46659191f35SAleksandr Rybalko event << (local_counter * 8));
46759191f35SAleksandr Rybalko
46859191f35SAleksandr Rybalko xp_pmucfg = pmu_cmn600_rd8(arg, nodeid, NODE_TYPE_XP,
46959191f35SAleksandr Rybalko POR_DTM_PMU_CONFIG);
47059191f35SAleksandr Rybalko /*
47159191f35SAleksandr Rybalko * 3. configure XP to connect one of four target node outputs to local
47259191f35SAleksandr Rybalko * counter.
47359191f35SAleksandr Rybalko */
47459191f35SAleksandr Rybalko source = cmn600_encode_source(node_type, local_counter, port, sub);
47559191f35SAleksandr Rybalko shift = (local_counter * POR_DTM_PMU_CONFIG_VCNT_INPUT_SEL_WIDTH) +
47659191f35SAleksandr Rybalko POR_DTM_PMU_CONFIG_VCNT_INPUT_SEL_SHIFT;
47759191f35SAleksandr Rybalko xp_pmucfg &= ~(0xffUL << shift);
47859191f35SAleksandr Rybalko xp_pmucfg |= source << shift;
47959191f35SAleksandr Rybalko
48059191f35SAleksandr Rybalko /* 4. Pair with global counters A, B, C, ..., H. */
48159191f35SAleksandr Rybalko shift = (local_counter * 4) + 16;
48259191f35SAleksandr Rybalko xp_pmucfg &= ~(0xfUL << shift);
48359191f35SAleksandr Rybalko xp_pmucfg |= counter << shift;
48459191f35SAleksandr Rybalko /* Enable pairing.*/
48559191f35SAleksandr Rybalko xp_pmucfg |= 1 << (local_counter + 4);
48659191f35SAleksandr Rybalko
48759191f35SAleksandr Rybalko /* 5. Combine local counters 0 with 1, 2 with 3 or all four. */
48859191f35SAleksandr Rybalko xp_pmucfg &= ~0xeUL;
48959191f35SAleksandr Rybalko
49059191f35SAleksandr Rybalko /* 6. Enable XP's PMU function. */
49159191f35SAleksandr Rybalko xp_pmucfg |= POR_DTM_PMU_CONFIG_PMU_EN;
49259191f35SAleksandr Rybalko pmu_cmn600_wr8(arg, nodeid, NODE_TYPE_XP, POR_DTM_PMU_CONFIG, xp_pmucfg);
49359191f35SAleksandr Rybalko if (node_type == NODE_TYPE_CXLA)
49459191f35SAleksandr Rybalko pmu_cmn600_set8(arg, nodeid, NODE_TYPE_CXLA,
49559191f35SAleksandr Rybalko POR_CXG_RA_CFG_CTL, EN_CXLA_PMUCMD_PROP);
49659191f35SAleksandr Rybalko
49759191f35SAleksandr Rybalko /* 7. Enable DTM. */
49859191f35SAleksandr Rybalko pmu_cmn600_set8(arg, nodeid, NODE_TYPE_XP, POR_DTM_CONTROL,
49959191f35SAleksandr Rybalko POR_DTM_CONTROL_DTM_ENABLE);
50059191f35SAleksandr Rybalko
50159191f35SAleksandr Rybalko /* 8. Reset grouping of global counters. Use 32 bits. */
50259191f35SAleksandr Rybalko pmu_cmn600_clr8(arg, nodeid, NODE_TYPE_DTC, POR_DT_PMCR,
50359191f35SAleksandr Rybalko POR_DT_PMCR_CNTCFG_MASK);
50459191f35SAleksandr Rybalko
50559191f35SAleksandr Rybalko /* 9. Enable DTC. */
50659191f35SAleksandr Rybalko pmu_cmn600_set8(arg, nodeid, NODE_TYPE_DTC, POR_DT_DTC_CTL,
50759191f35SAleksandr Rybalko POR_DT_DTC_CTL_DT_EN);
50859191f35SAleksandr Rybalko
50959191f35SAleksandr Rybalko /* 10. Enable Overflow Interrupt. */
51059191f35SAleksandr Rybalko pmu_cmn600_set8(arg, nodeid, NODE_TYPE_DTC, POR_DT_PMCR,
51159191f35SAleksandr Rybalko POR_DT_PMCR_OVFL_INTR_EN);
51259191f35SAleksandr Rybalko
51359191f35SAleksandr Rybalko /* 11. Run PMC. */
51459191f35SAleksandr Rybalko pmu_cmn600_set8(arg, nodeid, NODE_TYPE_DTC, POR_DT_PMCR,
51559191f35SAleksandr Rybalko POR_DT_PMCR_PMU_EN);
51659191f35SAleksandr Rybalko
51759191f35SAleksandr Rybalko return (0);
51859191f35SAleksandr Rybalko }
51959191f35SAleksandr Rybalko
52059191f35SAleksandr Rybalko /*
52159191f35SAleksandr Rybalko * Stop a PMC.
52259191f35SAleksandr Rybalko */
52359191f35SAleksandr Rybalko
52459191f35SAleksandr Rybalko static int
cmn600_stop_pmc(int cpu,int ri,struct pmc * pm)525*39f92a76SMitchell Horne cmn600_stop_pmc(int cpu, int ri, struct pmc *pm)
52659191f35SAleksandr Rybalko {
52759191f35SAleksandr Rybalko struct cmn600_descr *desc;
52859191f35SAleksandr Rybalko int local_counter;
52959191f35SAleksandr Rybalko uint64_t val;
53059191f35SAleksandr Rybalko
53159191f35SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
53259191f35SAleksandr Rybalko ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu));
53359191f35SAleksandr Rybalko KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__,
53459191f35SAleksandr Rybalko ri));
53559191f35SAleksandr Rybalko
53659191f35SAleksandr Rybalko desc = cmn600desc(ri);
53759191f35SAleksandr Rybalko
53859191f35SAleksandr Rybalko PMCDBG2(MDP, STO, 1, "%s ri=%d", __func__, ri);
53959191f35SAleksandr Rybalko
54059191f35SAleksandr Rybalko /* Disable pairing. */
54159191f35SAleksandr Rybalko local_counter = pm->pm_md.pm_cmn600.pm_cmn600_local_counter;
54259191f35SAleksandr Rybalko pmu_cmn600_clr8(desc->pd_rw_arg, pm->pm_md.pm_cmn600.pm_cmn600_nodeid,
54359191f35SAleksandr Rybalko NODE_TYPE_XP, POR_DTM_PMU_CONFIG, (1 << (local_counter + 4)));
54459191f35SAleksandr Rybalko
54559191f35SAleksandr Rybalko /* Shutdown XP's DTM function if no paired counters. */
54659191f35SAleksandr Rybalko val = pmu_cmn600_rd8(desc->pd_rw_arg,
54759191f35SAleksandr Rybalko pm->pm_md.pm_cmn600.pm_cmn600_nodeid, NODE_TYPE_XP,
54859191f35SAleksandr Rybalko POR_DTM_PMU_CONFIG);
54959191f35SAleksandr Rybalko if ((val & 0xf0) == 0)
55059191f35SAleksandr Rybalko pmu_cmn600_clr8(desc->pd_rw_arg,
55159191f35SAleksandr Rybalko pm->pm_md.pm_cmn600.pm_cmn600_nodeid, NODE_TYPE_XP,
55259191f35SAleksandr Rybalko POR_DTM_PMU_CONFIG, POR_DTM_CONTROL_DTM_ENABLE);
55359191f35SAleksandr Rybalko
55459191f35SAleksandr Rybalko return (0);
55559191f35SAleksandr Rybalko }
55659191f35SAleksandr Rybalko
55759191f35SAleksandr Rybalko /*
55859191f35SAleksandr Rybalko * describe a PMC
55959191f35SAleksandr Rybalko */
56059191f35SAleksandr Rybalko static int
cmn600_describe(int cpu,int ri,struct pmc_info * pi,struct pmc ** ppmc)56159191f35SAleksandr Rybalko cmn600_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
56259191f35SAleksandr Rybalko {
56331610e34SMitchell Horne struct pmc_descr *pd;
56459191f35SAleksandr Rybalko struct pmc_hw *phw;
56559191f35SAleksandr Rybalko
56659191f35SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
56759191f35SAleksandr Rybalko ("[cmn600,%d] illegal CPU %d", __LINE__, cpu));
56859191f35SAleksandr Rybalko KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__,
56959191f35SAleksandr Rybalko ri));
57059191f35SAleksandr Rybalko
57159191f35SAleksandr Rybalko phw = cmn600desc(ri)->pd_phw;
57231610e34SMitchell Horne pd = &cmn600desc(ri)->pd_descr;
57359191f35SAleksandr Rybalko
57431610e34SMitchell Horne strlcpy(pi->pm_name, pd->pd_name, sizeof(pi->pm_name));
57531610e34SMitchell Horne pi->pm_class = pd->pd_class;
57659191f35SAleksandr Rybalko
57759191f35SAleksandr Rybalko if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
57859191f35SAleksandr Rybalko pi->pm_enabled = TRUE;
57959191f35SAleksandr Rybalko *ppmc = phw->phw_pmc;
58059191f35SAleksandr Rybalko } else {
58159191f35SAleksandr Rybalko pi->pm_enabled = FALSE;
58259191f35SAleksandr Rybalko *ppmc = NULL;
58359191f35SAleksandr Rybalko }
58459191f35SAleksandr Rybalko
58559191f35SAleksandr Rybalko return (0);
58659191f35SAleksandr Rybalko }
58759191f35SAleksandr Rybalko
58859191f35SAleksandr Rybalko /*
58959191f35SAleksandr Rybalko * processor dependent initialization.
59059191f35SAleksandr Rybalko */
59159191f35SAleksandr Rybalko
59259191f35SAleksandr Rybalko static int
cmn600_pcpu_init(struct pmc_mdep * md,int cpu)59359191f35SAleksandr Rybalko cmn600_pcpu_init(struct pmc_mdep *md, int cpu)
59459191f35SAleksandr Rybalko {
59559191f35SAleksandr Rybalko int first_ri, n, npmc;
59659191f35SAleksandr Rybalko struct pmc_hw *phw;
59759191f35SAleksandr Rybalko struct pmc_cpu *pc;
59859191f35SAleksandr Rybalko int mdep_class;
59959191f35SAleksandr Rybalko
60059191f35SAleksandr Rybalko mdep_class = PMC_MDEP_CLASS_INDEX_CMN600;
60159191f35SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
60259191f35SAleksandr Rybalko ("[cmn600,%d] insane cpu number %d", __LINE__, cpu));
60359191f35SAleksandr Rybalko
60459191f35SAleksandr Rybalko PMCDBG1(MDP, INI, 1, "cmn600-init cpu=%d", cpu);
60559191f35SAleksandr Rybalko
60659191f35SAleksandr Rybalko /*
60759191f35SAleksandr Rybalko * Set the content of the hardware descriptors to a known
60859191f35SAleksandr Rybalko * state and initialize pointers in the MI per-cpu descriptor.
60959191f35SAleksandr Rybalko */
61059191f35SAleksandr Rybalko
61159191f35SAleksandr Rybalko pc = pmc_pcpu[cpu];
61259191f35SAleksandr Rybalko first_ri = md->pmd_classdep[mdep_class].pcd_ri;
61359191f35SAleksandr Rybalko npmc = md->pmd_classdep[mdep_class].pcd_num;
61459191f35SAleksandr Rybalko
61559191f35SAleksandr Rybalko for (n = 0; n < npmc; n++, phw++) {
61659191f35SAleksandr Rybalko phw = cmn600desc(n)->pd_phw;
61759191f35SAleksandr Rybalko phw->phw_state = PMC_PHW_CPU_TO_STATE(cpu) |
61859191f35SAleksandr Rybalko PMC_PHW_INDEX_TO_STATE(n);
61959191f35SAleksandr Rybalko /* Set enabled only if unit present. */
62059191f35SAleksandr Rybalko if (cmn600_pmcs[class_ri2unit(n)].arg != NULL)
62159191f35SAleksandr Rybalko phw->phw_state |= PMC_PHW_FLAG_IS_ENABLED;
62259191f35SAleksandr Rybalko phw->phw_pmc = NULL;
62359191f35SAleksandr Rybalko pc->pc_hwpmcs[n + first_ri] = phw;
62459191f35SAleksandr Rybalko }
62559191f35SAleksandr Rybalko return (0);
62659191f35SAleksandr Rybalko }
62759191f35SAleksandr Rybalko
62859191f35SAleksandr Rybalko /*
62959191f35SAleksandr Rybalko * processor dependent cleanup prior to the KLD
63059191f35SAleksandr Rybalko * being unloaded
63159191f35SAleksandr Rybalko */
63259191f35SAleksandr Rybalko
63359191f35SAleksandr Rybalko static int
cmn600_pcpu_fini(struct pmc_mdep * md,int cpu)63459191f35SAleksandr Rybalko cmn600_pcpu_fini(struct pmc_mdep *md, int cpu)
63559191f35SAleksandr Rybalko {
63659191f35SAleksandr Rybalko
63759191f35SAleksandr Rybalko return (0);
63859191f35SAleksandr Rybalko }
63959191f35SAleksandr Rybalko
64059191f35SAleksandr Rybalko static int
cmn600_pmu_intr(struct trapframe * tf,int unit,int i)64159191f35SAleksandr Rybalko cmn600_pmu_intr(struct trapframe *tf, int unit, int i)
64259191f35SAleksandr Rybalko {
643d78bef0eSBjoern A. Zeeb struct pmc_cpu *pc __diagused;
64459191f35SAleksandr Rybalko struct pmc_hw *phw;
64559191f35SAleksandr Rybalko struct pmc *pm;
64659191f35SAleksandr Rybalko int error, cpu, ri;
64759191f35SAleksandr Rybalko
64859191f35SAleksandr Rybalko ri = i + unit * CMN600_COUNTERS_N;
64959191f35SAleksandr Rybalko cpu = curcpu;
65059191f35SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
65159191f35SAleksandr Rybalko ("[cmn600,%d] CPU %d out of range", __LINE__, cpu));
65259191f35SAleksandr Rybalko pc = pmc_pcpu[cpu];
65359191f35SAleksandr Rybalko KASSERT(pc != NULL, ("pc != NULL"));
65459191f35SAleksandr Rybalko
65559191f35SAleksandr Rybalko phw = cmn600desc(ri)->pd_phw;
65659191f35SAleksandr Rybalko KASSERT(phw != NULL, ("phw != NULL"));
65759191f35SAleksandr Rybalko pm = phw->phw_pmc;
65859191f35SAleksandr Rybalko if (pm == NULL)
65959191f35SAleksandr Rybalko return (0);
66059191f35SAleksandr Rybalko
66159191f35SAleksandr Rybalko if (!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
66259191f35SAleksandr Rybalko /* Always CPU0. */
66359191f35SAleksandr Rybalko pm->pm_pcpu_state[0].pps_overflowcnt += 1;
66459191f35SAleksandr Rybalko return (0);
66559191f35SAleksandr Rybalko }
66659191f35SAleksandr Rybalko
66759191f35SAleksandr Rybalko if (pm->pm_state != PMC_STATE_RUNNING)
66859191f35SAleksandr Rybalko return (0);
66959191f35SAleksandr Rybalko
67059191f35SAleksandr Rybalko error = pmc_process_interrupt(PMC_HR, pm, tf);
67159191f35SAleksandr Rybalko if (error)
672*39f92a76SMitchell Horne cmn600_stop_pmc(cpu, ri, pm);
67359191f35SAleksandr Rybalko
67459191f35SAleksandr Rybalko /* Reload sampling count */
675*39f92a76SMitchell Horne cmn600_write_pmc(cpu, ri, pm, pm->pm_sc.pm_reloadcount);
67659191f35SAleksandr Rybalko
67759191f35SAleksandr Rybalko return (0);
67859191f35SAleksandr Rybalko }
67959191f35SAleksandr Rybalko
68059191f35SAleksandr Rybalko /*
68159191f35SAleksandr Rybalko * Initialize ourselves.
68259191f35SAleksandr Rybalko */
68359191f35SAleksandr Rybalko static int
cmn600_init_pmc_units(void)68405cef747SAndrew Turner cmn600_init_pmc_units(void)
68559191f35SAleksandr Rybalko {
68659191f35SAleksandr Rybalko int i;
68759191f35SAleksandr Rybalko
68859191f35SAleksandr Rybalko if (cmn600_units > 0) { /* Already initialized. */
68959191f35SAleksandr Rybalko return (0);
69059191f35SAleksandr Rybalko }
69159191f35SAleksandr Rybalko
69259191f35SAleksandr Rybalko cmn600_units = cmn600_pmc_nunits();
69359191f35SAleksandr Rybalko if (cmn600_units == 0)
69459191f35SAleksandr Rybalko return (ENOENT);
69559191f35SAleksandr Rybalko
69659191f35SAleksandr Rybalko for (i = 0; i < cmn600_units; i++) {
69759191f35SAleksandr Rybalko if (cmn600_pmc_getunit(i, &cmn600_pmcs[i].arg,
69859191f35SAleksandr Rybalko &cmn600_pmcs[i].domain) != 0)
69959191f35SAleksandr Rybalko cmn600_pmcs[i].arg = NULL;
70059191f35SAleksandr Rybalko }
70159191f35SAleksandr Rybalko return (0);
70259191f35SAleksandr Rybalko }
70359191f35SAleksandr Rybalko
70459191f35SAleksandr Rybalko int
pmc_cmn600_nclasses(void)70505cef747SAndrew Turner pmc_cmn600_nclasses(void)
70659191f35SAleksandr Rybalko {
70759191f35SAleksandr Rybalko
70859191f35SAleksandr Rybalko if (cmn600_pmc_nunits() > 0)
70959191f35SAleksandr Rybalko return (1);
71059191f35SAleksandr Rybalko return (0);
71159191f35SAleksandr Rybalko }
71259191f35SAleksandr Rybalko
71359191f35SAleksandr Rybalko int
pmc_cmn600_initialize(struct pmc_mdep * md)71459191f35SAleksandr Rybalko pmc_cmn600_initialize(struct pmc_mdep *md)
71559191f35SAleksandr Rybalko {
71659191f35SAleksandr Rybalko struct pmc_classdep *pcd;
71759191f35SAleksandr Rybalko int i, npmc, unit;
71859191f35SAleksandr Rybalko
71959191f35SAleksandr Rybalko cmn600_init_pmc_units();
72059191f35SAleksandr Rybalko KASSERT(md != NULL, ("[cmn600,%d] md is NULL", __LINE__));
72159191f35SAleksandr Rybalko KASSERT(cmn600_units < CMN600_UNIT_MAX,
72259191f35SAleksandr Rybalko ("[cmn600,%d] cmn600_units too big", __LINE__));
72359191f35SAleksandr Rybalko
72459191f35SAleksandr Rybalko PMCDBG0(MDP,INI,1, "cmn600-initialize");
72559191f35SAleksandr Rybalko
72659191f35SAleksandr Rybalko npmc = CMN600_COUNTERS_N * cmn600_units;
72759191f35SAleksandr Rybalko pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_CMN600];
72859191f35SAleksandr Rybalko
72959191f35SAleksandr Rybalko pcd->pcd_caps = PMC_CAP_SYSTEM | PMC_CAP_READ |
73059191f35SAleksandr Rybalko PMC_CAP_WRITE | PMC_CAP_QUALIFIER | PMC_CAP_INTERRUPT |
73159191f35SAleksandr Rybalko PMC_CAP_DOMWIDE;
73259191f35SAleksandr Rybalko pcd->pcd_class = PMC_CLASS_CMN600_PMU;
73359191f35SAleksandr Rybalko pcd->pcd_num = npmc;
73459191f35SAleksandr Rybalko pcd->pcd_ri = md->pmd_npmc;
73559191f35SAleksandr Rybalko pcd->pcd_width = 48;
73659191f35SAleksandr Rybalko
73759191f35SAleksandr Rybalko pcd->pcd_allocate_pmc = cmn600_allocate_pmc;
73859191f35SAleksandr Rybalko pcd->pcd_config_pmc = cmn600_config_pmc;
73959191f35SAleksandr Rybalko pcd->pcd_describe = cmn600_describe;
74059191f35SAleksandr Rybalko pcd->pcd_get_config = cmn600_get_config;
74159191f35SAleksandr Rybalko pcd->pcd_get_msr = NULL;
74259191f35SAleksandr Rybalko pcd->pcd_pcpu_fini = cmn600_pcpu_fini;
74359191f35SAleksandr Rybalko pcd->pcd_pcpu_init = cmn600_pcpu_init;
74459191f35SAleksandr Rybalko pcd->pcd_read_pmc = cmn600_read_pmc;
74559191f35SAleksandr Rybalko pcd->pcd_release_pmc = cmn600_release_pmc;
74659191f35SAleksandr Rybalko pcd->pcd_start_pmc = cmn600_start_pmc;
74759191f35SAleksandr Rybalko pcd->pcd_stop_pmc = cmn600_stop_pmc;
74859191f35SAleksandr Rybalko pcd->pcd_write_pmc = cmn600_write_pmc;
74959191f35SAleksandr Rybalko
75059191f35SAleksandr Rybalko md->pmd_npmc += npmc;
75159191f35SAleksandr Rybalko cmn600_pmcdesc = malloc(sizeof(struct cmn600_descr *) * npmc *
75259191f35SAleksandr Rybalko CMN600_PMU_DEFAULT_UNITS_N, M_PMC, M_WAITOK|M_ZERO);
75359191f35SAleksandr Rybalko for (i = 0; i < npmc; i++) {
75459191f35SAleksandr Rybalko cmn600_pmcdesc[i] = malloc(sizeof(struct cmn600_descr), M_PMC,
75559191f35SAleksandr Rybalko M_WAITOK|M_ZERO);
75659191f35SAleksandr Rybalko
75759191f35SAleksandr Rybalko unit = i / CMN600_COUNTERS_N;
75859191f35SAleksandr Rybalko KASSERT(unit >= 0, ("unit >= 0"));
75959191f35SAleksandr Rybalko KASSERT(cmn600_pmcs[unit].arg != NULL, ("arg != NULL"));
76059191f35SAleksandr Rybalko
76159191f35SAleksandr Rybalko cmn600_pmcdesc[i]->pd_rw_arg = cmn600_pmcs[unit].arg;
76259191f35SAleksandr Rybalko cmn600_pmcdesc[i]->pd_descr.pd_class =
76359191f35SAleksandr Rybalko PMC_CLASS_CMN600_PMU;
76459191f35SAleksandr Rybalko cmn600_pmcdesc[i]->pd_descr.pd_caps = pcd->pcd_caps;
76559191f35SAleksandr Rybalko cmn600_pmcdesc[i]->pd_phw = (struct pmc_hw *)malloc(
76659191f35SAleksandr Rybalko sizeof(struct pmc_hw), M_PMC, M_WAITOK|M_ZERO);
76759191f35SAleksandr Rybalko snprintf(cmn600_pmcdesc[i]->pd_descr.pd_name, 63,
76859191f35SAleksandr Rybalko "CMN600_%d", i);
76959191f35SAleksandr Rybalko cmn600_pmu_intr_cb(cmn600_pmcs[unit].arg, cmn600_pmu_intr);
77059191f35SAleksandr Rybalko }
77159191f35SAleksandr Rybalko
77259191f35SAleksandr Rybalko return (0);
77359191f35SAleksandr Rybalko }
77459191f35SAleksandr Rybalko
77559191f35SAleksandr Rybalko void
pmc_cmn600_finalize(struct pmc_mdep * md)77659191f35SAleksandr Rybalko pmc_cmn600_finalize(struct pmc_mdep *md)
77759191f35SAleksandr Rybalko {
77859191f35SAleksandr Rybalko struct pmc_classdep *pcd;
77959191f35SAleksandr Rybalko int i, npmc;
78059191f35SAleksandr Rybalko
78159191f35SAleksandr Rybalko KASSERT(md->pmd_classdep[PMC_MDEP_CLASS_INDEX_CMN600].pcd_class ==
78259191f35SAleksandr Rybalko PMC_CLASS_CMN600_PMU, ("[cmn600,%d] pmc class mismatch",
78359191f35SAleksandr Rybalko __LINE__));
78459191f35SAleksandr Rybalko
78559191f35SAleksandr Rybalko pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_CMN600];
78659191f35SAleksandr Rybalko
78759191f35SAleksandr Rybalko npmc = pcd->pcd_num;
78859191f35SAleksandr Rybalko for (i = 0; i < npmc; i++) {
78959191f35SAleksandr Rybalko free(cmn600_pmcdesc[i]->pd_phw, M_PMC);
79059191f35SAleksandr Rybalko free(cmn600_pmcdesc[i], M_PMC);
79159191f35SAleksandr Rybalko }
79259191f35SAleksandr Rybalko free(cmn600_pmcdesc, M_PMC);
79359191f35SAleksandr Rybalko cmn600_pmcdesc = NULL;
79459191f35SAleksandr Rybalko }
79559191f35SAleksandr Rybalko
79659191f35SAleksandr Rybalko MODULE_DEPEND(pmc, cmn600, 1, 1, 1);
797