// SPDX-License-Identifier: GPL-2.0 /* * This file contains functions to handle discovery of PMC metrics located * in the PMC SSRAM PCI device. * * Copyright (c) 2023, Intel Corporation. * All Rights Reserved. * */ #include #include #include "core.h" #define SSRAM_HDR_SIZE 0x100 #define SSRAM_PWRM_OFFSET 0x14 #define SSRAM_DVSEC_OFFSET 0x1C #define SSRAM_DVSEC_SIZE 0x10 #define SSRAM_PCH_OFFSET 0x60 #define SSRAM_IOE_OFFSET 0x68 #define SSRAM_DEVID_OFFSET 0x70 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 void 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; /* 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; } 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; } pmcdev->pmcs[pmc_index] = pmc; } static void pmc_core_ssram_get_pmc(struct pmc_dev *pmcdev, void __iomem *ssram, u32 offset, int pmc_idx) { u64 pwrm_base; u16 devid; if (pmc_idx != PMC_IDX_SOC) { u64 ssram_base = get_base(ssram, offset); if (!ssram_base) return; ssram = ioremap(ssram_base, SSRAM_HDR_SIZE); if (!ssram) return; } pwrm_base = get_base(ssram, SSRAM_PWRM_OFFSET); devid = readw(ssram + SSRAM_DEVID_OFFSET); if (pmcdev->regmap_list) { const struct pmc_reg_map *map; map = pmc_core_find_regmap(pmcdev->regmap_list, devid); if (map) pmc_core_pmc_add(pmcdev, pwrm_base, map, pmc_idx); } if (pmc_idx != PMC_IDX_SOC) iounmap(ssram); } void pmc_core_ssram_init(struct pmc_dev *pmcdev) { void __iomem *ssram; struct pci_dev *pcidev; u64 ssram_base; int ret; pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, 2)); if (!pcidev) goto out; ret = pcim_enable_device(pcidev); if (ret) goto release_dev; ssram_base = pcidev->resource[0].start; ssram = ioremap(ssram_base, SSRAM_HDR_SIZE); if (!ssram) goto disable_dev; pmcdev->ssram_pcidev = pcidev; pmc_core_ssram_get_pmc(pmcdev, ssram, 0, PMC_IDX_SOC); pmc_core_ssram_get_pmc(pmcdev, ssram, SSRAM_IOE_OFFSET, PMC_IDX_IOE); pmc_core_ssram_get_pmc(pmcdev, ssram, SSRAM_PCH_OFFSET, PMC_IDX_PCH); iounmap(ssram); out: return; disable_dev: pci_disable_device(pcidev); release_dev: pci_dev_put(pcidev); }