1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * This file contains functions to handle discovery of PMC metrics located
4 * in the PMC SSRAM PCI device.
5 *
6 * Copyright (c) 2023, Intel Corporation.
7 * All Rights Reserved.
8 *
9 */
10
11 #include <linux/pci.h>
12 #include <linux/io-64-nonatomic-lo-hi.h>
13
14 #include "core.h"
15
16 #define SSRAM_HDR_SIZE 0x100
17 #define SSRAM_PWRM_OFFSET 0x14
18 #define SSRAM_DVSEC_OFFSET 0x1C
19 #define SSRAM_DVSEC_SIZE 0x10
20 #define SSRAM_PCH_OFFSET 0x60
21 #define SSRAM_IOE_OFFSET 0x68
22 #define SSRAM_DEVID_OFFSET 0x70
23
pmc_core_find_regmap(struct pmc_info * list,u16 devid)24 static const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 devid)
25 {
26 for (; list->map; ++list)
27 if (devid == list->devid)
28 return list->map;
29
30 return NULL;
31 }
32
get_base(void __iomem * addr,u32 offset)33 static inline u64 get_base(void __iomem *addr, u32 offset)
34 {
35 return lo_hi_readq(addr + offset) & GENMASK_ULL(63, 3);
36 }
37
38 static void
pmc_core_pmc_add(struct pmc_dev * pmcdev,u64 pwrm_base,const struct pmc_reg_map * reg_map,int pmc_index)39 pmc_core_pmc_add(struct pmc_dev *pmcdev, u64 pwrm_base,
40 const struct pmc_reg_map *reg_map, int pmc_index)
41 {
42 struct pmc *pmc = pmcdev->pmcs[pmc_index];
43
44 if (!pwrm_base)
45 return;
46
47 /* Memory for primary PMC has been allocated in core.c */
48 if (!pmc) {
49 pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL);
50 if (!pmc)
51 return;
52 }
53
54 pmc->map = reg_map;
55 pmc->base_addr = pwrm_base;
56 pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length);
57
58 if (!pmc->regbase) {
59 devm_kfree(&pmcdev->pdev->dev, pmc);
60 return;
61 }
62
63 pmcdev->pmcs[pmc_index] = pmc;
64 }
65
66 static void
pmc_core_ssram_get_pmc(struct pmc_dev * pmcdev,void __iomem * ssram,u32 offset,int pmc_idx)67 pmc_core_ssram_get_pmc(struct pmc_dev *pmcdev, void __iomem *ssram, u32 offset,
68 int pmc_idx)
69 {
70 u64 pwrm_base;
71 u16 devid;
72
73 if (pmc_idx != PMC_IDX_SOC) {
74 u64 ssram_base = get_base(ssram, offset);
75
76 if (!ssram_base)
77 return;
78
79 ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
80 if (!ssram)
81 return;
82 }
83
84 pwrm_base = get_base(ssram, SSRAM_PWRM_OFFSET);
85 devid = readw(ssram + SSRAM_DEVID_OFFSET);
86
87 if (pmcdev->regmap_list) {
88 const struct pmc_reg_map *map;
89
90 map = pmc_core_find_regmap(pmcdev->regmap_list, devid);
91 if (map)
92 pmc_core_pmc_add(pmcdev, pwrm_base, map, pmc_idx);
93 }
94
95 if (pmc_idx != PMC_IDX_SOC)
96 iounmap(ssram);
97 }
98
pmc_core_ssram_init(struct pmc_dev * pmcdev)99 void pmc_core_ssram_init(struct pmc_dev *pmcdev)
100 {
101 void __iomem *ssram;
102 struct pci_dev *pcidev;
103 u64 ssram_base;
104 int ret;
105
106 pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, 2));
107 if (!pcidev)
108 goto out;
109
110 ret = pcim_enable_device(pcidev);
111 if (ret)
112 goto release_dev;
113
114 ssram_base = pcidev->resource[0].start;
115 ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
116 if (!ssram)
117 goto disable_dev;
118
119 pmcdev->ssram_pcidev = pcidev;
120
121 pmc_core_ssram_get_pmc(pmcdev, ssram, 0, PMC_IDX_SOC);
122 pmc_core_ssram_get_pmc(pmcdev, ssram, SSRAM_IOE_OFFSET, PMC_IDX_IOE);
123 pmc_core_ssram_get_pmc(pmcdev, ssram, SSRAM_PCH_OFFSET, PMC_IDX_PCH);
124
125 iounmap(ssram);
126 out:
127 return;
128
129 disable_dev:
130 pci_disable_device(pcidev);
131 release_dev:
132 pci_dev_put(pcidev);
133 }
134