mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 19:13:47 +02:00
platform/x86:intel/pmc: Move PMC Core related functions
Move functions that implements PMC Core feature from core_ssram.c to core.c. This patch is a preparation step to introduce a new SSRAM Telemetry driver for the SSRAM device. Signed-off-by: Xi Pardee <xi.pardee@linux.intel.com> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Link: https://lore.kernel.org/r/20250409191056.15434-2-xi.pardee@linux.intel.com Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
parent
88f67f2a99
commit
78a7491d5c
|
|
@ -1345,6 +1345,173 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
|
|||
}
|
||||
}
|
||||
|
||||
static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map)
|
||||
{
|
||||
for (; list->map; ++list)
|
||||
if (list->map == map)
|
||||
return list->guid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmc_core_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc)
|
||||
{
|
||||
struct telem_endpoint *ep;
|
||||
const u8 *lpm_indices;
|
||||
int num_maps, mode_offset = 0;
|
||||
int ret, mode;
|
||||
int lpm_size;
|
||||
u32 guid;
|
||||
|
||||
lpm_indices = pmc->map->lpm_reg_index;
|
||||
num_maps = pmc->map->lpm_num_maps;
|
||||
lpm_size = LPM_MAX_NUM_MODES * num_maps;
|
||||
|
||||
guid = pmc_core_find_guid(pmcdev->regmap_list, pmc->map);
|
||||
if (!guid)
|
||||
return -ENXIO;
|
||||
|
||||
ep = pmt_telem_find_and_register_endpoint(pmcdev->ssram_pcidev, guid, 0);
|
||||
if (IS_ERR(ep)) {
|
||||
dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %ld",
|
||||
PTR_ERR(ep));
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
pmc->lpm_req_regs = devm_kzalloc(&pmcdev->pdev->dev,
|
||||
lpm_size * sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (!pmc->lpm_req_regs) {
|
||||
ret = -ENOMEM;
|
||||
goto unregister_ep;
|
||||
}
|
||||
|
||||
/*
|
||||
* PMC Low Power Mode (LPM) table
|
||||
*
|
||||
* In telemetry space, the LPM table contains a 4 byte header followed
|
||||
* by 8 consecutive mode blocks (one for each LPM mode). Each block
|
||||
* has a 4 byte header followed by a set of registers that describe the
|
||||
* IP state requirements for the given mode. The IP mapping is platform
|
||||
* specific but the same for each block, making for easy analysis.
|
||||
* Platforms only use a subset of the space to track the requirements
|
||||
* for their IPs. Callers provide the requirement registers they use as
|
||||
* a list of indices. Each requirement register is associated with an
|
||||
* IP map that's maintained by the caller.
|
||||
*
|
||||
* Header
|
||||
* +----+----------------------------+----------------------------+
|
||||
* | 0 | REVISION | ENABLED MODES |
|
||||
* +----+--------------+-------------+-------------+--------------+
|
||||
*
|
||||
* Low Power Mode 0 Block
|
||||
* +----+--------------+-------------+-------------+--------------+
|
||||
* | 1 | SUB ID | SIZE | MAJOR | MINOR |
|
||||
* +----+--------------+-------------+-------------+--------------+
|
||||
* | 2 | LPM0 Requirements 0 |
|
||||
* +----+---------------------------------------------------------+
|
||||
* | | ... |
|
||||
* +----+---------------------------------------------------------+
|
||||
* | 29 | LPM0 Requirements 27 |
|
||||
* +----+---------------------------------------------------------+
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* Low Power Mode 7 Block
|
||||
* +----+--------------+-------------+-------------+--------------+
|
||||
* | | SUB ID | SIZE | MAJOR | MINOR |
|
||||
* +----+--------------+-------------+-------------+--------------+
|
||||
* | 60 | LPM7 Requirements 0 |
|
||||
* +----+---------------------------------------------------------+
|
||||
* | | ... |
|
||||
* +----+---------------------------------------------------------+
|
||||
* | 87 | LPM7 Requirements 27 |
|
||||
* +----+---------------------------------------------------------+
|
||||
*
|
||||
*/
|
||||
mode_offset = LPM_HEADER_OFFSET + LPM_MODE_OFFSET;
|
||||
pmc_for_each_mode(mode, pmcdev) {
|
||||
u32 *req_offset = pmc->lpm_req_regs + (mode * num_maps);
|
||||
int m;
|
||||
|
||||
for (m = 0; m < num_maps; m++) {
|
||||
u8 sample_id = lpm_indices[m] + mode_offset;
|
||||
|
||||
ret = pmt_telem_read32(ep, sample_id, req_offset, 1);
|
||||
if (ret) {
|
||||
dev_err(&pmcdev->pdev->dev,
|
||||
"couldn't read Low Power Mode requirements: %d\n", ret);
|
||||
devm_kfree(&pmcdev->pdev->dev, pmc->lpm_req_regs);
|
||||
goto unregister_ep;
|
||||
}
|
||||
++req_offset;
|
||||
}
|
||||
mode_offset += LPM_REG_COUNT + LPM_MODE_OFFSET;
|
||||
}
|
||||
|
||||
unregister_ep:
|
||||
pmt_telem_unregister_endpoint(ep);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
if (!pmcdev->ssram_pcidev)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
|
||||
if (!pmcdev->pmcs[i])
|
||||
continue;
|
||||
|
||||
ret = pmc_core_get_lpm_req(pmcdev, pmcdev->pmcs[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 devid)
|
||||
{
|
||||
for (; list->map; ++list)
|
||||
if (devid == list->devid)
|
||||
return list->map;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int pmc_core_pmc_add(struct pmc_dev *pmcdev, u64 pwrm_base,
|
||||
const struct pmc_reg_map *reg_map, int pmc_index)
|
||||
{
|
||||
struct pmc *pmc = pmcdev->pmcs[pmc_index];
|
||||
|
||||
if (!pwrm_base)
|
||||
return -ENODEV;
|
||||
|
||||
/* Memory for primary PMC has been allocated in core.c */
|
||||
if (!pmc) {
|
||||
pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL);
|
||||
if (!pmc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pmc->map = reg_map;
|
||||
pmc->base_addr = pwrm_base;
|
||||
pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length);
|
||||
|
||||
if (!pmc->regbase) {
|
||||
devm_kfree(&pmcdev->pdev->dev, pmc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pmcdev->pmcs[pmc_index] = pmc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When supported, ssram init is used to achieve all available PMCs.
|
||||
* If ssram init fails, this function uses legacy method to at least get the
|
||||
|
|
@ -1719,5 +1886,6 @@ static struct platform_driver pmc_core_driver = {
|
|||
|
||||
module_platform_driver(pmc_core_driver);
|
||||
|
||||
MODULE_IMPORT_NS("INTEL_PMT_TELEMETRY");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Intel PMC Core Driver");
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@ struct telem_endpoint;
|
|||
#define MAX_NUM_PMC 3
|
||||
#define S0IX_BLK_SIZE 4
|
||||
|
||||
/* PCH query */
|
||||
#define LPM_HEADER_OFFSET 1
|
||||
#define LPM_REG_COUNT 28
|
||||
#define LPM_MODE_OFFSET 1
|
||||
|
||||
/* Sunrise Point Power Management Controller PCI Device ID */
|
||||
#define SPT_PMC_PCI_DEVICE_ID 0x9d21
|
||||
#define SPT_PMC_BASE_ADDR_OFFSET 0x48
|
||||
|
|
@ -485,7 +490,6 @@ extern const struct pmc_reg_map mtl_socm_reg_map;
|
|||
extern const struct pmc_reg_map mtl_ioep_reg_map;
|
||||
|
||||
void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev);
|
||||
int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev);
|
||||
int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore);
|
||||
|
||||
int pmc_core_resume_common(struct pmc_dev *pmcdev);
|
||||
|
|
@ -497,6 +501,9 @@ void pmc_core_set_device_d3(unsigned int device);
|
|||
int pmc_core_ssram_init(struct pmc_dev *pmcdev, int func);
|
||||
|
||||
int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
|
||||
const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 devid);
|
||||
int pmc_core_pmc_add(struct pmc_dev *pmcdev, u64 pwrm_base,
|
||||
const struct pmc_reg_map *reg_map, int pmc_index);
|
||||
|
||||
extern struct pmc_dev_info spt_pmc_dev;
|
||||
extern struct pmc_dev_info cnp_pmc_dev;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "../pmt/telemetry.h"
|
||||
|
||||
#define SSRAM_HDR_SIZE 0x100
|
||||
#define SSRAM_PWRM_OFFSET 0x14
|
||||
|
|
@ -24,142 +23,8 @@
|
|||
#define SSRAM_IOE_OFFSET 0x68
|
||||
#define SSRAM_DEVID_OFFSET 0x70
|
||||
|
||||
/* PCH query */
|
||||
#define LPM_HEADER_OFFSET 1
|
||||
#define LPM_REG_COUNT 28
|
||||
#define LPM_MODE_OFFSET 1
|
||||
|
||||
DEFINE_FREE(pmc_core_iounmap, void __iomem *, if (_T) iounmap(_T))
|
||||
|
||||
static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map)
|
||||
{
|
||||
for (; list->map; ++list)
|
||||
if (list->map == map)
|
||||
return list->guid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmc_core_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc)
|
||||
{
|
||||
struct telem_endpoint *ep;
|
||||
const u8 *lpm_indices;
|
||||
int num_maps, mode_offset = 0;
|
||||
int ret, mode;
|
||||
int lpm_size;
|
||||
u32 guid;
|
||||
|
||||
lpm_indices = pmc->map->lpm_reg_index;
|
||||
num_maps = pmc->map->lpm_num_maps;
|
||||
lpm_size = LPM_MAX_NUM_MODES * num_maps;
|
||||
|
||||
guid = pmc_core_find_guid(pmcdev->regmap_list, pmc->map);
|
||||
if (!guid)
|
||||
return -ENXIO;
|
||||
|
||||
ep = pmt_telem_find_and_register_endpoint(pmcdev->ssram_pcidev, guid, 0);
|
||||
if (IS_ERR(ep)) {
|
||||
dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %ld",
|
||||
PTR_ERR(ep));
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
pmc->lpm_req_regs = devm_kzalloc(&pmcdev->pdev->dev,
|
||||
lpm_size * sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (!pmc->lpm_req_regs) {
|
||||
ret = -ENOMEM;
|
||||
goto unregister_ep;
|
||||
}
|
||||
|
||||
/*
|
||||
* PMC Low Power Mode (LPM) table
|
||||
*
|
||||
* In telemetry space, the LPM table contains a 4 byte header followed
|
||||
* by 8 consecutive mode blocks (one for each LPM mode). Each block
|
||||
* has a 4 byte header followed by a set of registers that describe the
|
||||
* IP state requirements for the given mode. The IP mapping is platform
|
||||
* specific but the same for each block, making for easy analysis.
|
||||
* Platforms only use a subset of the space to track the requirements
|
||||
* for their IPs. Callers provide the requirement registers they use as
|
||||
* a list of indices. Each requirement register is associated with an
|
||||
* IP map that's maintained by the caller.
|
||||
*
|
||||
* Header
|
||||
* +----+----------------------------+----------------------------+
|
||||
* | 0 | REVISION | ENABLED MODES |
|
||||
* +----+--------------+-------------+-------------+--------------+
|
||||
*
|
||||
* Low Power Mode 0 Block
|
||||
* +----+--------------+-------------+-------------+--------------+
|
||||
* | 1 | SUB ID | SIZE | MAJOR | MINOR |
|
||||
* +----+--------------+-------------+-------------+--------------+
|
||||
* | 2 | LPM0 Requirements 0 |
|
||||
* +----+---------------------------------------------------------+
|
||||
* | | ... |
|
||||
* +----+---------------------------------------------------------+
|
||||
* | 29 | LPM0 Requirements 27 |
|
||||
* +----+---------------------------------------------------------+
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* Low Power Mode 7 Block
|
||||
* +----+--------------+-------------+-------------+--------------+
|
||||
* | | SUB ID | SIZE | MAJOR | MINOR |
|
||||
* +----+--------------+-------------+-------------+--------------+
|
||||
* | 60 | LPM7 Requirements 0 |
|
||||
* +----+---------------------------------------------------------+
|
||||
* | | ... |
|
||||
* +----+---------------------------------------------------------+
|
||||
* | 87 | LPM7 Requirements 27 |
|
||||
* +----+---------------------------------------------------------+
|
||||
*
|
||||
*/
|
||||
mode_offset = LPM_HEADER_OFFSET + LPM_MODE_OFFSET;
|
||||
pmc_for_each_mode(mode, pmcdev) {
|
||||
u32 *req_offset = pmc->lpm_req_regs + (mode * num_maps);
|
||||
int m;
|
||||
|
||||
for (m = 0; m < num_maps; m++) {
|
||||
u8 sample_id = lpm_indices[m] + mode_offset;
|
||||
|
||||
ret = pmt_telem_read32(ep, sample_id, req_offset, 1);
|
||||
if (ret) {
|
||||
dev_err(&pmcdev->pdev->dev,
|
||||
"couldn't read Low Power Mode requirements: %d\n", ret);
|
||||
devm_kfree(&pmcdev->pdev->dev, pmc->lpm_req_regs);
|
||||
goto unregister_ep;
|
||||
}
|
||||
++req_offset;
|
||||
}
|
||||
mode_offset += LPM_REG_COUNT + LPM_MODE_OFFSET;
|
||||
}
|
||||
|
||||
unregister_ep:
|
||||
pmt_telem_unregister_endpoint(ep);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
if (!pmcdev->ssram_pcidev)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
|
||||
if (!pmcdev->pmcs[i])
|
||||
continue;
|
||||
|
||||
ret = pmc_core_get_lpm_req(pmcdev, pmcdev->pmcs[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pmc_add_pmt(struct pmc_dev *pmcdev, u64 ssram_base, void __iomem *ssram)
|
||||
{
|
||||
|
|
@ -203,50 +68,11 @@ pmc_add_pmt(struct pmc_dev *pmcdev, u64 ssram_base, void __iomem *ssram)
|
|||
intel_vsec_register(pcidev, &info);
|
||||
}
|
||||
|
||||
static const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 devid)
|
||||
{
|
||||
for (; list->map; ++list)
|
||||
if (devid == list->devid)
|
||||
return list->map;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline u64 get_base(void __iomem *addr, u32 offset)
|
||||
{
|
||||
return lo_hi_readq(addr + offset) & GENMASK_ULL(63, 3);
|
||||
}
|
||||
|
||||
static int
|
||||
pmc_core_pmc_add(struct pmc_dev *pmcdev, u64 pwrm_base,
|
||||
const struct pmc_reg_map *reg_map, int pmc_index)
|
||||
{
|
||||
struct pmc *pmc = pmcdev->pmcs[pmc_index];
|
||||
|
||||
if (!pwrm_base)
|
||||
return -ENODEV;
|
||||
|
||||
/* Memory for primary PMC has been allocated in core.c */
|
||||
if (!pmc) {
|
||||
pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL);
|
||||
if (!pmc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pmc->map = reg_map;
|
||||
pmc->base_addr = pwrm_base;
|
||||
pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length);
|
||||
|
||||
if (!pmc->regbase) {
|
||||
devm_kfree(&pmcdev->pdev->dev, pmc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pmcdev->pmcs[pmc_index] = pmc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pmc_core_ssram_get_pmc(struct pmc_dev *pmcdev, int pmc_idx, u32 offset)
|
||||
{
|
||||
|
|
@ -329,4 +155,3 @@ int pmc_core_ssram_init(struct pmc_dev *pmcdev, int func)
|
|||
return ret;
|
||||
}
|
||||
MODULE_IMPORT_NS("INTEL_VSEC");
|
||||
MODULE_IMPORT_NS("INTEL_PMT_TELEMETRY");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user