mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-15 21:23:23 +00:00
Merge branch 'for-next/perf' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git
This commit is contained in:
commit
cb272ea815
@ -60,7 +60,7 @@ description of available events and configuration options in sysfs, see
|
||||
The "format" directory describes format of the config fields of the
|
||||
perf_event_attr structure. The "events" directory provides configuration
|
||||
templates for all documented events. For example,
|
||||
"Rx_PCIe_TLP_Data_Payload" is an equivalent of "eventid=0x22,type=0x1".
|
||||
"rx_pcie_tlp_data_payload" is an equivalent of "eventid=0x21,type=0x0".
|
||||
|
||||
The "perf list" command shall list the available events from sysfs, e.g.::
|
||||
|
||||
@ -79,8 +79,8 @@ Example usage of counting PCIe RX TLP data payload (Units of bytes)::
|
||||
|
||||
The average RX/TX bandwidth can be calculated using the following formula:
|
||||
|
||||
PCIe RX Bandwidth = Rx_PCIe_TLP_Data_Payload / Measure_Time_Window
|
||||
PCIe TX Bandwidth = Tx_PCIe_TLP_Data_Payload / Measure_Time_Window
|
||||
PCIe RX Bandwidth = rx_pcie_tlp_data_payload / Measure_Time_Window
|
||||
PCIe TX Bandwidth = tx_pcie_tlp_data_payload / Measure_Time_Window
|
||||
|
||||
Lane Event Usage
|
||||
-------------------------------
|
||||
|
@ -35,7 +35,10 @@ e.g. hisi_sccl1_hha0/rx_operations is RX_OPERATIONS event of HHA index #0 in
|
||||
SCCL ID #1.
|
||||
|
||||
The driver also provides a "cpumask" sysfs attribute, which shows the CPU core
|
||||
ID used to count the uncore PMU event.
|
||||
ID used to count the uncore PMU event. An "associated_cpus" sysfs attribute is
|
||||
also provided to show the CPUs associated with this PMU. The "cpumask" indicates
|
||||
the CPUs to open the events, usually as a hint for userspaces tools like perf.
|
||||
It only contains one associated CPU from the "associated_cpus".
|
||||
|
||||
Example usage of perf::
|
||||
|
||||
|
@ -14,6 +14,8 @@ Performance monitor support
|
||||
qcom_l2_pmu
|
||||
qcom_l3_pmu
|
||||
starfive_starlink_pmu
|
||||
mrvl-odyssey-ddr-pmu
|
||||
mrvl-odyssey-tad-pmu
|
||||
arm-ccn
|
||||
arm-cmn
|
||||
arm-ni
|
||||
|
80
Documentation/admin-guide/perf/mrvl-odyssey-ddr-pmu.rst
Normal file
80
Documentation/admin-guide/perf/mrvl-odyssey-ddr-pmu.rst
Normal file
@ -0,0 +1,80 @@
|
||||
===================================================================
|
||||
Marvell Odyssey DDR PMU Performance Monitoring Unit (PMU UNCORE)
|
||||
===================================================================
|
||||
|
||||
Odyssey DRAM Subsystem supports eight counters for monitoring performance
|
||||
and software can program those counters to monitor any of the defined
|
||||
performance events. Supported performance events include those counted
|
||||
at the interface between the DDR controller and the PHY, interface between
|
||||
the DDR Controller and the CHI interconnect, or within the DDR Controller.
|
||||
|
||||
Additionally DSS also supports two fixed performance event counters, one
|
||||
for ddr reads and the other for ddr writes.
|
||||
|
||||
The counter will be operating in either manual or auto mode.
|
||||
|
||||
The PMU driver exposes the available events and format options under sysfs::
|
||||
|
||||
/sys/bus/event_source/devices/mrvl_ddr_pmu_<>/events/
|
||||
/sys/bus/event_source/devices/mrvl_ddr_pmu_<>/format/
|
||||
|
||||
Examples::
|
||||
|
||||
$ perf list | grep ddr
|
||||
mrvl_ddr_pmu_<>/ddr_act_bypass_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_bsm_alloc/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_bsm_starvation/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_cam_active_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_cam_mwr/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_cam_rd_active_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_cam_rd_or_wr_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_cam_read/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_cam_wr_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_cam_write/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_capar_error/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_crit_ref/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_ddr_reads/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_ddr_writes/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_dfi_cmd_is_retry/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_dfi_cycles/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_dfi_parity_poison/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_dfi_rd_data_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_dfi_wr_data_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_dqsosc_mpc/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_dqsosc_mrr/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_enter_mpsm/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_enter_powerdown/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_enter_selfref/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_hif_pri_rdaccess/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_hif_rd_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_hif_rd_or_wr_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_hif_rmw_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_hif_wr_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_hpri_sched_rd_crit_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_load_mode/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_lpri_sched_rd_crit_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_precharge/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_precharge_for_other/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_precharge_for_rdwr/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_raw_hazard/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_rd_bypass_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_rd_crc_error/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_rd_uc_ecc_error/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_rdwr_transitions/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_refresh/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_retry_fifo_full/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_spec_ref/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_tcr_mrr/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_war_hazard/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_waw_hazard/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_win_limit_reached_rd/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_win_limit_reached_wr/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_wr_crc_error/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_wr_trxn_crit_access/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_write_combine/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_zqcl/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_zqlatch/ [Kernel PMU event]
|
||||
mrvl_ddr_pmu_<>/ddr_zqstart/ [Kernel PMU event]
|
||||
|
||||
$ perf stat -e ddr_cam_read,ddr_cam_write,ddr_cam_active_access,ddr_cam
|
||||
rd_or_wr_access,ddr_cam_rd_active_access,ddr_cam_mwr <workload>
|
37
Documentation/admin-guide/perf/mrvl-odyssey-tad-pmu.rst
Normal file
37
Documentation/admin-guide/perf/mrvl-odyssey-tad-pmu.rst
Normal file
@ -0,0 +1,37 @@
|
||||
====================================================================
|
||||
Marvell Odyssey LLC-TAD Performance Monitoring Unit (PMU UNCORE)
|
||||
====================================================================
|
||||
|
||||
Each TAD provides eight 64-bit counters for monitoring
|
||||
cache behavior.The driver always configures the same counter for
|
||||
all the TADs. The user would end up effectively reserving one of
|
||||
eight counters in every TAD to look across all TADs.
|
||||
The occurrences of events are aggregated and presented to the user
|
||||
at the end of running the workload. The driver does not provide a
|
||||
way for the user to partition TADs so that different TADs are used for
|
||||
different applications.
|
||||
|
||||
The performance events reflect various internal or interface activities.
|
||||
By combining the values from multiple performance counters, cache
|
||||
performance can be measured in terms such as: cache miss rate, cache
|
||||
allocations, interface retry rate, internal resource occupancy, etc.
|
||||
|
||||
The PMU driver exposes the available events and format options under sysfs::
|
||||
|
||||
/sys/bus/event_source/devices/tad/events/
|
||||
/sys/bus/event_source/devices/tad/format/
|
||||
|
||||
Examples::
|
||||
|
||||
$ perf list | grep tad
|
||||
tad/tad_alloc_any/ [Kernel PMU event]
|
||||
tad/tad_alloc_dtg/ [Kernel PMU event]
|
||||
tad/tad_alloc_ltg/ [Kernel PMU event]
|
||||
tad/tad_hit_any/ [Kernel PMU event]
|
||||
tad/tad_hit_dtg/ [Kernel PMU event]
|
||||
tad/tad_hit_ltg/ [Kernel PMU event]
|
||||
tad/tad_req_msh_in_exlmn/ [Kernel PMU event]
|
||||
tad/tad_tag_rd/ [Kernel PMU event]
|
||||
tad/tad_tot_cycle/ [Kernel PMU event]
|
||||
|
||||
$ perf stat -e tad_alloc_dtg,tad_alloc_ltg,tad_alloc_any,tad_hit_dtg,tad_hit_ltg,tad_hit_any,tad_tag_rd <workload>
|
@ -34,7 +34,7 @@ strongly-ordered (SO) PCIE write traffic to local/remote memory. Please see
|
||||
traffic coverage.
|
||||
|
||||
The events and configuration options of this PMU device are described in sysfs,
|
||||
see /sys/bus/event_sources/devices/nvidia_scf_pmu_<socket-id>.
|
||||
see /sys/bus/event_source/devices/nvidia_scf_pmu_<socket-id>.
|
||||
|
||||
Example usage:
|
||||
|
||||
@ -66,7 +66,7 @@ Please see :ref:`NVIDIA_Uncore_PMU_Traffic_Coverage_Section` for more info about
|
||||
the PMU traffic coverage.
|
||||
|
||||
The events and configuration options of this PMU device are described in sysfs,
|
||||
see /sys/bus/event_sources/devices/nvidia_nvlink_c2c0_pmu_<socket-id>.
|
||||
see /sys/bus/event_source/devices/nvidia_nvlink_c2c0_pmu_<socket-id>.
|
||||
|
||||
Example usage:
|
||||
|
||||
@ -86,6 +86,22 @@ Example usage:
|
||||
|
||||
perf stat -a -e nvidia_nvlink_c2c0_pmu_3/event=0x0/
|
||||
|
||||
The NVLink-C2C has two ports that can be connected to one GPU (occupying both
|
||||
ports) or to two GPUs (one GPU per port). The user can use "port" bitmap
|
||||
parameter to select the port(s) to monitor. Each bit represents the port number,
|
||||
e.g. "port=0x1" corresponds to port 0 and "port=0x3" is for port 0 and 1. The
|
||||
PMU will monitor both ports by default if not specified.
|
||||
|
||||
Example for port filtering:
|
||||
|
||||
* Count event id 0x0 from the GPU connected with socket 0 on port 0::
|
||||
|
||||
perf stat -a -e nvidia_nvlink_c2c0_pmu_0/event=0x0,port=0x1/
|
||||
|
||||
* Count event id 0x0 from the GPUs connected with socket 0 on port 0 and port 1::
|
||||
|
||||
perf stat -a -e nvidia_nvlink_c2c0_pmu_0/event=0x0,port=0x3/
|
||||
|
||||
NVLink-C2C1 PMU
|
||||
-------------------
|
||||
|
||||
@ -96,7 +112,7 @@ Please see :ref:`NVIDIA_Uncore_PMU_Traffic_Coverage_Section` for more info about
|
||||
the PMU traffic coverage.
|
||||
|
||||
The events and configuration options of this PMU device are described in sysfs,
|
||||
see /sys/bus/event_sources/devices/nvidia_nvlink_c2c1_pmu_<socket-id>.
|
||||
see /sys/bus/event_source/devices/nvidia_nvlink_c2c1_pmu_<socket-id>.
|
||||
|
||||
Example usage:
|
||||
|
||||
@ -116,6 +132,22 @@ Example usage:
|
||||
|
||||
perf stat -a -e nvidia_nvlink_c2c1_pmu_3/event=0x0/
|
||||
|
||||
The NVLink-C2C has two ports that can be connected to one GPU (occupying both
|
||||
ports) or to two GPUs (one GPU per port). The user can use "port" bitmap
|
||||
parameter to select the port(s) to monitor. Each bit represents the port number,
|
||||
e.g. "port=0x1" corresponds to port 0 and "port=0x3" is for port 0 and 1. The
|
||||
PMU will monitor both ports by default if not specified.
|
||||
|
||||
Example for port filtering:
|
||||
|
||||
* Count event id 0x0 from the GPU connected with socket 0 on port 0::
|
||||
|
||||
perf stat -a -e nvidia_nvlink_c2c1_pmu_0/event=0x0,port=0x1/
|
||||
|
||||
* Count event id 0x0 from the GPUs connected with socket 0 on port 0 and port 1::
|
||||
|
||||
perf stat -a -e nvidia_nvlink_c2c1_pmu_0/event=0x0,port=0x3/
|
||||
|
||||
CNVLink PMU
|
||||
---------------
|
||||
|
||||
@ -125,13 +157,14 @@ to local memory. For PCIE traffic, this PMU captures read and relaxed ordered
|
||||
for more info about the PMU traffic coverage.
|
||||
|
||||
The events and configuration options of this PMU device are described in sysfs,
|
||||
see /sys/bus/event_sources/devices/nvidia_cnvlink_pmu_<socket-id>.
|
||||
see /sys/bus/event_source/devices/nvidia_cnvlink_pmu_<socket-id>.
|
||||
|
||||
Each SoC socket can be connected to one or more sockets via CNVLink. The user can
|
||||
use "rem_socket" bitmap parameter to select the remote socket(s) to monitor.
|
||||
Each bit represents the socket number, e.g. "rem_socket=0xE" corresponds to
|
||||
socket 1 to 3.
|
||||
/sys/bus/event_sources/devices/nvidia_cnvlink_pmu_<socket-id>/format/rem_socket
|
||||
socket 1 to 3. The PMU will monitor all remote sockets by default if not
|
||||
specified.
|
||||
/sys/bus/event_source/devices/nvidia_cnvlink_pmu_<socket-id>/format/rem_socket
|
||||
shows the valid bits that can be set in the "rem_socket" parameter.
|
||||
|
||||
The PMU can not distinguish the remote traffic initiator, therefore it does not
|
||||
@ -165,12 +198,13 @@ local/remote memory. Please see :ref:`NVIDIA_Uncore_PMU_Traffic_Coverage_Section
|
||||
for more info about the PMU traffic coverage.
|
||||
|
||||
The events and configuration options of this PMU device are described in sysfs,
|
||||
see /sys/bus/event_sources/devices/nvidia_pcie_pmu_<socket-id>.
|
||||
see /sys/bus/event_source/devices/nvidia_pcie_pmu_<socket-id>.
|
||||
|
||||
Each SoC socket can support multiple root ports. The user can use
|
||||
"root_port" bitmap parameter to select the port(s) to monitor, i.e.
|
||||
"root_port=0xF" corresponds to root port 0 to 3.
|
||||
/sys/bus/event_sources/devices/nvidia_pcie_pmu_<socket-id>/format/root_port
|
||||
"root_port=0xF" corresponds to root port 0 to 3. The PMU will monitor all root
|
||||
ports by default if not specified.
|
||||
/sys/bus/event_source/devices/nvidia_pcie_pmu_<socket-id>/format/root_port
|
||||
shows the valid bits that can be set in the "root_port" parameter.
|
||||
|
||||
Example usage:
|
||||
|
@ -1713,8 +1713,8 @@ static int arm_cmn_validate_group(struct arm_cmn *cmn, struct perf_event *event)
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < CMN_MAX_DTCS; i++)
|
||||
if (val->dtc_count[i] == CMN_DT_NUM_COUNTERS)
|
||||
for_each_hw_dtc_idx(hw, dtc, idx)
|
||||
if (val->dtc_count[dtc] == CMN_DT_NUM_COUNTERS)
|
||||
goto done;
|
||||
|
||||
for_each_hw_dn(hw, dn, i) {
|
||||
|
@ -54,65 +54,24 @@ static struct attribute *scf_pmu_event_attrs[] = {
|
||||
ARM_CSPMU_EVENT_ATTR(scf_cache_wb, 0xF3),
|
||||
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, rd_data, 0x101),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, dl_rsp, 0x105),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, wb_data, 0x109),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, ev_rsp, 0x10d),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, prb_data, 0x111),
|
||||
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, rd_outstanding, 0x115),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, dl_outstanding, 0x119),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, wb_outstanding, 0x11d),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, wr_outstanding, 0x121),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, ev_outstanding, 0x125),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, prb_outstanding, 0x129),
|
||||
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, rd_access, 0x12d),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, dl_access, 0x131),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, wb_access, 0x135),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, wr_access, 0x139),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, ev_access, 0x13d),
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, prb_access, 0x141),
|
||||
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, gmem_rd_data, 0x145),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, gmem_rd_access, 0x149),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wb_access, 0x14d),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, gmem_rd_outstanding, 0x151),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wr_outstanding, 0x155),
|
||||
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, rem_rd_data, 0x159),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, rem_rd_access, 0x15d),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, rem_wb_access, 0x161),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, rem_rd_outstanding, 0x165),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, rem_wr_outstanding, 0x169),
|
||||
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_rd_data, 0x16d),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_rd_access, 0x16e),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_rd_outstanding, 0x16f),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_dl_rsp, 0x170),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_dl_access, 0x171),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_dl_outstanding, 0x172),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_wb_data, 0x173),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_wb_access, 0x174),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_wb_outstanding, 0x175),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_ev_rsp, 0x176),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_ev_access, 0x177),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_ev_outstanding, 0x178),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_wr_data, 0x179),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_wr_outstanding, 0x17a),
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_wr_access, 0x17b),
|
||||
|
||||
NV_CSPMU_EVENT_ATTR_4(socket, wr_data, 0x17c),
|
||||
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wr_data, 0x180),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wb_data, 0x184),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wr_access, 0x188),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, gmem_wb_outstanding, 0x18c),
|
||||
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, rem_wr_data, 0x190),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, rem_wb_data, 0x194),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, rem_wr_access, 0x198),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, rem_wb_outstanding, 0x19c),
|
||||
|
||||
ARM_CSPMU_EVENT_ATTR(gmem_wr_total_bytes, 0x1a0),
|
||||
ARM_CSPMU_EVENT_ATTR(remote_socket_wr_total_bytes, 0x1a1),
|
||||
ARM_CSPMU_EVENT_ATTR(remote_socket_rd_data, 0x1a2),
|
||||
@ -122,35 +81,12 @@ static struct attribute *scf_pmu_event_attrs[] = {
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_rd_data, 0x1a5),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_rd_access, 0x1a6),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_rd_outstanding, 0x1a7),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_dl_rsp, 0x1a8),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_dl_access, 0x1a9),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_dl_outstanding, 0x1aa),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_wb_data, 0x1ab),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_wb_access, 0x1ac),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_wb_outstanding, 0x1ad),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_ev_rsp, 0x1ae),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_ev_access, 0x1af),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_ev_outstanding, 0x1b0),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_wr_data, 0x1b1),
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_wr_outstanding, 0x1b2),
|
||||
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, cmem_rd_data, 0x1b3),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, cmem_rd_access, 0x1b7),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wb_access, 0x1bb),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, cmem_rd_outstanding, 0x1bf),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wr_outstanding, 0x1c3),
|
||||
|
||||
ARM_CSPMU_EVENT_ATTR(ocu_prb_access, 0x1c7),
|
||||
ARM_CSPMU_EVENT_ATTR(ocu_prb_data, 0x1c8),
|
||||
ARM_CSPMU_EVENT_ATTR(ocu_prb_outstanding, 0x1c9),
|
||||
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_wr_access, 0x1ca),
|
||||
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wr_access, 0x1cb),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wb_data, 0x1cf),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wr_data, 0x1d3),
|
||||
NV_CSPMU_EVENT_ATTR_4(ocu, cmem_wb_outstanding, 0x1d7),
|
||||
|
||||
ARM_CSPMU_EVENT_ATTR(cmem_wr_total_bytes, 0x1db),
|
||||
|
||||
ARM_CSPMU_EVENT_ATTR(cycles, ARM_CSPMU_EVT_CYCLES_DEFAULT),
|
||||
@ -194,6 +130,7 @@ static struct attribute *pcie_pmu_format_attrs[] = {
|
||||
|
||||
static struct attribute *nvlink_c2c_pmu_format_attrs[] = {
|
||||
ARM_CSPMU_FORMAT_EVENT_ATTR,
|
||||
ARM_CSPMU_FORMAT_ATTR(port, "config1:0-1"),
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -238,10 +175,12 @@ static u32 nv_cspmu_event_filter(const struct perf_event *event)
|
||||
const struct nv_cspmu_ctx *ctx =
|
||||
to_nv_cspmu_ctx(to_arm_cspmu(event->pmu));
|
||||
|
||||
if (ctx->filter_mask == 0)
|
||||
const u32 filter_val = event->attr.config1 & ctx->filter_mask;
|
||||
|
||||
if (filter_val == 0)
|
||||
return ctx->filter_default_val;
|
||||
|
||||
return event->attr.config1 & ctx->filter_mask;
|
||||
return filter_val;
|
||||
}
|
||||
|
||||
enum nv_cspmu_name_fmt {
|
||||
@ -274,7 +213,7 @@ static const struct nv_cspmu_match nv_cspmu_match[] = {
|
||||
{
|
||||
.prodid = 0x104,
|
||||
.prodid_mask = NV_PRODID_MASK,
|
||||
.filter_mask = 0x0,
|
||||
.filter_mask = NV_NVL_C2C_FILTER_ID_MASK,
|
||||
.filter_default_val = NV_NVL_C2C_FILTER_ID_MASK,
|
||||
.name_pattern = "nvidia_nvlink_c2c1_pmu_%u",
|
||||
.name_fmt = NAME_FMT_SOCKET,
|
||||
@ -284,7 +223,7 @@ static const struct nv_cspmu_match nv_cspmu_match[] = {
|
||||
{
|
||||
.prodid = 0x105,
|
||||
.prodid_mask = NV_PRODID_MASK,
|
||||
.filter_mask = 0x0,
|
||||
.filter_mask = NV_NVL_C2C_FILTER_ID_MASK,
|
||||
.filter_default_val = NV_NVL_C2C_FILTER_ID_MASK,
|
||||
.name_pattern = "nvidia_nvlink_c2c0_pmu_%u",
|
||||
.name_fmt = NAME_FMT_SOCKET,
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define DWC_PCIE_VSEC_RAS_DES_ID 0x02
|
||||
#define DWC_PCIE_EVENT_CNT_CTL 0x8
|
||||
|
||||
/*
|
||||
@ -100,14 +99,23 @@ struct dwc_pcie_dev_info {
|
||||
struct list_head dev_node;
|
||||
};
|
||||
|
||||
struct dwc_pcie_vendor_id {
|
||||
int vendor_id;
|
||||
struct dwc_pcie_pmu_vsec_id {
|
||||
u16 vendor_id;
|
||||
u16 vsec_id;
|
||||
u8 vsec_rev;
|
||||
};
|
||||
|
||||
static const struct dwc_pcie_vendor_id dwc_pcie_vendor_ids[] = {
|
||||
{.vendor_id = PCI_VENDOR_ID_ALIBABA },
|
||||
{.vendor_id = PCI_VENDOR_ID_AMPERE },
|
||||
{.vendor_id = PCI_VENDOR_ID_QCOM },
|
||||
/*
|
||||
* VSEC IDs are allocated by the vendor, so a given ID may mean different
|
||||
* things to different vendors. See PCIe r6.0, sec 7.9.5.2.
|
||||
*/
|
||||
static const struct dwc_pcie_pmu_vsec_id dwc_pcie_pmu_vsec_ids[] = {
|
||||
{ .vendor_id = PCI_VENDOR_ID_ALIBABA,
|
||||
.vsec_id = 0x02, .vsec_rev = 0x4 },
|
||||
{ .vendor_id = PCI_VENDOR_ID_AMPERE,
|
||||
.vsec_id = 0x02, .vsec_rev = 0x4 },
|
||||
{ .vendor_id = PCI_VENDOR_ID_QCOM,
|
||||
.vsec_id = 0x02, .vsec_rev = 0x4 },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
@ -199,8 +207,8 @@ static struct attribute *dwc_pcie_pmu_time_event_attrs[] = {
|
||||
DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(L1_1, 0x05),
|
||||
DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(L1_2, 0x06),
|
||||
DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(CFG_RCVRY, 0x07),
|
||||
DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(TX_RX_L0S, 0x08),
|
||||
DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(L1_AUX, 0x09),
|
||||
DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(L1_AUX, 0x08),
|
||||
DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(TX_RX_L0S, 0x09),
|
||||
|
||||
/* Group #1 */
|
||||
DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(tx_pcie_tlp_data_payload, 0x20),
|
||||
@ -519,31 +527,28 @@ static void dwc_pcie_unregister_pmu(void *data)
|
||||
perf_pmu_unregister(&pcie_pmu->pmu);
|
||||
}
|
||||
|
||||
static bool dwc_pcie_match_des_cap(struct pci_dev *pdev)
|
||||
static u16 dwc_pcie_des_cap(struct pci_dev *pdev)
|
||||
{
|
||||
const struct dwc_pcie_vendor_id *vid;
|
||||
u16 vsec = 0;
|
||||
const struct dwc_pcie_pmu_vsec_id *vid;
|
||||
u16 vsec;
|
||||
u32 val;
|
||||
|
||||
if (!pci_is_pcie(pdev) || !(pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
for (vid = dwc_pcie_vendor_ids; vid->vendor_id; vid++) {
|
||||
for (vid = dwc_pcie_pmu_vsec_ids; vid->vendor_id; vid++) {
|
||||
vsec = pci_find_vsec_capability(pdev, vid->vendor_id,
|
||||
DWC_PCIE_VSEC_RAS_DES_ID);
|
||||
if (vsec)
|
||||
break;
|
||||
vid->vsec_id);
|
||||
if (vsec) {
|
||||
pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER,
|
||||
&val);
|
||||
if (PCI_VNDR_HEADER_REV(val) == vid->vsec_rev) {
|
||||
pci_dbg(pdev, "Detected PCIe Vendor-Specific Extended Capability RAS DES\n");
|
||||
return vsec;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!vsec)
|
||||
return false;
|
||||
|
||||
pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val);
|
||||
if (PCI_VNDR_HEADER_REV(val) != 0x04)
|
||||
return false;
|
||||
|
||||
pci_dbg(pdev,
|
||||
"Detected PCIe Vendor-Specific Extended Capability RAS DES\n");
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc_pcie_unregister_dev(struct dwc_pcie_dev_info *dev_info)
|
||||
@ -587,7 +592,7 @@ static int dwc_pcie_pmu_notifier(struct notifier_block *nb,
|
||||
|
||||
switch (action) {
|
||||
case BUS_NOTIFY_ADD_DEVICE:
|
||||
if (!dwc_pcie_match_des_cap(pdev))
|
||||
if (!dwc_pcie_des_cap(pdev))
|
||||
return NOTIFY_DONE;
|
||||
if (dwc_pcie_register_dev(pdev))
|
||||
return NOTIFY_BAD;
|
||||
@ -612,13 +617,14 @@ static int dwc_pcie_pmu_probe(struct platform_device *plat_dev)
|
||||
struct pci_dev *pdev = plat_dev->dev.platform_data;
|
||||
struct dwc_pcie_pmu *pcie_pmu;
|
||||
char *name;
|
||||
u32 sbdf, val;
|
||||
u32 sbdf;
|
||||
u16 vsec;
|
||||
int ret;
|
||||
|
||||
vsec = pci_find_vsec_capability(pdev, pdev->vendor,
|
||||
DWC_PCIE_VSEC_RAS_DES_ID);
|
||||
pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val);
|
||||
vsec = dwc_pcie_des_cap(pdev);
|
||||
if (!vsec)
|
||||
return -ENODEV;
|
||||
|
||||
sbdf = plat_dev->id;
|
||||
name = devm_kasprintf(&plat_dev->dev, GFP_KERNEL, "dwc_rootport_%x", sbdf);
|
||||
if (!name)
|
||||
@ -730,7 +736,7 @@ static int __init dwc_pcie_pmu_init(void)
|
||||
int ret;
|
||||
|
||||
for_each_pci_dev(pdev) {
|
||||
if (!dwc_pcie_match_des_cap(pdev))
|
||||
if (!dwc_pcie_des_cap(pdev))
|
||||
continue;
|
||||
|
||||
ret = dwc_pcie_register_dev(pdev);
|
||||
|
@ -63,8 +63,21 @@
|
||||
|
||||
static DEFINE_IDA(ddr_ida);
|
||||
|
||||
/*
|
||||
* V1 support 1 read transaction, 1 write transaction and 1 read beats
|
||||
* event which corresponding respecitively to counter 2, 3 and 4.
|
||||
*/
|
||||
#define DDR_PERF_AXI_FILTER_V1 0x1
|
||||
|
||||
/*
|
||||
* V2 support 1 read beats and 3 write beats events which corresponding
|
||||
* respecitively to counter 2-5.
|
||||
*/
|
||||
#define DDR_PERF_AXI_FILTER_V2 0x2
|
||||
|
||||
struct imx_ddr_devtype_data {
|
||||
const char *identifier; /* system PMU identifier for userspace */
|
||||
unsigned int filter_ver; /* AXI filter version */
|
||||
};
|
||||
|
||||
struct ddr_pmu {
|
||||
@ -83,24 +96,27 @@ struct ddr_pmu {
|
||||
|
||||
static const struct imx_ddr_devtype_data imx91_devtype_data = {
|
||||
.identifier = "imx91",
|
||||
.filter_ver = DDR_PERF_AXI_FILTER_V1
|
||||
};
|
||||
|
||||
static const struct imx_ddr_devtype_data imx93_devtype_data = {
|
||||
.identifier = "imx93",
|
||||
.filter_ver = DDR_PERF_AXI_FILTER_V1
|
||||
};
|
||||
|
||||
static const struct imx_ddr_devtype_data imx95_devtype_data = {
|
||||
.identifier = "imx95",
|
||||
.filter_ver = DDR_PERF_AXI_FILTER_V2
|
||||
};
|
||||
|
||||
static inline bool is_imx93(struct ddr_pmu *pmu)
|
||||
static inline bool axi_filter_v1(struct ddr_pmu *pmu)
|
||||
{
|
||||
return pmu->devtype_data == &imx93_devtype_data;
|
||||
return pmu->devtype_data->filter_ver == DDR_PERF_AXI_FILTER_V1;
|
||||
}
|
||||
|
||||
static inline bool is_imx95(struct ddr_pmu *pmu)
|
||||
static inline bool axi_filter_v2(struct ddr_pmu *pmu)
|
||||
{
|
||||
return pmu->devtype_data == &imx95_devtype_data;
|
||||
return pmu->devtype_data->filter_ver == DDR_PERF_AXI_FILTER_V2;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_ddr_pmu_dt_ids[] = {
|
||||
@ -155,7 +171,7 @@ static const struct attribute_group ddr_perf_cpumask_attr_group = {
|
||||
struct imx9_pmu_events_attr {
|
||||
struct device_attribute attr;
|
||||
u64 id;
|
||||
const void *devtype_data;
|
||||
const struct imx_ddr_devtype_data *devtype_data;
|
||||
};
|
||||
|
||||
static ssize_t ddr_pmu_event_show(struct device *dev,
|
||||
@ -307,7 +323,8 @@ ddr_perf_events_attrs_is_visible(struct kobject *kobj,
|
||||
if (!eattr->devtype_data)
|
||||
return attr->mode;
|
||||
|
||||
if (eattr->devtype_data != ddr_pmu->devtype_data)
|
||||
if (eattr->devtype_data != ddr_pmu->devtype_data &&
|
||||
eattr->devtype_data->filter_ver != ddr_pmu->devtype_data->filter_ver)
|
||||
return 0;
|
||||
|
||||
return attr->mode;
|
||||
@ -624,11 +641,11 @@ static int ddr_perf_event_add(struct perf_event *event, int flags)
|
||||
hwc->idx = counter;
|
||||
hwc->state |= PERF_HES_STOPPED;
|
||||
|
||||
if (is_imx93(pmu))
|
||||
if (axi_filter_v1(pmu))
|
||||
/* read trans, write trans, read beat */
|
||||
imx93_ddr_perf_monitor_config(pmu, event_id, counter, cfg1, cfg2);
|
||||
|
||||
if (is_imx95(pmu))
|
||||
if (axi_filter_v2(pmu))
|
||||
/* write beat, read beat2, read beat1, read beat */
|
||||
imx95_ddr_perf_monitor_config(pmu, event_id, counter, cfg1, cfg2);
|
||||
|
||||
|
@ -180,20 +180,18 @@ MODULE_DEVICE_TABLE(acpi, hisi_cpa_pmu_acpi_match);
|
||||
static int hisi_cpa_pmu_init_data(struct platform_device *pdev,
|
||||
struct hisi_pmu *cpa_pmu)
|
||||
{
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
|
||||
&cpa_pmu->sicl_id)) {
|
||||
hisi_uncore_pmu_init_topology(cpa_pmu, &pdev->dev);
|
||||
|
||||
if (cpa_pmu->topo.sicl_id < 0) {
|
||||
dev_err(&pdev->dev, "Can not read sicl-id\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
|
||||
&cpa_pmu->index_id)) {
|
||||
if (cpa_pmu->topo.index_id < 0) {
|
||||
dev_err(&pdev->dev, "Cannot read idx-id\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpa_pmu->ccl_id = -1;
|
||||
cpa_pmu->sccl_id = -1;
|
||||
cpa_pmu->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(cpa_pmu->base))
|
||||
return PTR_ERR(cpa_pmu->base);
|
||||
@ -227,34 +225,11 @@ static const struct attribute_group hisi_cpa_pmu_events_group = {
|
||||
.attrs = hisi_cpa_pmu_events_attr,
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
|
||||
|
||||
static struct attribute *hisi_cpa_pmu_cpumask_attrs[] = {
|
||||
&dev_attr_cpumask.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_cpa_pmu_cpumask_attr_group = {
|
||||
.attrs = hisi_cpa_pmu_cpumask_attrs,
|
||||
};
|
||||
|
||||
static struct device_attribute hisi_cpa_pmu_identifier_attr =
|
||||
__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
|
||||
|
||||
static struct attribute *hisi_cpa_pmu_identifier_attrs[] = {
|
||||
&hisi_cpa_pmu_identifier_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_cpa_pmu_identifier_group = {
|
||||
.attrs = hisi_cpa_pmu_identifier_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *hisi_cpa_pmu_attr_groups[] = {
|
||||
&hisi_cpa_pmu_format_group,
|
||||
&hisi_cpa_pmu_events_group,
|
||||
&hisi_cpa_pmu_cpumask_attr_group,
|
||||
&hisi_cpa_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -311,8 +286,8 @@ static int hisi_cpa_pmu_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sicl%d_cpa%u",
|
||||
cpa_pmu->sicl_id, cpa_pmu->index_id);
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sicl%d_cpa%d",
|
||||
cpa_pmu->topo.sicl_id, cpa_pmu->topo.index_id);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -389,6 +364,7 @@ static void __exit hisi_cpa_pmu_module_exit(void)
|
||||
}
|
||||
module_exit(hisi_cpa_pmu_module_exit);
|
||||
|
||||
MODULE_IMPORT_NS("HISI_PMU");
|
||||
MODULE_DESCRIPTION("HiSilicon SoC CPA PMU driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
|
||||
|
@ -111,14 +111,14 @@ static void hisi_ddrc_pmu_v2_write_counter(struct hisi_pmu *ddrc_pmu,
|
||||
* so there is no need to write event type, while it is programmable counter in
|
||||
* PMU v2.
|
||||
*/
|
||||
static void hisi_ddrc_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
|
||||
static void hisi_ddrc_pmu_write_evtype(struct hisi_pmu *ddrc_pmu, int idx,
|
||||
u32 type)
|
||||
{
|
||||
u32 offset;
|
||||
|
||||
if (hha_pmu->identifier >= HISI_PMU_V2) {
|
||||
if (ddrc_pmu->identifier >= HISI_PMU_V2) {
|
||||
offset = DDRC_V2_EVENT_TYPE + 4 * idx;
|
||||
writel(type, hha_pmu->base + offset);
|
||||
writel(type, ddrc_pmu->base + offset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,23 +297,22 @@ MODULE_DEVICE_TABLE(acpi, hisi_ddrc_pmu_acpi_match);
|
||||
static int hisi_ddrc_pmu_init_data(struct platform_device *pdev,
|
||||
struct hisi_pmu *ddrc_pmu)
|
||||
{
|
||||
hisi_uncore_pmu_init_topology(ddrc_pmu, &pdev->dev);
|
||||
|
||||
/*
|
||||
* Use the SCCL_ID and DDRC channel ID to identify the
|
||||
* DDRC PMU, while SCCL_ID is in MPIDR[aff2].
|
||||
*/
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,ch-id",
|
||||
&ddrc_pmu->index_id)) {
|
||||
&ddrc_pmu->topo.index_id)) {
|
||||
dev_err(&pdev->dev, "Can not read ddrc channel-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
|
||||
&ddrc_pmu->sccl_id)) {
|
||||
if (ddrc_pmu->topo.sccl_id < 0) {
|
||||
dev_err(&pdev->dev, "Can not read ddrc sccl-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* DDRC PMUs only share the same SCCL */
|
||||
ddrc_pmu->ccl_id = -1;
|
||||
|
||||
ddrc_pmu->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ddrc_pmu->base)) {
|
||||
@ -323,8 +322,7 @@ static int hisi_ddrc_pmu_init_data(struct platform_device *pdev,
|
||||
|
||||
ddrc_pmu->identifier = readl(ddrc_pmu->base + DDRC_VERSION);
|
||||
if (ddrc_pmu->identifier >= HISI_PMU_V2) {
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,sub-id",
|
||||
&ddrc_pmu->sub_id)) {
|
||||
if (ddrc_pmu->topo.sub_id < 0) {
|
||||
dev_err(&pdev->dev, "Can not read sub-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -382,42 +380,19 @@ static const struct attribute_group hisi_ddrc_pmu_v2_events_group = {
|
||||
.attrs = hisi_ddrc_pmu_v2_events_attr,
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
|
||||
|
||||
static struct attribute *hisi_ddrc_pmu_cpumask_attrs[] = {
|
||||
&dev_attr_cpumask.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_ddrc_pmu_cpumask_attr_group = {
|
||||
.attrs = hisi_ddrc_pmu_cpumask_attrs,
|
||||
};
|
||||
|
||||
static struct device_attribute hisi_ddrc_pmu_identifier_attr =
|
||||
__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
|
||||
|
||||
static struct attribute *hisi_ddrc_pmu_identifier_attrs[] = {
|
||||
&hisi_ddrc_pmu_identifier_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_ddrc_pmu_identifier_group = {
|
||||
.attrs = hisi_ddrc_pmu_identifier_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *hisi_ddrc_pmu_v1_attr_groups[] = {
|
||||
&hisi_ddrc_pmu_v1_format_group,
|
||||
&hisi_ddrc_pmu_v1_events_group,
|
||||
&hisi_ddrc_pmu_cpumask_attr_group,
|
||||
&hisi_ddrc_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group *hisi_ddrc_pmu_v2_attr_groups[] = {
|
||||
&hisi_ddrc_pmu_v2_format_group,
|
||||
&hisi_ddrc_pmu_v2_events_group,
|
||||
&hisi_ddrc_pmu_cpumask_attr_group,
|
||||
&hisi_ddrc_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -501,13 +476,13 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
|
||||
|
||||
if (ddrc_pmu->identifier >= HISI_PMU_V2)
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
|
||||
"hisi_sccl%u_ddrc%u_%u",
|
||||
ddrc_pmu->sccl_id, ddrc_pmu->index_id,
|
||||
ddrc_pmu->sub_id);
|
||||
"hisi_sccl%d_ddrc%d_%d",
|
||||
ddrc_pmu->topo.sccl_id, ddrc_pmu->topo.index_id,
|
||||
ddrc_pmu->topo.sub_id);
|
||||
else
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
|
||||
"hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id,
|
||||
ddrc_pmu->index_id);
|
||||
"hisi_sccl%d_ddrc%d", ddrc_pmu->topo.sccl_id,
|
||||
ddrc_pmu->topo.index_id);
|
||||
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
@ -575,10 +550,10 @@ static void __exit hisi_ddrc_pmu_module_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&hisi_ddrc_pmu_driver);
|
||||
cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE);
|
||||
|
||||
}
|
||||
module_exit(hisi_ddrc_pmu_module_exit);
|
||||
|
||||
MODULE_IMPORT_NS("HISI_PMU");
|
||||
MODULE_DESCRIPTION("HiSilicon SoC DDRC uncore PMU driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
|
||||
|
@ -295,12 +295,13 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
|
||||
unsigned long long id;
|
||||
acpi_status status;
|
||||
|
||||
hisi_uncore_pmu_init_topology(hha_pmu, &pdev->dev);
|
||||
|
||||
/*
|
||||
* Use SCCL_ID and UID to identify the HHA PMU, while
|
||||
* SCCL_ID is in MPIDR[aff2].
|
||||
*/
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
|
||||
&hha_pmu->sccl_id)) {
|
||||
if (hha_pmu->topo.sccl_id < 0) {
|
||||
dev_err(&pdev->dev, "Can not read hha sccl-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -309,8 +310,7 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
|
||||
* Early versions of BIOS support _UID by mistake, so we support
|
||||
* both "hisilicon, idx-id" as preference, if available.
|
||||
*/
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
|
||||
&hha_pmu->index_id)) {
|
||||
if (hha_pmu->topo.index_id < 0) {
|
||||
status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev),
|
||||
"_UID", NULL, &id);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
@ -318,10 +318,8 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hha_pmu->index_id = id;
|
||||
hha_pmu->topo.index_id = id;
|
||||
}
|
||||
/* HHA PMUs only share the same SCCL */
|
||||
hha_pmu->ccl_id = -1;
|
||||
|
||||
hha_pmu->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hha_pmu->base)) {
|
||||
@ -407,42 +405,19 @@ static const struct attribute_group hisi_hha_pmu_v2_events_group = {
|
||||
.attrs = hisi_hha_pmu_v2_events_attr,
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
|
||||
|
||||
static struct attribute *hisi_hha_pmu_cpumask_attrs[] = {
|
||||
&dev_attr_cpumask.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_hha_pmu_cpumask_attr_group = {
|
||||
.attrs = hisi_hha_pmu_cpumask_attrs,
|
||||
};
|
||||
|
||||
static struct device_attribute hisi_hha_pmu_identifier_attr =
|
||||
__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
|
||||
|
||||
static struct attribute *hisi_hha_pmu_identifier_attrs[] = {
|
||||
&hisi_hha_pmu_identifier_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_hha_pmu_identifier_group = {
|
||||
.attrs = hisi_hha_pmu_identifier_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *hisi_hha_pmu_v1_attr_groups[] = {
|
||||
&hisi_hha_pmu_v1_format_group,
|
||||
&hisi_hha_pmu_v1_events_group,
|
||||
&hisi_hha_pmu_cpumask_attr_group,
|
||||
&hisi_hha_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group *hisi_hha_pmu_v2_attr_groups[] = {
|
||||
&hisi_hha_pmu_v2_format_group,
|
||||
&hisi_hha_pmu_v2_events_group,
|
||||
&hisi_hha_pmu_cpumask_attr_group,
|
||||
&hisi_hha_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -510,8 +485,8 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_hha%u",
|
||||
hha_pmu->sccl_id, hha_pmu->index_id);
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%d_hha%d",
|
||||
hha_pmu->topo.sccl_id, hha_pmu->topo.index_id);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -581,6 +556,7 @@ static void __exit hisi_hha_pmu_module_exit(void)
|
||||
}
|
||||
module_exit(hisi_hha_pmu_module_exit);
|
||||
|
||||
MODULE_IMPORT_NS("HISI_PMU");
|
||||
MODULE_DESCRIPTION("HiSilicon SoC HHA uncore PMU driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
|
||||
|
@ -355,18 +355,18 @@ MODULE_DEVICE_TABLE(acpi, hisi_l3c_pmu_acpi_match);
|
||||
static int hisi_l3c_pmu_init_data(struct platform_device *pdev,
|
||||
struct hisi_pmu *l3c_pmu)
|
||||
{
|
||||
hisi_uncore_pmu_init_topology(l3c_pmu, &pdev->dev);
|
||||
|
||||
/*
|
||||
* Use the SCCL_ID and CCL_ID to identify the L3C PMU, while
|
||||
* SCCL_ID is in MPIDR[aff2] and CCL_ID is in MPIDR[aff1].
|
||||
*/
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
|
||||
&l3c_pmu->sccl_id)) {
|
||||
if (l3c_pmu->topo.sccl_id < 0) {
|
||||
dev_err(&pdev->dev, "Can not read l3c sccl-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,ccl-id",
|
||||
&l3c_pmu->ccl_id)) {
|
||||
if (l3c_pmu->topo.ccl_id < 0) {
|
||||
dev_err(&pdev->dev, "Can not read l3c ccl-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -441,42 +441,19 @@ static const struct attribute_group hisi_l3c_pmu_v2_events_group = {
|
||||
.attrs = hisi_l3c_pmu_v2_events_attr,
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
|
||||
|
||||
static struct attribute *hisi_l3c_pmu_cpumask_attrs[] = {
|
||||
&dev_attr_cpumask.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_l3c_pmu_cpumask_attr_group = {
|
||||
.attrs = hisi_l3c_pmu_cpumask_attrs,
|
||||
};
|
||||
|
||||
static struct device_attribute hisi_l3c_pmu_identifier_attr =
|
||||
__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
|
||||
|
||||
static struct attribute *hisi_l3c_pmu_identifier_attrs[] = {
|
||||
&hisi_l3c_pmu_identifier_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_l3c_pmu_identifier_group = {
|
||||
.attrs = hisi_l3c_pmu_identifier_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *hisi_l3c_pmu_v1_attr_groups[] = {
|
||||
&hisi_l3c_pmu_v1_format_group,
|
||||
&hisi_l3c_pmu_v1_events_group,
|
||||
&hisi_l3c_pmu_cpumask_attr_group,
|
||||
&hisi_l3c_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group *hisi_l3c_pmu_v2_attr_groups[] = {
|
||||
&hisi_l3c_pmu_v2_format_group,
|
||||
&hisi_l3c_pmu_v2_events_group,
|
||||
&hisi_l3c_pmu_cpumask_attr_group,
|
||||
&hisi_l3c_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -544,8 +521,8 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u",
|
||||
l3c_pmu->sccl_id, l3c_pmu->ccl_id);
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%d_l3c%d",
|
||||
l3c_pmu->topo.sccl_id, l3c_pmu->topo.ccl_id);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -615,6 +592,7 @@ static void __exit hisi_l3c_pmu_module_exit(void)
|
||||
}
|
||||
module_exit(hisi_l3c_pmu_module_exit);
|
||||
|
||||
MODULE_IMPORT_NS("HISI_PMU");
|
||||
MODULE_DESCRIPTION("HiSilicon SoC L3C uncore PMU driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Anurup M <anurup.m@huawei.com>");
|
||||
|
@ -269,25 +269,22 @@ static void hisi_pa_pmu_clear_int_status(struct hisi_pmu *pa_pmu, int idx)
|
||||
static int hisi_pa_pmu_init_data(struct platform_device *pdev,
|
||||
struct hisi_pmu *pa_pmu)
|
||||
{
|
||||
hisi_uncore_pmu_init_topology(pa_pmu, &pdev->dev);
|
||||
|
||||
/*
|
||||
* As PA PMU is in a SICL, use the SICL_ID and the index ID
|
||||
* to identify the PA PMU.
|
||||
*/
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
|
||||
&pa_pmu->sicl_id)) {
|
||||
if (pa_pmu->topo.sicl_id < 0) {
|
||||
dev_err(&pdev->dev, "Cannot read sicl-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
|
||||
&pa_pmu->index_id)) {
|
||||
if (pa_pmu->topo.index_id < 0) {
|
||||
dev_err(&pdev->dev, "Cannot read idx-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pa_pmu->ccl_id = -1;
|
||||
pa_pmu->sccl_id = -1;
|
||||
|
||||
pa_pmu->dev_info = device_get_match_data(&pdev->dev);
|
||||
if (!pa_pmu->dev_info)
|
||||
return -ENODEV;
|
||||
@ -356,29 +353,6 @@ static const struct attribute_group hisi_h60pa_pmu_events_group = {
|
||||
.attrs = hisi_h60pa_pmu_events_attr,
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
|
||||
|
||||
static struct attribute *hisi_pa_pmu_cpumask_attrs[] = {
|
||||
&dev_attr_cpumask.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_pa_pmu_cpumask_attr_group = {
|
||||
.attrs = hisi_pa_pmu_cpumask_attrs,
|
||||
};
|
||||
|
||||
static struct device_attribute hisi_pa_pmu_identifier_attr =
|
||||
__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
|
||||
|
||||
static struct attribute *hisi_pa_pmu_identifier_attrs[] = {
|
||||
&hisi_pa_pmu_identifier_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_pa_pmu_identifier_group = {
|
||||
.attrs = hisi_pa_pmu_identifier_attrs,
|
||||
};
|
||||
|
||||
static struct hisi_pa_pmu_int_regs hisi_pa_pmu_regs = {
|
||||
.mask_offset = PA_INT_MASK,
|
||||
.clear_offset = PA_INT_CLEAR,
|
||||
@ -388,8 +362,8 @@ static struct hisi_pa_pmu_int_regs hisi_pa_pmu_regs = {
|
||||
static const struct attribute_group *hisi_pa_pmu_v2_attr_groups[] = {
|
||||
&hisi_pa_pmu_v2_format_group,
|
||||
&hisi_pa_pmu_v2_events_group,
|
||||
&hisi_pa_pmu_cpumask_attr_group,
|
||||
&hisi_pa_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -402,8 +376,8 @@ static const struct hisi_pmu_dev_info hisi_h32pa_v2 = {
|
||||
static const struct attribute_group *hisi_pa_pmu_v3_attr_groups[] = {
|
||||
&hisi_pa_pmu_v2_format_group,
|
||||
&hisi_pa_pmu_v3_events_group,
|
||||
&hisi_pa_pmu_cpumask_attr_group,
|
||||
&hisi_pa_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -422,8 +396,8 @@ static struct hisi_pa_pmu_int_regs hisi_h60pa_pmu_regs = {
|
||||
static const struct attribute_group *hisi_h60pa_pmu_attr_groups[] = {
|
||||
&hisi_pa_pmu_v2_format_group,
|
||||
&hisi_h60pa_pmu_events_group,
|
||||
&hisi_pa_pmu_cpumask_attr_group,
|
||||
&hisi_pa_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -488,9 +462,9 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sicl%d_%s%u",
|
||||
pa_pmu->sicl_id, pa_pmu->dev_info->name,
|
||||
pa_pmu->index_id);
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sicl%d_%s%d",
|
||||
pa_pmu->topo.sicl_id, pa_pmu->dev_info->name,
|
||||
pa_pmu->topo.index_id);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -569,6 +543,7 @@ static void __exit hisi_pa_pmu_module_exit(void)
|
||||
}
|
||||
module_exit(hisi_pa_pmu_module_exit);
|
||||
|
||||
MODULE_IMPORT_NS("HISI_PMU");
|
||||
MODULE_DESCRIPTION("HiSilicon Protocol Adapter uncore PMU driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/local64.h>
|
||||
@ -34,7 +35,7 @@ ssize_t hisi_event_sysfs_show(struct device *dev,
|
||||
|
||||
return sysfs_emit(page, "config=0x%lx\n", (unsigned long)eattr->var);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_event_sysfs_show);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_event_sysfs_show, "HISI_PMU");
|
||||
|
||||
/*
|
||||
* sysfs cpumask attributes. For uncore PMU, we only have a single CPU to show
|
||||
@ -46,7 +47,52 @@ ssize_t hisi_cpumask_sysfs_show(struct device *dev,
|
||||
|
||||
return sysfs_emit(buf, "%d\n", hisi_pmu->on_cpu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_cpumask_sysfs_show);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_cpumask_sysfs_show, "HISI_PMU");
|
||||
|
||||
static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
|
||||
|
||||
static ssize_t hisi_associated_cpus_sysfs_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hisi_pmu *hisi_pmu = to_hisi_pmu(dev_get_drvdata(dev));
|
||||
|
||||
return cpumap_print_to_pagebuf(true, buf, &hisi_pmu->associated_cpus);
|
||||
}
|
||||
static DEVICE_ATTR(associated_cpus, 0444, hisi_associated_cpus_sysfs_show, NULL);
|
||||
|
||||
static struct attribute *hisi_pmu_cpumask_attrs[] = {
|
||||
&dev_attr_cpumask.attr,
|
||||
&dev_attr_associated_cpus.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct attribute_group hisi_pmu_cpumask_attr_group = {
|
||||
.attrs = hisi_pmu_cpumask_attrs,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_pmu_cpumask_attr_group, "HISI_PMU");
|
||||
|
||||
ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *page)
|
||||
{
|
||||
struct hisi_pmu *hisi_pmu = to_hisi_pmu(dev_get_drvdata(dev));
|
||||
|
||||
return sysfs_emit(page, "0x%08x\n", hisi_pmu->identifier);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_identifier_attr_show, "HISI_PMU");
|
||||
|
||||
static struct device_attribute hisi_pmu_identifier_attr =
|
||||
__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
|
||||
|
||||
static struct attribute *hisi_pmu_identifier_attrs[] = {
|
||||
&hisi_pmu_identifier_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct attribute_group hisi_pmu_identifier_group = {
|
||||
.attrs = hisi_pmu_identifier_attrs,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_pmu_identifier_group, "HISI_PMU");
|
||||
|
||||
static bool hisi_validate_event_group(struct perf_event *event)
|
||||
{
|
||||
@ -96,17 +142,7 @@ int hisi_uncore_pmu_get_event_idx(struct perf_event *event)
|
||||
|
||||
return idx;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_get_event_idx);
|
||||
|
||||
ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *page)
|
||||
{
|
||||
struct hisi_pmu *hisi_pmu = to_hisi_pmu(dev_get_drvdata(dev));
|
||||
|
||||
return sysfs_emit(page, "0x%08x\n", hisi_pmu->identifier);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_identifier_attr_show);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_get_event_idx, "HISI_PMU");
|
||||
|
||||
static void hisi_uncore_pmu_clear_event_idx(struct hisi_pmu *hisi_pmu, int idx)
|
||||
{
|
||||
@ -165,7 +201,7 @@ int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_init_irq);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_init_irq, "HISI_PMU");
|
||||
|
||||
int hisi_uncore_pmu_event_init(struct perf_event *event)
|
||||
{
|
||||
@ -219,7 +255,7 @@ int hisi_uncore_pmu_event_init(struct perf_event *event)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_event_init);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_event_init, "HISI_PMU");
|
||||
|
||||
/*
|
||||
* Set the counter to count the event that we're interested in,
|
||||
@ -273,7 +309,7 @@ void hisi_uncore_pmu_set_event_period(struct perf_event *event)
|
||||
/* Write start value to the hardware event counter */
|
||||
hisi_pmu->ops->write_counter(hisi_pmu, hwc, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_set_event_period);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_set_event_period, "HISI_PMU");
|
||||
|
||||
void hisi_uncore_pmu_event_update(struct perf_event *event)
|
||||
{
|
||||
@ -294,7 +330,7 @@ void hisi_uncore_pmu_event_update(struct perf_event *event)
|
||||
HISI_MAX_PERIOD(hisi_pmu->counter_bits);
|
||||
local64_add(delta, &event->count);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_event_update);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_event_update, "HISI_PMU");
|
||||
|
||||
void hisi_uncore_pmu_start(struct perf_event *event, int flags)
|
||||
{
|
||||
@ -317,7 +353,7 @@ void hisi_uncore_pmu_start(struct perf_event *event, int flags)
|
||||
hisi_uncore_pmu_enable_event(event);
|
||||
perf_event_update_userpage(event);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_start);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_start, "HISI_PMU");
|
||||
|
||||
void hisi_uncore_pmu_stop(struct perf_event *event, int flags)
|
||||
{
|
||||
@ -334,7 +370,7 @@ void hisi_uncore_pmu_stop(struct perf_event *event, int flags)
|
||||
hisi_uncore_pmu_event_update(event);
|
||||
hwc->state |= PERF_HES_UPTODATE;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_stop);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_stop, "HISI_PMU");
|
||||
|
||||
int hisi_uncore_pmu_add(struct perf_event *event, int flags)
|
||||
{
|
||||
@ -357,7 +393,7 @@ int hisi_uncore_pmu_add(struct perf_event *event, int flags)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_add);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_add, "HISI_PMU");
|
||||
|
||||
void hisi_uncore_pmu_del(struct perf_event *event, int flags)
|
||||
{
|
||||
@ -369,14 +405,14 @@ void hisi_uncore_pmu_del(struct perf_event *event, int flags)
|
||||
perf_event_update_userpage(event);
|
||||
hisi_pmu->pmu_events.hw_events[hwc->idx] = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_del);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_del, "HISI_PMU");
|
||||
|
||||
void hisi_uncore_pmu_read(struct perf_event *event)
|
||||
{
|
||||
/* Read hardware counter and update the perf counter statistics */
|
||||
hisi_uncore_pmu_event_update(event);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_read);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_read, "HISI_PMU");
|
||||
|
||||
void hisi_uncore_pmu_enable(struct pmu *pmu)
|
||||
{
|
||||
@ -389,7 +425,7 @@ void hisi_uncore_pmu_enable(struct pmu *pmu)
|
||||
|
||||
hisi_pmu->ops->start_counters(hisi_pmu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_enable);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_enable, "HISI_PMU");
|
||||
|
||||
void hisi_uncore_pmu_disable(struct pmu *pmu)
|
||||
{
|
||||
@ -397,7 +433,7 @@ void hisi_uncore_pmu_disable(struct pmu *pmu)
|
||||
|
||||
hisi_pmu->ops->stop_counters(hisi_pmu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_disable);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_disable, "HISI_PMU");
|
||||
|
||||
|
||||
/*
|
||||
@ -444,22 +480,19 @@ static void hisi_read_sccl_and_ccl_id(int *scclp, int *cclp)
|
||||
*/
|
||||
static bool hisi_pmu_cpu_is_associated_pmu(struct hisi_pmu *hisi_pmu)
|
||||
{
|
||||
struct hisi_pmu_topology *topo = &hisi_pmu->topo;
|
||||
int sccl_id, ccl_id;
|
||||
|
||||
/* If SCCL_ID is -1, the PMU is in a SICL and has no CPU affinity */
|
||||
if (hisi_pmu->sccl_id == -1)
|
||||
return true;
|
||||
|
||||
if (hisi_pmu->ccl_id == -1) {
|
||||
if (topo->ccl_id == -1) {
|
||||
/* If CCL_ID is -1, the PMU only shares the same SCCL */
|
||||
hisi_read_sccl_and_ccl_id(&sccl_id, NULL);
|
||||
|
||||
return sccl_id == hisi_pmu->sccl_id;
|
||||
return sccl_id == topo->sccl_id;
|
||||
}
|
||||
|
||||
hisi_read_sccl_and_ccl_id(&sccl_id, &ccl_id);
|
||||
|
||||
return sccl_id == hisi_pmu->sccl_id && ccl_id == hisi_pmu->ccl_id;
|
||||
return sccl_id == topo->sccl_id && ccl_id == topo->ccl_id;
|
||||
}
|
||||
|
||||
int hisi_uncore_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
@ -467,13 +500,25 @@ int hisi_uncore_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
struct hisi_pmu *hisi_pmu = hlist_entry_safe(node, struct hisi_pmu,
|
||||
node);
|
||||
|
||||
if (!hisi_pmu_cpu_is_associated_pmu(hisi_pmu))
|
||||
/*
|
||||
* If the CPU is not associated to PMU, initialize the hisi_pmu->on_cpu
|
||||
* based on the locality if it hasn't been initialized yet. For PMUs
|
||||
* do have associated CPUs, it'll be updated later.
|
||||
*/
|
||||
if (!hisi_pmu_cpu_is_associated_pmu(hisi_pmu)) {
|
||||
if (hisi_pmu->on_cpu != -1)
|
||||
return 0;
|
||||
|
||||
hisi_pmu->on_cpu = cpumask_local_spread(0, dev_to_node(hisi_pmu->dev));
|
||||
WARN_ON(irq_set_affinity(hisi_pmu->irq, cpumask_of(cpu)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
cpumask_set_cpu(cpu, &hisi_pmu->associated_cpus);
|
||||
|
||||
/* If another CPU is already managing this PMU, simply return. */
|
||||
if (hisi_pmu->on_cpu != -1)
|
||||
/* If another associated CPU is already managing this PMU, simply return. */
|
||||
if (hisi_pmu->on_cpu != -1 &&
|
||||
cpumask_test_cpu(hisi_pmu->on_cpu, &hisi_pmu->associated_cpus))
|
||||
return 0;
|
||||
|
||||
/* Use this CPU in cpumask for event counting */
|
||||
@ -484,7 +529,7 @@ int hisi_uncore_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_online_cpu);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_online_cpu, "HISI_PMU");
|
||||
|
||||
int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
{
|
||||
@ -492,9 +537,6 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
node);
|
||||
unsigned int target;
|
||||
|
||||
if (!cpumask_test_and_clear_cpu(cpu, &hisi_pmu->associated_cpus))
|
||||
return 0;
|
||||
|
||||
/* Nothing to do if this CPU doesn't own the PMU */
|
||||
if (hisi_pmu->on_cpu != cpu)
|
||||
return 0;
|
||||
@ -502,9 +544,16 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
/* Give up ownership of the PMU */
|
||||
hisi_pmu->on_cpu = -1;
|
||||
|
||||
/* Choose a new CPU to migrate ownership of the PMU to */
|
||||
/*
|
||||
* Migrate ownership of the PMU to a new CPU chosen from PMU's online
|
||||
* associated CPUs if possible, if no associated CPU online then
|
||||
* migrate to one online CPU.
|
||||
*/
|
||||
target = cpumask_any_and_but(&hisi_pmu->associated_cpus,
|
||||
cpu_online_mask, cpu);
|
||||
if (target >= nr_cpu_ids)
|
||||
target = cpumask_any_but(cpu_online_mask, cpu);
|
||||
|
||||
if (target >= nr_cpu_ids)
|
||||
return 0;
|
||||
|
||||
@ -515,7 +564,36 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_uncore_pmu_offline_cpu);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_offline_cpu, "HISI_PMU");
|
||||
|
||||
/*
|
||||
* Retrieve the topology information from the firmware for the hisi_pmu device.
|
||||
* The topology ID will be -1 if we cannot initialize it, it may either due to
|
||||
* the PMU doesn't locate on this certain topology or the firmware needs to be
|
||||
* fixed.
|
||||
*/
|
||||
void hisi_uncore_pmu_init_topology(struct hisi_pmu *hisi_pmu, struct device *dev)
|
||||
{
|
||||
struct hisi_pmu_topology *topo = &hisi_pmu->topo;
|
||||
|
||||
topo->sccl_id = -1;
|
||||
topo->ccl_id = -1;
|
||||
topo->index_id = -1;
|
||||
topo->sub_id = -1;
|
||||
|
||||
if (device_property_read_u32(dev, "hisilicon,scl-id", &topo->sccl_id))
|
||||
dev_dbg(dev, "no scl-id present\n");
|
||||
|
||||
if (device_property_read_u32(dev, "hisilicon,ccl-id", &topo->ccl_id))
|
||||
dev_dbg(dev, "no ccl-id present\n");
|
||||
|
||||
if (device_property_read_u32(dev, "hisilicon,idx-id", &topo->index_id))
|
||||
dev_dbg(dev, "no idx-id present\n");
|
||||
|
||||
if (device_property_read_u32(dev, "hisilicon,sub-id", &topo->sub_id))
|
||||
dev_dbg(dev, "no sub-id present\n");
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_init_topology, "HISI_PMU");
|
||||
|
||||
void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module)
|
||||
{
|
||||
@ -535,7 +613,7 @@ void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module)
|
||||
pmu->attr_groups = hisi_pmu->pmu_events.attr_groups;
|
||||
pmu->capabilities = PERF_PMU_CAP_NO_EXCLUDE;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_pmu_init);
|
||||
EXPORT_SYMBOL_NS_GPL(hisi_pmu_init, "HISI_PMU");
|
||||
|
||||
MODULE_DESCRIPTION("HiSilicon SoC uncore Performance Monitor driver framework");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -81,27 +81,55 @@ struct hisi_pmu_hwevents {
|
||||
const struct attribute_group **attr_groups;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hisi_pmu_topology - Describe the topology hierarchy on which the PMU
|
||||
* is located.
|
||||
* @sccl_id: ID of the SCCL on which the PMU locate is located.
|
||||
* @sicl_id: ID of the SICL on which the PMU locate is located.
|
||||
* @scl_id: ID used by the core which is unaware of the SCCL/SICL.
|
||||
* @ccl_id: ID of the CCL (CPU cluster) on which the PMU is located.
|
||||
* @index_id: the ID of the PMU module if there're several PMUs at a
|
||||
* particularly location in the topology.
|
||||
* @sub_id: submodule ID of the PMU. For example we use this for DDRC PMU v2
|
||||
* since each DDRC has more than one DMC
|
||||
*
|
||||
* The ID will be -1 if the PMU isn't located on a certain topology.
|
||||
*/
|
||||
struct hisi_pmu_topology {
|
||||
/*
|
||||
* SCCL (Super CPU CLuster) and SICL (Super I/O Cluster) are parallel
|
||||
* so a PMU cannot locate on a SCCL and a SICL. If the SCCL/SICL
|
||||
* distinction is not relevant, use scl_id instead.
|
||||
*/
|
||||
union {
|
||||
int sccl_id;
|
||||
int sicl_id;
|
||||
int scl_id;
|
||||
};
|
||||
int ccl_id;
|
||||
int index_id;
|
||||
int sub_id;
|
||||
};
|
||||
|
||||
/* Generic pmu struct for different pmu types */
|
||||
struct hisi_pmu {
|
||||
struct pmu pmu;
|
||||
const struct hisi_uncore_ops *ops;
|
||||
const struct hisi_pmu_dev_info *dev_info;
|
||||
struct hisi_pmu_hwevents pmu_events;
|
||||
/* associated_cpus: All CPUs associated with the PMU */
|
||||
struct hisi_pmu_topology topo;
|
||||
/*
|
||||
* CPUs associated to the PMU and are preferred to use for counting.
|
||||
* Could be empty if PMU has no association (e.g. PMU on SICL), in
|
||||
* which case any online CPU will be used.
|
||||
*/
|
||||
cpumask_t associated_cpus;
|
||||
/* CPU used for counting */
|
||||
int on_cpu;
|
||||
int irq;
|
||||
struct device *dev;
|
||||
struct hlist_node node;
|
||||
int sccl_id;
|
||||
int sicl_id;
|
||||
int ccl_id;
|
||||
void __iomem *base;
|
||||
/* the ID of the PMU modules */
|
||||
u32 index_id;
|
||||
/* For DDRC PMU v2: each DDRC has more than one DMC */
|
||||
u32 sub_id;
|
||||
int num_counters;
|
||||
int counter_bits;
|
||||
/* check event code range */
|
||||
@ -109,6 +137,10 @@ struct hisi_pmu {
|
||||
u32 identifier;
|
||||
};
|
||||
|
||||
/* Generic implementation of cpumask/identifier group */
|
||||
extern const struct attribute_group hisi_pmu_cpumask_attr_group;
|
||||
extern const struct attribute_group hisi_pmu_identifier_group;
|
||||
|
||||
int hisi_uncore_pmu_get_event_idx(struct perf_event *event);
|
||||
void hisi_uncore_pmu_read(struct perf_event *event);
|
||||
int hisi_uncore_pmu_add(struct perf_event *event, int flags);
|
||||
@ -132,6 +164,7 @@ ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev,
|
||||
char *page);
|
||||
int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
|
||||
struct platform_device *pdev);
|
||||
void hisi_uncore_pmu_init_topology(struct hisi_pmu *hisi_pmu, struct device *dev);
|
||||
|
||||
void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module);
|
||||
#endif /* __HISI_UNCORE_PMU_H__ */
|
||||
|
@ -288,25 +288,22 @@ MODULE_DEVICE_TABLE(acpi, hisi_sllc_pmu_acpi_match);
|
||||
static int hisi_sllc_pmu_init_data(struct platform_device *pdev,
|
||||
struct hisi_pmu *sllc_pmu)
|
||||
{
|
||||
hisi_uncore_pmu_init_topology(sllc_pmu, &pdev->dev);
|
||||
|
||||
/*
|
||||
* Use the SCCL_ID and the index ID to identify the SLLC PMU,
|
||||
* while SCCL_ID is from MPIDR_EL1 by CPU.
|
||||
*/
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
|
||||
&sllc_pmu->sccl_id)) {
|
||||
if (sllc_pmu->topo.sccl_id < 0) {
|
||||
dev_err(&pdev->dev, "Cannot read sccl-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
|
||||
&sllc_pmu->index_id)) {
|
||||
if (sllc_pmu->topo.index_id < 0) {
|
||||
dev_err(&pdev->dev, "Cannot read idx-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* SLLC PMUs only share the same SCCL */
|
||||
sllc_pmu->ccl_id = -1;
|
||||
|
||||
sllc_pmu->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(sllc_pmu->base)) {
|
||||
dev_err(&pdev->dev, "ioremap failed for sllc_pmu resource.\n");
|
||||
@ -347,34 +344,11 @@ static const struct attribute_group hisi_sllc_pmu_v2_events_group = {
|
||||
.attrs = hisi_sllc_pmu_v2_events_attr,
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
|
||||
|
||||
static struct attribute *hisi_sllc_pmu_cpumask_attrs[] = {
|
||||
&dev_attr_cpumask.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_sllc_pmu_cpumask_attr_group = {
|
||||
.attrs = hisi_sllc_pmu_cpumask_attrs,
|
||||
};
|
||||
|
||||
static struct device_attribute hisi_sllc_pmu_identifier_attr =
|
||||
__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
|
||||
|
||||
static struct attribute *hisi_sllc_pmu_identifier_attrs[] = {
|
||||
&hisi_sllc_pmu_identifier_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_sllc_pmu_identifier_group = {
|
||||
.attrs = hisi_sllc_pmu_identifier_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *hisi_sllc_pmu_v2_attr_groups[] = {
|
||||
&hisi_sllc_pmu_v2_format_group,
|
||||
&hisi_sllc_pmu_v2_events_group,
|
||||
&hisi_sllc_pmu_cpumask_attr_group,
|
||||
&hisi_sllc_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -433,8 +407,8 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_sllc%u",
|
||||
sllc_pmu->sccl_id, sllc_pmu->index_id);
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%d_sllc%d",
|
||||
sllc_pmu->topo.sccl_id, sllc_pmu->topo.index_id);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -507,6 +481,7 @@ static void __exit hisi_sllc_pmu_module_exit(void)
|
||||
}
|
||||
module_exit(hisi_sllc_pmu_module_exit);
|
||||
|
||||
MODULE_IMPORT_NS("HISI_PMU");
|
||||
MODULE_DESCRIPTION("HiSilicon SLLC uncore PMU driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include "hisi_uncore_pmu.h"
|
||||
|
||||
@ -366,25 +365,24 @@ static void hisi_uc_pmu_clear_int_status(struct hisi_pmu *uc_pmu, int idx)
|
||||
static int hisi_uc_pmu_init_data(struct platform_device *pdev,
|
||||
struct hisi_pmu *uc_pmu)
|
||||
{
|
||||
hisi_uncore_pmu_init_topology(uc_pmu, &pdev->dev);
|
||||
|
||||
/*
|
||||
* Use SCCL (Super CPU Cluster) ID and CCL (CPU Cluster) ID to
|
||||
* identify the topology information of UC PMU devices in the chip.
|
||||
* They have some CCLs per SCCL and then 4 UC PMU per CCL.
|
||||
*/
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
|
||||
&uc_pmu->sccl_id)) {
|
||||
if (uc_pmu->topo.sccl_id < 0) {
|
||||
dev_err(&pdev->dev, "Can not read uc sccl-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,ccl-id",
|
||||
&uc_pmu->ccl_id)) {
|
||||
if (uc_pmu->topo.ccl_id < 0) {
|
||||
dev_err(&pdev->dev, "Can not read uc ccl-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (device_property_read_u32(&pdev->dev, "hisilicon,sub-id",
|
||||
&uc_pmu->sub_id)) {
|
||||
if (uc_pmu->topo.sub_id < 0) {
|
||||
dev_err(&pdev->dev, "Can not read sub-id!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -439,34 +437,11 @@ static const struct attribute_group hisi_uc_pmu_events_group = {
|
||||
.attrs = hisi_uc_pmu_events_attr,
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
|
||||
|
||||
static struct attribute *hisi_uc_pmu_cpumask_attrs[] = {
|
||||
&dev_attr_cpumask.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_uc_pmu_cpumask_attr_group = {
|
||||
.attrs = hisi_uc_pmu_cpumask_attrs,
|
||||
};
|
||||
|
||||
static struct device_attribute hisi_uc_pmu_identifier_attr =
|
||||
__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
|
||||
|
||||
static struct attribute *hisi_uc_pmu_identifier_attrs[] = {
|
||||
&hisi_uc_pmu_identifier_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hisi_uc_pmu_identifier_group = {
|
||||
.attrs = hisi_uc_pmu_identifier_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *hisi_uc_pmu_attr_groups[] = {
|
||||
&hisi_uc_pmu_format_group,
|
||||
&hisi_uc_pmu_events_group,
|
||||
&hisi_uc_pmu_cpumask_attr_group,
|
||||
&hisi_uc_pmu_identifier_group,
|
||||
&hisi_pmu_cpumask_attr_group,
|
||||
&hisi_pmu_identifier_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -538,8 +513,9 @@ static int hisi_uc_pmu_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%d_uc%d_%u",
|
||||
uc_pmu->sccl_id, uc_pmu->ccl_id, uc_pmu->sub_id);
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%d_uc%d_%d",
|
||||
uc_pmu->topo.sccl_id, uc_pmu->topo.ccl_id,
|
||||
uc_pmu->topo.sub_id);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -613,6 +589,7 @@ static void __exit hisi_uc_pmu_module_exit(void)
|
||||
}
|
||||
module_exit(hisi_uc_pmu_module_exit);
|
||||
|
||||
MODULE_IMPORT_NS("HISI_PMU");
|
||||
MODULE_DESCRIPTION("HiSilicon SoC UC uncore PMU driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Junhao He <hejunhao3@huawei.com>");
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Marvell CN10K DRAM Subsystem (DSS) Performance Monitor Driver
|
||||
/*
|
||||
* Marvell CN10K DRAM Subsystem (DSS) Performance Monitor Driver
|
||||
*
|
||||
* Copyright (C) 2021 Marvell.
|
||||
* Copyright (C) 2021-2024 Marvell.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
@ -14,24 +15,29 @@
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* Performance Counters Operating Mode Control Registers */
|
||||
#define DDRC_PERF_CNT_OP_MODE_CTRL 0x8020
|
||||
#define OP_MODE_CTRL_VAL_MANNUAL 0x1
|
||||
#define CN10K_DDRC_PERF_CNT_OP_MODE_CTRL 0x8020
|
||||
#define ODY_DDRC_PERF_CNT_OP_MODE_CTRL 0x20020
|
||||
#define OP_MODE_CTRL_VAL_MANUAL 0x1
|
||||
|
||||
/* Performance Counters Start Operation Control Registers */
|
||||
#define DDRC_PERF_CNT_START_OP_CTRL 0x8028
|
||||
#define CN10K_DDRC_PERF_CNT_START_OP_CTRL 0x8028
|
||||
#define ODY_DDRC_PERF_CNT_START_OP_CTRL 0x200A0
|
||||
#define START_OP_CTRL_VAL_START 0x1ULL
|
||||
#define START_OP_CTRL_VAL_ACTIVE 0x2
|
||||
|
||||
/* Performance Counters End Operation Control Registers */
|
||||
#define DDRC_PERF_CNT_END_OP_CTRL 0x8030
|
||||
#define CN10K_DDRC_PERF_CNT_END_OP_CTRL 0x8030
|
||||
#define ODY_DDRC_PERF_CNT_END_OP_CTRL 0x200E0
|
||||
#define END_OP_CTRL_VAL_END 0x1ULL
|
||||
|
||||
/* Performance Counters End Status Registers */
|
||||
#define DDRC_PERF_CNT_END_STATUS 0x8038
|
||||
#define CN10K_DDRC_PERF_CNT_END_STATUS 0x8038
|
||||
#define ODY_DDRC_PERF_CNT_END_STATUS 0x20120
|
||||
#define END_STATUS_VAL_END_TIMER_MODE_END 0x1
|
||||
|
||||
/* Performance Counters Configuration Registers */
|
||||
#define DDRC_PERF_CFG_BASE 0x8040
|
||||
#define CN10K_DDRC_PERF_CFG_BASE 0x8040
|
||||
#define ODY_DDRC_PERF_CFG_BASE 0x20160
|
||||
|
||||
/* 8 Generic event counter + 2 fixed event counters */
|
||||
#define DDRC_PERF_NUM_GEN_COUNTERS 8
|
||||
@ -42,18 +48,28 @@
|
||||
DDRC_PERF_NUM_FIX_COUNTERS)
|
||||
|
||||
/* Generic event counter registers */
|
||||
#define DDRC_PERF_CFG(n) (DDRC_PERF_CFG_BASE + 8 * (n))
|
||||
#define DDRC_PERF_CFG(base, n) ((base) + 8 * (n))
|
||||
#define EVENT_ENABLE BIT_ULL(63)
|
||||
|
||||
/* Two dedicated event counters for DDR reads and writes */
|
||||
#define EVENT_DDR_READS 101
|
||||
#define EVENT_DDR_WRITES 100
|
||||
|
||||
#define DDRC_PERF_REG(base, n) ((base) + 8 * (n))
|
||||
/*
|
||||
* programmable events IDs in programmable event counters.
|
||||
* DO NOT change these event-id numbers, they are used to
|
||||
* program event bitmap in h/w.
|
||||
*/
|
||||
#define EVENT_DFI_CMD_IS_RETRY 61
|
||||
#define EVENT_RD_UC_ECC_ERROR 60
|
||||
#define EVENT_RD_CRC_ERROR 59
|
||||
#define EVENT_CAPAR_ERROR 58
|
||||
#define EVENT_WR_CRC_ERROR 57
|
||||
#define EVENT_DFI_PARITY_POISON 56
|
||||
#define EVENT_RETRY_FIFO_FULL 46
|
||||
#define EVENT_DFI_CYCLES 45
|
||||
|
||||
#define EVENT_OP_IS_ZQLATCH 55
|
||||
#define EVENT_OP_IS_ZQSTART 54
|
||||
#define EVENT_OP_IS_TCR_MRR 53
|
||||
@ -102,28 +118,37 @@
|
||||
#define EVENT_HIF_RD_OR_WR 1
|
||||
|
||||
/* Event counter value registers */
|
||||
#define DDRC_PERF_CNT_VALUE_BASE 0x8080
|
||||
#define DDRC_PERF_CNT_VALUE(n) (DDRC_PERF_CNT_VALUE_BASE + 8 * (n))
|
||||
#define CN10K_DDRC_PERF_CNT_VALUE_BASE 0x8080
|
||||
#define ODY_DDRC_PERF_CNT_VALUE_BASE 0x201C0
|
||||
|
||||
/* Fixed event counter enable/disable register */
|
||||
#define DDRC_PERF_CNT_FREERUN_EN 0x80C0
|
||||
#define CN10K_DDRC_PERF_CNT_FREERUN_EN 0x80C0
|
||||
#define DDRC_PERF_FREERUN_WRITE_EN 0x1
|
||||
#define DDRC_PERF_FREERUN_READ_EN 0x2
|
||||
|
||||
/* Fixed event counter control register */
|
||||
#define DDRC_PERF_CNT_FREERUN_CTRL 0x80C8
|
||||
#define CN10K_DDRC_PERF_CNT_FREERUN_CTRL 0x80C8
|
||||
#define ODY_DDRC_PERF_CNT_FREERUN_CTRL 0x20240
|
||||
#define DDRC_FREERUN_WRITE_CNT_CLR 0x1
|
||||
#define DDRC_FREERUN_READ_CNT_CLR 0x2
|
||||
|
||||
/* Fixed event counter value register */
|
||||
#define DDRC_PERF_CNT_VALUE_WR_OP 0x80D0
|
||||
#define DDRC_PERF_CNT_VALUE_RD_OP 0x80D8
|
||||
/* Fixed event counter clear register, defined only for Odyssey */
|
||||
#define ODY_DDRC_PERF_CNT_FREERUN_CLR 0x20248
|
||||
|
||||
#define DDRC_PERF_CNT_VALUE_OVERFLOW BIT_ULL(48)
|
||||
#define DDRC_PERF_CNT_MAX_VALUE GENMASK_ULL(48, 0)
|
||||
|
||||
/* Fixed event counter value register */
|
||||
#define CN10K_DDRC_PERF_CNT_VALUE_WR_OP 0x80D0
|
||||
#define CN10K_DDRC_PERF_CNT_VALUE_RD_OP 0x80D8
|
||||
#define ODY_DDRC_PERF_CNT_VALUE_WR_OP 0x20250
|
||||
#define ODY_DDRC_PERF_CNT_VALUE_RD_OP 0x20258
|
||||
|
||||
struct cn10k_ddr_pmu {
|
||||
struct pmu pmu;
|
||||
void __iomem *base;
|
||||
const struct ddr_pmu_platform_data *p_data;
|
||||
const struct ddr_pmu_ops *ops;
|
||||
unsigned int cpu;
|
||||
struct device *dev;
|
||||
int active_events;
|
||||
@ -132,8 +157,36 @@ struct cn10k_ddr_pmu {
|
||||
struct hlist_node node;
|
||||
};
|
||||
|
||||
struct ddr_pmu_ops {
|
||||
void (*enable_read_freerun_counter)(struct cn10k_ddr_pmu *pmu,
|
||||
bool enable);
|
||||
void (*enable_write_freerun_counter)(struct cn10k_ddr_pmu *pmu,
|
||||
bool enable);
|
||||
void (*clear_read_freerun_counter)(struct cn10k_ddr_pmu *pmu);
|
||||
void (*clear_write_freerun_counter)(struct cn10k_ddr_pmu *pmu);
|
||||
void (*pmu_overflow_handler)(struct cn10k_ddr_pmu *pmu, int evt_idx);
|
||||
};
|
||||
|
||||
#define to_cn10k_ddr_pmu(p) container_of(p, struct cn10k_ddr_pmu, pmu)
|
||||
|
||||
struct ddr_pmu_platform_data {
|
||||
u64 counter_overflow_val;
|
||||
u64 counter_max_val;
|
||||
u64 cnt_base;
|
||||
u64 cfg_base;
|
||||
u64 cnt_op_mode_ctrl;
|
||||
u64 cnt_start_op_ctrl;
|
||||
u64 cnt_end_op_ctrl;
|
||||
u64 cnt_end_status;
|
||||
u64 cnt_freerun_en;
|
||||
u64 cnt_freerun_ctrl;
|
||||
u64 cnt_freerun_clr;
|
||||
u64 cnt_value_wr_op;
|
||||
u64 cnt_value_rd_op;
|
||||
bool is_cn10k;
|
||||
bool is_ody;
|
||||
};
|
||||
|
||||
static ssize_t cn10k_ddr_pmu_event_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *page)
|
||||
@ -209,6 +262,85 @@ static struct attribute *cn10k_ddr_perf_events_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute *odyssey_ddr_perf_events_attrs[] = {
|
||||
/* Programmable */
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_hif_rd_or_wr_access, EVENT_HIF_RD_OR_WR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_hif_wr_access, EVENT_HIF_WR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_hif_rd_access, EVENT_HIF_RD),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_hif_rmw_access, EVENT_HIF_RMW),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_hif_pri_rdaccess, EVENT_HIF_HI_PRI_RD),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_rd_bypass_access, EVENT_READ_BYPASS),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_act_bypass_access, EVENT_ACT_BYPASS),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_dfi_wr_data_access,
|
||||
EVENT_DFI_WR_DATA_CYCLES),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_dfi_rd_data_access,
|
||||
EVENT_DFI_RD_DATA_CYCLES),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_hpri_sched_rd_crit_access,
|
||||
EVENT_HPR_XACT_WHEN_CRITICAL),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_lpri_sched_rd_crit_access,
|
||||
EVENT_LPR_XACT_WHEN_CRITICAL),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_wr_trxn_crit_access,
|
||||
EVENT_WR_XACT_WHEN_CRITICAL),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_cam_active_access, EVENT_OP_IS_ACTIVATE),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_cam_rd_or_wr_access,
|
||||
EVENT_OP_IS_RD_OR_WR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_cam_rd_active_access,
|
||||
EVENT_OP_IS_RD_ACTIVATE),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_cam_read, EVENT_OP_IS_RD),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_cam_write, EVENT_OP_IS_WR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_cam_mwr, EVENT_OP_IS_MWR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_precharge, EVENT_OP_IS_PRECHARGE),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_precharge_for_rdwr,
|
||||
EVENT_PRECHARGE_FOR_RDWR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_precharge_for_other,
|
||||
EVENT_PRECHARGE_FOR_OTHER),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_rdwr_transitions, EVENT_RDWR_TRANSITIONS),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_write_combine, EVENT_WRITE_COMBINE),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_war_hazard, EVENT_WAR_HAZARD),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_raw_hazard, EVENT_RAW_HAZARD),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_waw_hazard, EVENT_WAW_HAZARD),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_enter_selfref, EVENT_OP_IS_ENTER_SELFREF),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_enter_powerdown,
|
||||
EVENT_OP_IS_ENTER_POWERDOWN),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_enter_mpsm, EVENT_OP_IS_ENTER_MPSM),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_refresh, EVENT_OP_IS_REFRESH),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_crit_ref, EVENT_OP_IS_CRIT_REF),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_spec_ref, EVENT_OP_IS_SPEC_REF),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_load_mode, EVENT_OP_IS_LOAD_MODE),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_zqcl, EVENT_OP_IS_ZQCL),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_cam_wr_access, EVENT_OP_IS_ZQCS),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_dfi_cycles, EVENT_DFI_CYCLES),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_retry_fifo_full,
|
||||
EVENT_RETRY_FIFO_FULL),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_bsm_alloc, EVENT_BSM_ALLOC),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_bsm_starvation, EVENT_BSM_STARVATION),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_win_limit_reached_rd,
|
||||
EVENT_VISIBLE_WIN_LIMIT_REACHED_RD),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_win_limit_reached_wr,
|
||||
EVENT_VISIBLE_WIN_LIMIT_REACHED_WR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_dqsosc_mpc, EVENT_OP_IS_DQSOSC_MPC),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_dqsosc_mrr, EVENT_OP_IS_DQSOSC_MRR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_tcr_mrr, EVENT_OP_IS_TCR_MRR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_zqstart, EVENT_OP_IS_ZQSTART),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_zqlatch, EVENT_OP_IS_ZQLATCH),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_dfi_parity_poison,
|
||||
EVENT_DFI_PARITY_POISON),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_wr_crc_error, EVENT_WR_CRC_ERROR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_capar_error, EVENT_CAPAR_ERROR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_rd_crc_error, EVENT_RD_CRC_ERROR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_rd_uc_ecc_error, EVENT_RD_UC_ECC_ERROR),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_dfi_cmd_is_retry, EVENT_DFI_CMD_IS_RETRY),
|
||||
/* Free run event counters */
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_ddr_reads, EVENT_DDR_READS),
|
||||
CN10K_DDR_PMU_EVENT_ATTR(ddr_ddr_writes, EVENT_DDR_WRITES),
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group odyssey_ddr_perf_events_attr_group = {
|
||||
.name = "events",
|
||||
.attrs = odyssey_ddr_perf_events_attrs,
|
||||
};
|
||||
|
||||
static struct attribute_group cn10k_ddr_perf_events_attr_group = {
|
||||
.name = "events",
|
||||
.attrs = cn10k_ddr_perf_events_attrs,
|
||||
@ -254,6 +386,13 @@ static const struct attribute_group *cn10k_attr_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group *odyssey_attr_groups[] = {
|
||||
&odyssey_ddr_perf_events_attr_group,
|
||||
&cn10k_ddr_perf_format_attr_group,
|
||||
&cn10k_ddr_perf_cpumask_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Default poll timeout is 100 sec, which is very sufficient for
|
||||
* 48 bit counter incremented max at 5.6 GT/s, which may take many
|
||||
* hours to overflow.
|
||||
@ -266,9 +405,18 @@ static ktime_t cn10k_ddr_pmu_timer_period(void)
|
||||
return ms_to_ktime((u64)cn10k_ddr_pmu_poll_period_sec * USEC_PER_SEC);
|
||||
}
|
||||
|
||||
static int ddr_perf_get_event_bitmap(int eventid, u64 *event_bitmap)
|
||||
static int ddr_perf_get_event_bitmap(int eventid, u64 *event_bitmap,
|
||||
struct cn10k_ddr_pmu *ddr_pmu)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (eventid) {
|
||||
case EVENT_DFI_PARITY_POISON ...EVENT_DFI_CMD_IS_RETRY:
|
||||
if (!ddr_pmu->p_data->is_ody) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
case EVENT_HIF_RD_OR_WR ... EVENT_WAW_HAZARD:
|
||||
case EVENT_OP_IS_REFRESH ... EVENT_OP_IS_ZQLATCH:
|
||||
*event_bitmap = (1ULL << (eventid - 1));
|
||||
@ -279,11 +427,12 @@ static int ddr_perf_get_event_bitmap(int eventid, u64 *event_bitmap)
|
||||
*event_bitmap = (0xFULL << (eventid - 1));
|
||||
break;
|
||||
default:
|
||||
pr_err("%s Invalid eventid %d\n", __func__, eventid);
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (err)
|
||||
pr_err("%s Invalid eventid %d\n", __func__, eventid);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cn10k_ddr_perf_alloc_counter(struct cn10k_ddr_pmu *pmu,
|
||||
@ -351,9 +500,33 @@ static int cn10k_ddr_perf_event_init(struct perf_event *event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cn10k_ddr_perf_counter_start(struct cn10k_ddr_pmu *ddr_pmu,
|
||||
int counter)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = ddr_pmu->p_data;
|
||||
u64 ctrl_reg = p_data->cnt_start_op_ctrl;
|
||||
|
||||
writeq_relaxed(START_OP_CTRL_VAL_START, ddr_pmu->base +
|
||||
DDRC_PERF_REG(ctrl_reg, counter));
|
||||
}
|
||||
|
||||
static void cn10k_ddr_perf_counter_stop(struct cn10k_ddr_pmu *ddr_pmu,
|
||||
int counter)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = ddr_pmu->p_data;
|
||||
u64 ctrl_reg = p_data->cnt_end_op_ctrl;
|
||||
|
||||
writeq_relaxed(END_OP_CTRL_VAL_END, ddr_pmu->base +
|
||||
DDRC_PERF_REG(ctrl_reg, counter));
|
||||
}
|
||||
|
||||
static void cn10k_ddr_perf_counter_enable(struct cn10k_ddr_pmu *pmu,
|
||||
int counter, bool enable)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
u64 ctrl_reg = pmu->p_data->cnt_op_mode_ctrl;
|
||||
const struct ddr_pmu_ops *ops = pmu->ops;
|
||||
bool is_ody = pmu->p_data->is_ody;
|
||||
u32 reg;
|
||||
u64 val;
|
||||
|
||||
@ -363,7 +536,7 @@ static void cn10k_ddr_perf_counter_enable(struct cn10k_ddr_pmu *pmu,
|
||||
}
|
||||
|
||||
if (counter < DDRC_PERF_NUM_GEN_COUNTERS) {
|
||||
reg = DDRC_PERF_CFG(counter);
|
||||
reg = DDRC_PERF_CFG(p_data->cfg_base, counter);
|
||||
val = readq_relaxed(pmu->base + reg);
|
||||
|
||||
if (enable)
|
||||
@ -372,40 +545,52 @@ static void cn10k_ddr_perf_counter_enable(struct cn10k_ddr_pmu *pmu,
|
||||
val &= ~EVENT_ENABLE;
|
||||
|
||||
writeq_relaxed(val, pmu->base + reg);
|
||||
} else {
|
||||
val = readq_relaxed(pmu->base + DDRC_PERF_CNT_FREERUN_EN);
|
||||
if (enable) {
|
||||
if (counter == DDRC_PERF_READ_COUNTER_IDX)
|
||||
val |= DDRC_PERF_FREERUN_READ_EN;
|
||||
else
|
||||
val |= DDRC_PERF_FREERUN_WRITE_EN;
|
||||
} else {
|
||||
if (counter == DDRC_PERF_READ_COUNTER_IDX)
|
||||
val &= ~DDRC_PERF_FREERUN_READ_EN;
|
||||
else
|
||||
val &= ~DDRC_PERF_FREERUN_WRITE_EN;
|
||||
|
||||
if (is_ody) {
|
||||
if (enable) {
|
||||
/*
|
||||
* Setup the PMU counter to work in
|
||||
* manual mode
|
||||
*/
|
||||
reg = DDRC_PERF_REG(ctrl_reg, counter);
|
||||
writeq_relaxed(OP_MODE_CTRL_VAL_MANUAL,
|
||||
pmu->base + reg);
|
||||
|
||||
cn10k_ddr_perf_counter_start(pmu, counter);
|
||||
} else {
|
||||
cn10k_ddr_perf_counter_stop(pmu, counter);
|
||||
}
|
||||
}
|
||||
writeq_relaxed(val, pmu->base + DDRC_PERF_CNT_FREERUN_EN);
|
||||
} else {
|
||||
if (counter == DDRC_PERF_READ_COUNTER_IDX)
|
||||
ops->enable_read_freerun_counter(pmu, enable);
|
||||
else
|
||||
ops->enable_write_freerun_counter(pmu, enable);
|
||||
}
|
||||
}
|
||||
|
||||
static u64 cn10k_ddr_perf_read_counter(struct cn10k_ddr_pmu *pmu, int counter)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
u64 val;
|
||||
|
||||
if (counter == DDRC_PERF_READ_COUNTER_IDX)
|
||||
return readq_relaxed(pmu->base + DDRC_PERF_CNT_VALUE_RD_OP);
|
||||
return readq_relaxed(pmu->base +
|
||||
p_data->cnt_value_rd_op);
|
||||
|
||||
if (counter == DDRC_PERF_WRITE_COUNTER_IDX)
|
||||
return readq_relaxed(pmu->base + DDRC_PERF_CNT_VALUE_WR_OP);
|
||||
return readq_relaxed(pmu->base +
|
||||
p_data->cnt_value_wr_op);
|
||||
|
||||
val = readq_relaxed(pmu->base + DDRC_PERF_CNT_VALUE(counter));
|
||||
val = readq_relaxed(pmu->base +
|
||||
DDRC_PERF_REG(p_data->cnt_base, counter));
|
||||
return val;
|
||||
}
|
||||
|
||||
static void cn10k_ddr_perf_event_update(struct perf_event *event)
|
||||
{
|
||||
struct cn10k_ddr_pmu *pmu = to_cn10k_ddr_pmu(event->pmu);
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
u64 prev_count, new_count, mask;
|
||||
|
||||
@ -414,7 +599,7 @@ static void cn10k_ddr_perf_event_update(struct perf_event *event)
|
||||
new_count = cn10k_ddr_perf_read_counter(pmu, hwc->idx);
|
||||
} while (local64_xchg(&hwc->prev_count, new_count) != prev_count);
|
||||
|
||||
mask = DDRC_PERF_CNT_MAX_VALUE;
|
||||
mask = p_data->counter_max_val;
|
||||
|
||||
local64_add((new_count - prev_count) & mask, &event->count);
|
||||
}
|
||||
@ -435,6 +620,8 @@ static void cn10k_ddr_perf_event_start(struct perf_event *event, int flags)
|
||||
static int cn10k_ddr_perf_event_add(struct perf_event *event, int flags)
|
||||
{
|
||||
struct cn10k_ddr_pmu *pmu = to_cn10k_ddr_pmu(event->pmu);
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
const struct ddr_pmu_ops *ops = pmu->ops;
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
u8 config = event->attr.config;
|
||||
int counter, ret;
|
||||
@ -454,8 +641,8 @@ static int cn10k_ddr_perf_event_add(struct perf_event *event, int flags)
|
||||
|
||||
if (counter < DDRC_PERF_NUM_GEN_COUNTERS) {
|
||||
/* Generic counters, configure event id */
|
||||
reg_offset = DDRC_PERF_CFG(counter);
|
||||
ret = ddr_perf_get_event_bitmap(config, &val);
|
||||
reg_offset = DDRC_PERF_CFG(p_data->cfg_base, counter);
|
||||
ret = ddr_perf_get_event_bitmap(config, &val, pmu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -463,11 +650,9 @@ static int cn10k_ddr_perf_event_add(struct perf_event *event, int flags)
|
||||
} else {
|
||||
/* fixed event counter, clear counter value */
|
||||
if (counter == DDRC_PERF_READ_COUNTER_IDX)
|
||||
val = DDRC_FREERUN_READ_CNT_CLR;
|
||||
ops->clear_read_freerun_counter(pmu);
|
||||
else
|
||||
val = DDRC_FREERUN_WRITE_CNT_CLR;
|
||||
|
||||
writeq_relaxed(val, pmu->base + DDRC_PERF_CNT_FREERUN_CTRL);
|
||||
ops->clear_write_freerun_counter(pmu);
|
||||
}
|
||||
|
||||
hwc->state |= PERF_HES_STOPPED;
|
||||
@ -512,17 +697,19 @@ static void cn10k_ddr_perf_event_del(struct perf_event *event, int flags)
|
||||
static void cn10k_ddr_perf_pmu_enable(struct pmu *pmu)
|
||||
{
|
||||
struct cn10k_ddr_pmu *ddr_pmu = to_cn10k_ddr_pmu(pmu);
|
||||
const struct ddr_pmu_platform_data *p_data = ddr_pmu->p_data;
|
||||
|
||||
writeq_relaxed(START_OP_CTRL_VAL_START, ddr_pmu->base +
|
||||
DDRC_PERF_CNT_START_OP_CTRL);
|
||||
p_data->cnt_start_op_ctrl);
|
||||
}
|
||||
|
||||
static void cn10k_ddr_perf_pmu_disable(struct pmu *pmu)
|
||||
{
|
||||
struct cn10k_ddr_pmu *ddr_pmu = to_cn10k_ddr_pmu(pmu);
|
||||
const struct ddr_pmu_platform_data *p_data = ddr_pmu->p_data;
|
||||
|
||||
writeq_relaxed(END_OP_CTRL_VAL_END, ddr_pmu->base +
|
||||
DDRC_PERF_CNT_END_OP_CTRL);
|
||||
p_data->cnt_end_op_ctrl);
|
||||
}
|
||||
|
||||
static void cn10k_ddr_perf_event_update_all(struct cn10k_ddr_pmu *pmu)
|
||||
@ -547,8 +734,123 @@ static void cn10k_ddr_perf_event_update_all(struct cn10k_ddr_pmu *pmu)
|
||||
}
|
||||
}
|
||||
|
||||
static void ddr_pmu_enable_read_freerun(struct cn10k_ddr_pmu *pmu, bool enable)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
u64 val;
|
||||
|
||||
val = readq_relaxed(pmu->base + p_data->cnt_freerun_en);
|
||||
if (enable)
|
||||
val |= DDRC_PERF_FREERUN_READ_EN;
|
||||
else
|
||||
val &= ~DDRC_PERF_FREERUN_READ_EN;
|
||||
|
||||
writeq_relaxed(val, pmu->base + p_data->cnt_freerun_en);
|
||||
}
|
||||
|
||||
static void ddr_pmu_enable_write_freerun(struct cn10k_ddr_pmu *pmu, bool enable)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
u64 val;
|
||||
|
||||
val = readq_relaxed(pmu->base + p_data->cnt_freerun_en);
|
||||
if (enable)
|
||||
val |= DDRC_PERF_FREERUN_WRITE_EN;
|
||||
else
|
||||
val &= ~DDRC_PERF_FREERUN_WRITE_EN;
|
||||
|
||||
writeq_relaxed(val, pmu->base + p_data->cnt_freerun_en);
|
||||
}
|
||||
|
||||
static void ddr_pmu_read_clear_freerun(struct cn10k_ddr_pmu *pmu)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
u64 val;
|
||||
|
||||
val = DDRC_FREERUN_READ_CNT_CLR;
|
||||
writeq_relaxed(val, pmu->base + p_data->cnt_freerun_ctrl);
|
||||
}
|
||||
|
||||
static void ddr_pmu_write_clear_freerun(struct cn10k_ddr_pmu *pmu)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
u64 val;
|
||||
|
||||
val = DDRC_FREERUN_WRITE_CNT_CLR;
|
||||
writeq_relaxed(val, pmu->base + p_data->cnt_freerun_ctrl);
|
||||
}
|
||||
|
||||
static void ddr_pmu_overflow_hander(struct cn10k_ddr_pmu *pmu, int evt_idx)
|
||||
{
|
||||
cn10k_ddr_perf_event_update_all(pmu);
|
||||
cn10k_ddr_perf_pmu_disable(&pmu->pmu);
|
||||
cn10k_ddr_perf_pmu_enable(&pmu->pmu);
|
||||
}
|
||||
|
||||
static void ddr_pmu_ody_enable_read_freerun(struct cn10k_ddr_pmu *pmu,
|
||||
bool enable)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
u64 val;
|
||||
|
||||
val = readq_relaxed(pmu->base + p_data->cnt_freerun_ctrl);
|
||||
if (enable)
|
||||
val |= DDRC_PERF_FREERUN_READ_EN;
|
||||
else
|
||||
val &= ~DDRC_PERF_FREERUN_READ_EN;
|
||||
|
||||
writeq_relaxed(val, pmu->base + p_data->cnt_freerun_ctrl);
|
||||
}
|
||||
|
||||
static void ddr_pmu_ody_enable_write_freerun(struct cn10k_ddr_pmu *pmu,
|
||||
bool enable)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
u64 val;
|
||||
|
||||
val = readq_relaxed(pmu->base + p_data->cnt_freerun_ctrl);
|
||||
if (enable)
|
||||
val |= DDRC_PERF_FREERUN_WRITE_EN;
|
||||
else
|
||||
val &= ~DDRC_PERF_FREERUN_WRITE_EN;
|
||||
|
||||
writeq_relaxed(val, pmu->base + p_data->cnt_freerun_ctrl);
|
||||
}
|
||||
|
||||
static void ddr_pmu_ody_read_clear_freerun(struct cn10k_ddr_pmu *pmu)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
u64 val;
|
||||
|
||||
val = DDRC_FREERUN_READ_CNT_CLR;
|
||||
writeq_relaxed(val, pmu->base + p_data->cnt_freerun_clr);
|
||||
}
|
||||
|
||||
static void ddr_pmu_ody_write_clear_freerun(struct cn10k_ddr_pmu *pmu)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
u64 val;
|
||||
|
||||
val = DDRC_FREERUN_WRITE_CNT_CLR;
|
||||
writeq_relaxed(val, pmu->base + p_data->cnt_freerun_clr);
|
||||
}
|
||||
|
||||
static void ddr_pmu_ody_overflow_hander(struct cn10k_ddr_pmu *pmu, int evt_idx)
|
||||
{
|
||||
/*
|
||||
* On reaching the maximum value of the counter, the counter freezes
|
||||
* there. The particular event is updated and the respective counter
|
||||
* is stopped and started again so that it starts counting from zero
|
||||
*/
|
||||
cn10k_ddr_perf_event_update(pmu->events[evt_idx]);
|
||||
cn10k_ddr_perf_counter_stop(pmu, evt_idx);
|
||||
cn10k_ddr_perf_counter_start(pmu, evt_idx);
|
||||
}
|
||||
|
||||
static irqreturn_t cn10k_ddr_pmu_overflow_handler(struct cn10k_ddr_pmu *pmu)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *p_data = pmu->p_data;
|
||||
const struct ddr_pmu_ops *ops = pmu->ops;
|
||||
struct perf_event *event;
|
||||
struct hw_perf_event *hwc;
|
||||
u64 prev_count, new_count;
|
||||
@ -586,11 +888,9 @@ static irqreturn_t cn10k_ddr_pmu_overflow_handler(struct cn10k_ddr_pmu *pmu)
|
||||
continue;
|
||||
|
||||
value = cn10k_ddr_perf_read_counter(pmu, i);
|
||||
if (value == DDRC_PERF_CNT_MAX_VALUE) {
|
||||
if (value == p_data->counter_max_val) {
|
||||
pr_info("Counter-(%d) reached max value\n", i);
|
||||
cn10k_ddr_perf_event_update_all(pmu);
|
||||
cn10k_ddr_perf_pmu_disable(&pmu->pmu);
|
||||
cn10k_ddr_perf_pmu_enable(&pmu->pmu);
|
||||
ops->pmu_overflow_handler(pmu, i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -629,11 +929,68 @@ static int cn10k_ddr_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ddr_pmu_ops ddr_pmu_ops = {
|
||||
.enable_read_freerun_counter = ddr_pmu_enable_read_freerun,
|
||||
.enable_write_freerun_counter = ddr_pmu_enable_write_freerun,
|
||||
.clear_read_freerun_counter = ddr_pmu_read_clear_freerun,
|
||||
.clear_write_freerun_counter = ddr_pmu_write_clear_freerun,
|
||||
.pmu_overflow_handler = ddr_pmu_overflow_hander,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_ACPI) || defined(CONFIG_OF)
|
||||
static const struct ddr_pmu_platform_data cn10k_ddr_pmu_pdata = {
|
||||
.counter_overflow_val = BIT_ULL(48),
|
||||
.counter_max_val = GENMASK_ULL(48, 0),
|
||||
.cnt_base = CN10K_DDRC_PERF_CNT_VALUE_BASE,
|
||||
.cfg_base = CN10K_DDRC_PERF_CFG_BASE,
|
||||
.cnt_op_mode_ctrl = CN10K_DDRC_PERF_CNT_OP_MODE_CTRL,
|
||||
.cnt_start_op_ctrl = CN10K_DDRC_PERF_CNT_START_OP_CTRL,
|
||||
.cnt_end_op_ctrl = CN10K_DDRC_PERF_CNT_END_OP_CTRL,
|
||||
.cnt_end_status = CN10K_DDRC_PERF_CNT_END_STATUS,
|
||||
.cnt_freerun_en = CN10K_DDRC_PERF_CNT_FREERUN_EN,
|
||||
.cnt_freerun_ctrl = CN10K_DDRC_PERF_CNT_FREERUN_CTRL,
|
||||
.cnt_freerun_clr = 0,
|
||||
.cnt_value_wr_op = CN10K_DDRC_PERF_CNT_VALUE_WR_OP,
|
||||
.cnt_value_rd_op = CN10K_DDRC_PERF_CNT_VALUE_RD_OP,
|
||||
.is_cn10k = TRUE,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct ddr_pmu_ops ddr_pmu_ody_ops = {
|
||||
.enable_read_freerun_counter = ddr_pmu_ody_enable_read_freerun,
|
||||
.enable_write_freerun_counter = ddr_pmu_ody_enable_write_freerun,
|
||||
.clear_read_freerun_counter = ddr_pmu_ody_read_clear_freerun,
|
||||
.clear_write_freerun_counter = ddr_pmu_ody_write_clear_freerun,
|
||||
.pmu_overflow_handler = ddr_pmu_ody_overflow_hander,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct ddr_pmu_platform_data odyssey_ddr_pmu_pdata = {
|
||||
.counter_overflow_val = 0,
|
||||
.counter_max_val = GENMASK_ULL(63, 0),
|
||||
.cnt_base = ODY_DDRC_PERF_CNT_VALUE_BASE,
|
||||
.cfg_base = ODY_DDRC_PERF_CFG_BASE,
|
||||
.cnt_op_mode_ctrl = ODY_DDRC_PERF_CNT_OP_MODE_CTRL,
|
||||
.cnt_start_op_ctrl = ODY_DDRC_PERF_CNT_START_OP_CTRL,
|
||||
.cnt_end_op_ctrl = ODY_DDRC_PERF_CNT_END_OP_CTRL,
|
||||
.cnt_end_status = ODY_DDRC_PERF_CNT_END_STATUS,
|
||||
.cnt_freerun_en = 0,
|
||||
.cnt_freerun_ctrl = ODY_DDRC_PERF_CNT_FREERUN_CTRL,
|
||||
.cnt_freerun_clr = ODY_DDRC_PERF_CNT_FREERUN_CLR,
|
||||
.cnt_value_wr_op = ODY_DDRC_PERF_CNT_VALUE_WR_OP,
|
||||
.cnt_value_rd_op = ODY_DDRC_PERF_CNT_VALUE_RD_OP,
|
||||
.is_ody = TRUE,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int cn10k_ddr_perf_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct ddr_pmu_platform_data *dev_data;
|
||||
struct cn10k_ddr_pmu *ddr_pmu;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
bool is_cn10k;
|
||||
bool is_ody;
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
@ -644,30 +1001,60 @@ static int cn10k_ddr_perf_probe(struct platform_device *pdev)
|
||||
ddr_pmu->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, ddr_pmu);
|
||||
|
||||
dev_data = device_get_match_data(&pdev->dev);
|
||||
if (!dev_data) {
|
||||
dev_err(&pdev->dev, "Error: No device match data found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
ddr_pmu->base = base;
|
||||
|
||||
/* Setup the PMU counter to work in manual mode */
|
||||
writeq_relaxed(OP_MODE_CTRL_VAL_MANNUAL, ddr_pmu->base +
|
||||
DDRC_PERF_CNT_OP_MODE_CTRL);
|
||||
ddr_pmu->p_data = dev_data;
|
||||
is_cn10k = ddr_pmu->p_data->is_cn10k;
|
||||
is_ody = ddr_pmu->p_data->is_ody;
|
||||
|
||||
ddr_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.attr_groups = cn10k_attr_groups,
|
||||
.event_init = cn10k_ddr_perf_event_init,
|
||||
.add = cn10k_ddr_perf_event_add,
|
||||
.del = cn10k_ddr_perf_event_del,
|
||||
.start = cn10k_ddr_perf_event_start,
|
||||
.stop = cn10k_ddr_perf_event_stop,
|
||||
.read = cn10k_ddr_perf_event_update,
|
||||
.pmu_enable = cn10k_ddr_perf_pmu_enable,
|
||||
.pmu_disable = cn10k_ddr_perf_pmu_disable,
|
||||
};
|
||||
if (is_cn10k) {
|
||||
ddr_pmu->ops = &ddr_pmu_ops;
|
||||
/* Setup the PMU counter to work in manual mode */
|
||||
writeq_relaxed(OP_MODE_CTRL_VAL_MANUAL, ddr_pmu->base +
|
||||
ddr_pmu->p_data->cnt_op_mode_ctrl);
|
||||
|
||||
ddr_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.attr_groups = cn10k_attr_groups,
|
||||
.event_init = cn10k_ddr_perf_event_init,
|
||||
.add = cn10k_ddr_perf_event_add,
|
||||
.del = cn10k_ddr_perf_event_del,
|
||||
.start = cn10k_ddr_perf_event_start,
|
||||
.stop = cn10k_ddr_perf_event_stop,
|
||||
.read = cn10k_ddr_perf_event_update,
|
||||
.pmu_enable = cn10k_ddr_perf_pmu_enable,
|
||||
.pmu_disable = cn10k_ddr_perf_pmu_disable,
|
||||
};
|
||||
}
|
||||
|
||||
if (is_ody) {
|
||||
ddr_pmu->ops = &ddr_pmu_ody_ops;
|
||||
|
||||
ddr_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.attr_groups = odyssey_attr_groups,
|
||||
.event_init = cn10k_ddr_perf_event_init,
|
||||
.add = cn10k_ddr_perf_event_add,
|
||||
.del = cn10k_ddr_perf_event_del,
|
||||
.start = cn10k_ddr_perf_event_start,
|
||||
.stop = cn10k_ddr_perf_event_stop,
|
||||
.read = cn10k_ddr_perf_event_update,
|
||||
};
|
||||
}
|
||||
|
||||
/* Choose this cpu to collect perf data */
|
||||
ddr_pmu->cpu = raw_smp_processor_id();
|
||||
@ -688,7 +1075,7 @@ static int cn10k_ddr_perf_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
pr_info("CN10K DDR PMU Driver for ddrc@%llx\n", res->start);
|
||||
pr_info("DDR PMU Driver for ddrc@%llx\n", res->start);
|
||||
return 0;
|
||||
error:
|
||||
cpuhp_state_remove_instance_nocalls(
|
||||
@ -710,7 +1097,7 @@ static void cn10k_ddr_perf_remove(struct platform_device *pdev)
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id cn10k_ddr_pmu_of_match[] = {
|
||||
{ .compatible = "marvell,cn10k-ddr-pmu", },
|
||||
{ .compatible = "marvell,cn10k-ddr-pmu", .data = &cn10k_ddr_pmu_pdata },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cn10k_ddr_pmu_of_match);
|
||||
@ -718,7 +1105,8 @@ MODULE_DEVICE_TABLE(of, cn10k_ddr_pmu_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id cn10k_ddr_pmu_acpi_match[] = {
|
||||
{"MRVL000A", 0},
|
||||
{"MRVL000A", (kernel_ulong_t)&cn10k_ddr_pmu_pdata },
|
||||
{"MRVL000C", (kernel_ulong_t)&odyssey_ddr_pmu_pdata},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cn10k_ddr_pmu_acpi_match);
|
||||
|
@ -37,6 +37,15 @@ struct tad_pmu {
|
||||
DECLARE_BITMAP(counters_map, TAD_MAX_COUNTERS);
|
||||
};
|
||||
|
||||
enum mrvl_tad_pmu_version {
|
||||
TAD_PMU_V1 = 1,
|
||||
TAD_PMU_V2,
|
||||
};
|
||||
|
||||
struct tad_pmu_data {
|
||||
int id;
|
||||
};
|
||||
|
||||
static int tad_pmu_cpuhp_state;
|
||||
|
||||
static void tad_pmu_event_counter_read(struct perf_event *event)
|
||||
@ -214,6 +223,24 @@ static const struct attribute_group tad_pmu_events_attr_group = {
|
||||
.attrs = tad_pmu_event_attrs,
|
||||
};
|
||||
|
||||
static struct attribute *ody_tad_pmu_event_attrs[] = {
|
||||
TAD_PMU_EVENT_ATTR(tad_req_msh_in_exlmn, 0x3),
|
||||
TAD_PMU_EVENT_ATTR(tad_alloc_dtg, 0x1a),
|
||||
TAD_PMU_EVENT_ATTR(tad_alloc_ltg, 0x1b),
|
||||
TAD_PMU_EVENT_ATTR(tad_alloc_any, 0x1c),
|
||||
TAD_PMU_EVENT_ATTR(tad_hit_dtg, 0x1d),
|
||||
TAD_PMU_EVENT_ATTR(tad_hit_ltg, 0x1e),
|
||||
TAD_PMU_EVENT_ATTR(tad_hit_any, 0x1f),
|
||||
TAD_PMU_EVENT_ATTR(tad_tag_rd, 0x20),
|
||||
TAD_PMU_EVENT_ATTR(tad_tot_cycle, 0xFF),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ody_tad_pmu_events_attr_group = {
|
||||
.name = "events",
|
||||
.attrs = ody_tad_pmu_event_attrs,
|
||||
};
|
||||
|
||||
PMU_FORMAT_ATTR(event, "config:0-7");
|
||||
|
||||
static struct attribute *tad_pmu_format_attrs[] = {
|
||||
@ -252,8 +279,16 @@ static const struct attribute_group *tad_pmu_attr_groups[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group *ody_tad_pmu_attr_groups[] = {
|
||||
&ody_tad_pmu_events_attr_group,
|
||||
&tad_pmu_format_attr_group,
|
||||
&tad_pmu_cpumask_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int tad_pmu_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct tad_pmu_data *dev_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct tad_region *regions;
|
||||
struct tad_pmu *tad_pmu;
|
||||
@ -261,6 +296,7 @@ static int tad_pmu_probe(struct platform_device *pdev)
|
||||
u32 tad_pmu_page_size;
|
||||
u32 tad_page_size;
|
||||
u32 tad_cnt;
|
||||
int version;
|
||||
int i, ret;
|
||||
char *name;
|
||||
|
||||
@ -270,6 +306,13 @@ static int tad_pmu_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, tad_pmu);
|
||||
|
||||
dev_data = device_get_match_data(&pdev->dev);
|
||||
if (!dev_data) {
|
||||
dev_err(&pdev->dev, "Error: No device match data found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
version = dev_data->id;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Mem resource not found\n");
|
||||
@ -319,7 +362,6 @@ static int tad_pmu_probe(struct platform_device *pdev)
|
||||
tad_pmu->pmu = (struct pmu) {
|
||||
|
||||
.module = THIS_MODULE,
|
||||
.attr_groups = tad_pmu_attr_groups,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE |
|
||||
PERF_PMU_CAP_NO_INTERRUPT,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
@ -332,6 +374,11 @@ static int tad_pmu_probe(struct platform_device *pdev)
|
||||
.read = tad_pmu_event_counter_read,
|
||||
};
|
||||
|
||||
if (version == TAD_PMU_V1)
|
||||
tad_pmu->pmu.attr_groups = tad_pmu_attr_groups;
|
||||
else
|
||||
tad_pmu->pmu.attr_groups = ody_tad_pmu_attr_groups;
|
||||
|
||||
tad_pmu->cpu = raw_smp_processor_id();
|
||||
|
||||
/* Register pmu instance for cpu hotplug */
|
||||
@ -360,16 +407,29 @@ static void tad_pmu_remove(struct platform_device *pdev)
|
||||
perf_pmu_unregister(&pmu->pmu);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF) || defined(CONFIG_ACPI)
|
||||
static const struct tad_pmu_data tad_pmu_data = {
|
||||
.id = TAD_PMU_V1,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct tad_pmu_data tad_pmu_v2_data = {
|
||||
.id = TAD_PMU_V2,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id tad_pmu_of_match[] = {
|
||||
{ .compatible = "marvell,cn10k-tad-pmu", },
|
||||
{ .compatible = "marvell,cn10k-tad-pmu", .data = &tad_pmu_data },
|
||||
{},
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id tad_pmu_acpi_match[] = {
|
||||
{"MRVL000B", 0},
|
||||
{"MRVL000B", (kernel_ulong_t)&tad_pmu_data},
|
||||
{"MRVL000D", (kernel_ulong_t)&tad_pmu_v2_data},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, tad_pmu_acpi_match);
|
||||
|
Loading…
x
Reference in New Issue
Block a user