/*
 * QEMU KVM support -- x86 virtual energy-related MSR.
 *
 * Copyright 2024 Red Hat, Inc. 2024
 *
 *  Author:
 *      Anthony Harivel <aharivel@redhat.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 *
 */

#ifndef VMSR_ENERGY_H
#define VMSR_ENERGY_H

#include <stdint.h>
#include "qemu/osdep.h"
#include "io/channel-socket.h"
#include "hw/i386/topology.h"

/*
 * Define the interval time in micro seconds between 2 samples of
 * energy related MSRs
 */
#define MSR_ENERGY_THREAD_SLEEP_US 1000000.0

/*
 * Thread statistic
 * @ thread_id: TID (thread ID)
 * @ is_vcpu: true if TID is vCPU thread
 * @ cpu_id: CPU number last executed on
 * @ pkg_id: package number of the CPU
 * @ vcpu_id: vCPU ID
 * @ vpkg: virtual package number
 * @ acpi_id: APIC id of the vCPU
 * @ utime: amount of clock ticks the thread
 *          has been scheduled in User mode
 * @ stime: amount of clock ticks the thread
 *          has been scheduled in System mode
 * @ delta_ticks: delta of utime+stime between
 *          the two samples (before/after sleep)
 */
struct vmsr_thread_stat {
    unsigned int thread_id;
    bool is_vcpu;
    unsigned int cpu_id;
    unsigned int pkg_id;
    unsigned int vpkg_id;
    unsigned int vcpu_id;
    unsigned long acpi_id;
    unsigned long long *utime;
    unsigned long long *stime;
    unsigned long long delta_ticks;
};

/*
 * Package statistic
 * @ e_start: package energy counter before the sleep
 * @ e_end: package energy counter after the sleep
 * @ e_delta: delta of package energy counter
 * @ e_ratio: store the energy ratio of non-vCPU thread
 * @ nb_vcpu: number of vCPU running on this package
 */
struct vmsr_package_energy_stat {
    uint64_t e_start;
    uint64_t e_end;
    uint64_t e_delta;
    uint64_t e_ratio;
    unsigned int nb_vcpu;
};

typedef struct vmsr_thread_stat vmsr_thread_stat;
typedef struct vmsr_package_energy_stat vmsr_package_energy_stat;

char *vmsr_compute_default_paths(void);
void vmsr_read_thread_stat(pid_t pid,
                      unsigned int thread_id,
                      unsigned long long *utime,
                      unsigned long long *stime,
                      unsigned int *cpu_id);

QIOChannelSocket *vmsr_open_socket(const char *path);
uint64_t vmsr_read_msr(uint32_t reg, uint32_t cpu_id,
                       uint32_t tid, QIOChannelSocket *sioc);
void vmsr_delta_ticks(vmsr_thread_stat *thd_stat, int i);
unsigned int vmsr_get_maxcpus(void);
unsigned int vmsr_get_max_physical_package(unsigned int max_cpus);
unsigned int vmsr_count_cpus_per_package(unsigned int *package_count,
                                         unsigned int max_pkgs);
int vmsr_get_physical_package_id(int cpu_id);
pid_t *vmsr_get_thread_ids(pid_t pid, unsigned int *num_threads);
double vmsr_get_ratio(uint64_t e_delta,
                      unsigned long long delta_ticks,
                      unsigned int maxticks);
void vmsr_init_topo_info(X86CPUTopoInfo *topo_info, const MachineState *ms);
bool is_host_cpu_intel(void);
int is_rapl_enabled(void);
#endif /* VMSR_ENERGY_H */