Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/sbi/riscv_encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@
#define CSR_MCOUNTINHIBIT 0x320
#define CSR_MCYCLECFG 0x321
#define CSR_MINSTRETCFG 0x322
/* XuanTie vendor: per-counter event regs for fixed mcycle/minstret. */
#define CSR_MHPMEVENT0 0x7E0
#define CSR_MHPMEVENT2 0x7E1
#define CSR_MHPMEVENT3 0x323
Expand Down Expand Up @@ -691,6 +692,9 @@
/* For RV32 */
#define CSR_MCYCLECFGH 0x721
#define CSR_MINSTRETCFGH 0x722
/* XuanTie vendor: high half of mhpmevent0/2 (for OF/INH bits on RV32). */
#define CSR_MHPMEVENT0H 0x7E2
#define CSR_MHPMEVENT2H 0x7E3
#define CSR_MHPMEVENT3H 0x723
#define CSR_MHPMEVENT4H 0x724
#define CSR_MHPMEVENT5H 0x725
Expand Down
4 changes: 0 additions & 4 deletions lib/sbi/riscv_asm.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,6 @@ unsigned long csr_read_num(int csr_num)
switchcase_csr_read(CSR_MCOUNTINHIBIT, ret)
switchcase_csr_read(CSR_MCYCLECFG, ret)
switchcase_csr_read(CSR_MINSTRETCFG, ret)
switchcase_csr_read(CSR_MHPMEVENT0, ret)
switchcase_csr_read(CSR_MHPMEVENT2, ret)
switchcase_csr_read(CSR_MHPMEVENT3, ret)
switchcase_csr_read_4(CSR_MHPMEVENT4, ret)
switchcase_csr_read_8(CSR_MHPMEVENT8, ret)
Expand Down Expand Up @@ -226,8 +224,6 @@ void csr_write_num(int csr_num, unsigned long val)
switchcase_csr_write(CSR_MCOUNTINHIBIT, val)
switchcase_csr_write(CSR_MCYCLECFG, val)
switchcase_csr_write(CSR_MINSTRETCFG, val)
switchcase_csr_write(CSR_MHPMEVENT0, val)
switchcase_csr_write(CSR_MHPMEVENT2, val)
switchcase_csr_write(CSR_MHPMEVENT3, val)
switchcase_csr_write_4(CSR_MHPMEVENT4, val)
switchcase_csr_write_8(CSR_MHPMEVENT8, val)
Expand Down
27 changes: 6 additions & 21 deletions lib/sbi/sbi_pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,19 +329,14 @@ static int pmu_ctr_enable_irq_hw(int ctr_idx)
unsigned long mip_val;
unsigned long of_mask;

if (ctr_idx >= SBI_PMU_HW_CTR_MAX)
if (ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
return SBI_EFAIL;

#if __riscv_xlen == 32
mhpmevent_csr = CSR_MHPMEVENT3H + ctr_idx - 3;
of_mask = (uint32_t)~MHPMEVENTH_OF;
#else
if (ctr_idx == 0)
mhpmevent_csr = CSR_MHPMEVENT0;
else if (ctr_idx == 2)
mhpmevent_csr = CSR_MHPMEVENT2;
else
mhpmevent_csr = CSR_MHPMEVENT3 + ctr_idx - 3;
mhpmevent_csr = CSR_MHPMEVENT3 + ctr_idx - 3;
of_mask = ~MHPMEVENT_OF;
#endif

Expand Down Expand Up @@ -561,20 +556,15 @@ static int pmu_ctr_stop_fw(struct sbi_pmu_hart_state *phs,

static int pmu_reset_hw_mhpmevent(int ctr_idx)
{
if (ctr_idx >= SBI_PMU_HW_CTR_MAX)
if (ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
return SBI_EFAIL;
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, 0);
#else
if (ctr_idx == 0)
csr_write_num(CSR_MHPMEVENT0, 0);
else if (ctr_idx == 2)
csr_write_num(CSR_MHPMEVENT2, 0);
else
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
#endif

return 0;
Expand Down Expand Up @@ -647,7 +637,7 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
/* Get the final mhpmevent value to be written from platform */
mhpmevent_val = sbi_platform_pmu_xlate_to_mhpmevent(plat, eindex, data);

if (!mhpmevent_val || ctr_idx >= SBI_PMU_HW_CTR_MAX)
if (!mhpmevent_val || ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
return SBI_EFAIL;

/**
Expand All @@ -673,12 +663,7 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3,
mhpmevent_val >> BITS_PER_LONG);
#else
if (ctr_idx == 0)
csr_write_num(CSR_MHPMEVENT0, mhpmevent_val);
else if (ctr_idx == 2)
csr_write_num(CSR_MHPMEVENT2, mhpmevent_val);
else
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val);
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val);
#endif

return 0;
Expand Down
23 changes: 23 additions & 0 deletions platform/generic/include/xuantie/xuantie_pmu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*/

#ifndef __RISCV_XUANTIE_PMU_H__
#define __RISCV_XUANTIE_PMU_H__

/*
* XuanTie cores expose Sscofpmf-style OF semantics on the fixed cycle and
* instret counters via vendor per-counter event registers (mhpmevent0/2,
* and the matching high halves on RV32). The CSR addresses live in
* <sbi/riscv_encoding.h> next to the standard mhpmevent CSRs.
*
* mxstatus[8] (OFINT) is the per-hart master gate that lets the vendor
* OF bit raise lcofip; xuantie_pmu_enable_ofint() sets it.
*/

#define MXSTATUS_OFINT BIT(8)

void xuantie_pmu_register_device(void);
void xuantie_pmu_enable_ofint(void);

#endif /* __RISCV_XUANTIE_PMU_H__ */
1 change: 1 addition & 0 deletions platform/generic/include/xuantie/xuantie_quirk.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define QUIRK_XUANTIE_PMC BIT(0)
#define QUIRK_XUANTIE_LINK BIT(1)
#define QUIRK_XUANTIE_PMP_EXT BIT(2)
#define QUIRK_XUANTIE_PMU BIT(3)

struct xuantie_generic_quirks {
u32 quirk;
Expand Down
2 changes: 1 addition & 1 deletion platform/generic/xuantie/objects.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
#

carray-platform_override_modules-$(CONFIG_PLATFORM_XUANTIE) += xuantie_dummy
platform-objs-$(CONFIG_PLATFORM_XUANTIE) += xuantie/xuantie_dummy.o xuantie/xuantie_pmc.o xuantie/xuantie_link.o xuantie/xuantie_pmp_ext.o
platform-objs-$(CONFIG_PLATFORM_XUANTIE) += xuantie/xuantie_dummy.o xuantie/xuantie_pmc.o xuantie/xuantie_link.o xuantie/xuantie_pmp_ext.o xuantie/xuantie_pmu.o
15 changes: 14 additions & 1 deletion platform/generic/xuantie/xuantie_dummy.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <xuantie/xuantie_pmc.h>
#include <xuantie/xuantie_link.h>
#include <xuantie/xuantie_pmp_ext.h>
#include <xuantie/xuantie_pmu.h>

static u32 gquirk = 0;

Expand All @@ -24,6 +25,10 @@ int xuantie_early_init(bool cold_boot)
xuantie_pmp_ext_cfg();
}

/* mxstatus[8] OFINT is per-hart: enable on every boot path. */
if (gquirk & QUIRK_XUANTIE_PMU)
xuantie_pmu_enable_ofint();

return generic_early_init(cold_boot);
}

Expand All @@ -34,6 +39,8 @@ int xuantie_final_init(bool cold_boot)
xuantie_pmc_device_init();
if (gquirk & QUIRK_XUANTIE_LINK)
xuantie_link_pmu_device_init();
if (gquirk & QUIRK_XUANTIE_PMU)
xuantie_pmu_register_device();
}

return generic_final_init(cold_boot);
Expand All @@ -52,7 +59,8 @@ static int xuantie_dummy_platform_init(const void *fdt, int nodeoff,
}

static const struct xuantie_generic_quirks xuantie_quirks = {
.quirk = QUIRK_XUANTIE_PMC | QUIRK_XUANTIE_LINK | QUIRK_XUANTIE_PMP_EXT,
.quirk = QUIRK_XUANTIE_PMC | QUIRK_XUANTIE_LINK | QUIRK_XUANTIE_PMP_EXT |
QUIRK_XUANTIE_PMU,
};

static const struct xuantie_generic_quirks xuantie_pmc_quirks = {
Expand All @@ -67,10 +75,15 @@ static const struct xuantie_generic_quirks xuantie_pmp_ext_quirks = {
.quirk = QUIRK_XUANTIE_PMP_EXT,
};

static const struct xuantie_generic_quirks xuantie_pmu_quirks = {
.quirk = QUIRK_XUANTIE_PMU,
};

static const struct fdt_match xuantie_dummy_match[] = {
{ .compatible = "xuantie,dummy", .data = &xuantie_quirks },
{ .compatible = "xuantie,pmc", .data = &xuantie_pmc_quirks },
{ .compatible = "xuantie,link", .data = &xuantie_link_quirks },
{ .compatible = "xuantie,pmu", .data = &xuantie_pmu_quirks },
{ .compatible = "riscv-virtio", .data = &xuantie_pmp_ext_quirks }, // qemu debug
{ },
};
Expand Down
91 changes: 91 additions & 0 deletions platform/generic/xuantie/xuantie_pmu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_pmu.h>
#include <thead/c9xx_encoding.h>
#include <xuantie/xuantie_pmu.h>

/*
* Sscofpmf does not provide OF interrupts for the fixed cycle/instret
* counters. XuanTie cores back those counters with vendor mhpmevent0/2
* CSRs whose top bits follow the same OF/MINH/...INH layout as the
* standard mhpmevent3+. The generic sbi_pmu_device hooks let us layer
* the vendor OF handling on top of the regular Sscofpmf path: the core
* already calls hw_counter_enable_irq/disable_irq with ctr_idx 0 and 2
* via the fixed-counter fallback in pmu_fixed_ctr_update_inhibit_bits().
*
* Only ctr_idx == 0 (cycle) and ctr_idx == 2 (instret) need vendor
* handling. Other counters are programmable mhpmevent3+ and follow the
* standard Sscofpmf code path unchanged.
*/

static void xuantie_pmu_ctr_enable_irq(uint32_t ctr_idx)
{
if (ctr_idx != 0 && ctr_idx != 2)
return;

/*
* Mirror pmu_ctr_enable_irq_hw(): only clear OF when no lcofip is
* still pending, so we don't race with software that hasn't yet
* handled the previous overflow.
*/
if (csr_read(CSR_MIP) & MIP_LCOFIP)
return;

#if __riscv_xlen == 32
/* OF lives in the H half on RV32; clear via mhpmevent0H/mhpmevent2H. */
if (ctr_idx == 0)
csr_clear(CSR_MHPMEVENT0H, MHPMEVENTH_OF);
else
csr_clear(CSR_MHPMEVENT2H, MHPMEVENTH_OF);
#else
if (ctr_idx == 0)
csr_clear(CSR_MHPMEVENT0, MHPMEVENT_OF);
else
csr_clear(CSR_MHPMEVENT2, MHPMEVENT_OF);
#endif
}

static void xuantie_pmu_ctr_disable_irq(uint32_t ctr_idx)
{
if (ctr_idx != 0 && ctr_idx != 2)
return;

/*
* Setting OF latches the counter so a subsequent overflow cannot
* raise lcofip until enable_irq clears it again. This matches the
* "OF set = disabled" convention used by pmu_update_hw_mhpmevent().
*/
#if __riscv_xlen == 32
if (ctr_idx == 0)
csr_set(CSR_MHPMEVENT0H, MHPMEVENTH_OF);
else
csr_set(CSR_MHPMEVENT2H, MHPMEVENTH_OF);
#else
if (ctr_idx == 0)
csr_set(CSR_MHPMEVENT0, MHPMEVENT_OF);
else
csr_set(CSR_MHPMEVENT2, MHPMEVENT_OF);
#endif
}

static const struct sbi_pmu_device xuantie_pmu_device = {
.name = "xuantie,pmu",
.hw_counter_enable_irq = xuantie_pmu_ctr_enable_irq,
.hw_counter_disable_irq = xuantie_pmu_ctr_disable_irq,
};

void xuantie_pmu_register_device(void)
{
sbi_pmu_set_device(&xuantie_pmu_device);
}

void xuantie_pmu_enable_ofint(void)
{
csr_set(THEAD_C9XX_CSR_MXSTATUS, MXSTATUS_OFINT);
}
Loading