1*4faea7e0STomasz Jeznach /* 2*4faea7e0STomasz Jeznach * RISC-V IOMMU - Hardware Performance Monitor (HPM) helpers 3*4faea7e0STomasz Jeznach * 4*4faea7e0STomasz Jeznach * Copyright (C) 2022-2023 Rivos Inc. 5*4faea7e0STomasz Jeznach * 6*4faea7e0STomasz Jeznach * This program is free software; you can redistribute it and/or modify it 7*4faea7e0STomasz Jeznach * under the terms and conditions of the GNU General Public License, 8*4faea7e0STomasz Jeznach * version 2 or later, as published by the Free Software Foundation. 9*4faea7e0STomasz Jeznach * 10*4faea7e0STomasz Jeznach * This program is distributed in the hope that it will be useful, 11*4faea7e0STomasz Jeznach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12*4faea7e0STomasz Jeznach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*4faea7e0STomasz Jeznach * GNU General Public License for more details. 14*4faea7e0STomasz Jeznach * 15*4faea7e0STomasz Jeznach * You should have received a copy of the GNU General Public License along 16*4faea7e0STomasz Jeznach * with this program; if not, see <http://www.gnu.org/licenses/>. 17*4faea7e0STomasz Jeznach */ 18*4faea7e0STomasz Jeznach 19*4faea7e0STomasz Jeznach #include "qemu/osdep.h" 20*4faea7e0STomasz Jeznach #include "qemu/timer.h" 21*4faea7e0STomasz Jeznach #include "cpu_bits.h" 22*4faea7e0STomasz Jeznach #include "riscv-iommu-hpm.h" 23*4faea7e0STomasz Jeznach #include "riscv-iommu.h" 24*4faea7e0STomasz Jeznach #include "riscv-iommu-bits.h" 25*4faea7e0STomasz Jeznach #include "trace.h" 26*4faea7e0STomasz Jeznach 27*4faea7e0STomasz Jeznach /* For now we assume IOMMU HPM frequency to be 1GHz so 1-cycle is of 1-ns. */ 28*4faea7e0STomasz Jeznach static inline uint64_t get_cycles(void) 29*4faea7e0STomasz Jeznach { 30*4faea7e0STomasz Jeznach return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 31*4faea7e0STomasz Jeznach } 32*4faea7e0STomasz Jeznach 33*4faea7e0STomasz Jeznach uint64_t riscv_iommu_hpmcycle_read(RISCVIOMMUState *s) 34*4faea7e0STomasz Jeznach { 35*4faea7e0STomasz Jeznach const uint64_t cycle = riscv_iommu_reg_get64( 36*4faea7e0STomasz Jeznach s, RISCV_IOMMU_REG_IOHPMCYCLES); 37*4faea7e0STomasz Jeznach const uint32_t inhibit = riscv_iommu_reg_get32( 38*4faea7e0STomasz Jeznach s, RISCV_IOMMU_REG_IOCOUNTINH); 39*4faea7e0STomasz Jeznach const uint64_t ctr_prev = s->hpmcycle_prev; 40*4faea7e0STomasz Jeznach const uint64_t ctr_val = s->hpmcycle_val; 41*4faea7e0STomasz Jeznach 42*4faea7e0STomasz Jeznach if (get_field(inhibit, RISCV_IOMMU_IOCOUNTINH_CY)) { 43*4faea7e0STomasz Jeznach /* 44*4faea7e0STomasz Jeznach * Counter should not increment if inhibit bit is set. We can't really 45*4faea7e0STomasz Jeznach * stop the QEMU_CLOCK_VIRTUAL, so we just return the last updated 46*4faea7e0STomasz Jeznach * counter value to indicate that counter was not incremented. 47*4faea7e0STomasz Jeznach */ 48*4faea7e0STomasz Jeznach return (ctr_val & RISCV_IOMMU_IOHPMCYCLES_COUNTER) | 49*4faea7e0STomasz Jeznach (cycle & RISCV_IOMMU_IOHPMCYCLES_OVF); 50*4faea7e0STomasz Jeznach } 51*4faea7e0STomasz Jeznach 52*4faea7e0STomasz Jeznach return (ctr_val + get_cycles() - ctr_prev) | 53*4faea7e0STomasz Jeznach (cycle & RISCV_IOMMU_IOHPMCYCLES_OVF); 54*4faea7e0STomasz Jeznach } 55