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/cleanup.h>
12 #include <linux/intel_vsec.h>
13 #include <linux/pci.h>
14 #include <linux/io-64-nonatomic-lo-hi.h>
15
16 #include "core.h"
17 #include "../pmt/telemetry.h"
18
19 #define SSRAM_HDR_SIZE 0x100
20 #define SSRAM_PWRM_OFFSET 0x14
21 #define SSRAM_DVSEC_OFFSET 0x1C
22 #define SSRAM_DVSEC_SIZE 0x10
23 #define SSRAM_PCH_OFFSET 0x60
24 #define SSRAM_IOE_OFFSET 0x68
25 #define SSRAM_DEVID_OFFSET 0x70
26
27 /* PCH query */
28 #define LPM_HEADER_OFFSET 1
29 #define LPM_REG_COUNT 28
30 #define LPM_MODE_OFFSET 1
31
DEFINE_FREE(pmc_core_iounmap,void __iomem *,if (_T)iounmap (_T))32 DEFINE_FREE(pmc_core_iounmap, void __iomem *, if (_T) iounmap(_T))
33
34 static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map)
35 {
36 for (; list->map; ++list)
37 if (list->map == map)
38 return list->guid;
39
40 return 0;
41 }
42
pmc_core_get_lpm_req(struct pmc_dev * pmcdev,struct pmc * pmc)43 static int pmc_core_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc)
44 {
45 struct telem_endpoint *ep;
46 const u8 *lpm_indices;
47 int num_maps, mode_offset = 0;
48 int ret, mode;
49 int lpm_size;
50 u32 guid;
51
52 lpm_indices = pmc->map->lpm_reg_index;
53 num_maps = pmc->map->lpm_num_maps;
54 lpm_size = LPM_MAX_NUM_MODES * num_maps;
55
56 guid = pmc_core_find_guid(pmcdev->regmap_list, pmc->map);
57 if (!guid)
58 return -ENXIO;
59
60 ep = pmt_telem_find_and_register_endpoint(pmcdev->ssram_pcidev, guid, 0);
61 if (IS_ERR(ep)) {
62 dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %ld",
63 PTR_ERR(ep));
64 return -EPROBE_DEFER;
65 }
66
67 pmc->lpm_req_regs = devm_kzalloc(&pmcdev->pdev->dev,
68 lpm_size * sizeof(u32),
69 GFP_KERNEL);
70 if (!pmc->lpm_req_regs) {
71 ret = -ENOMEM;
72 goto unregister_ep;
73 }
74
75 /*
76 * PMC Low Power Mode (LPM) table
77 *
78 * In telemetry space, the LPM table contains a 4 byte header followed
79 * by 8 consecutive mode blocks (one for each LPM mode). Each block
80 * has a 4 byte header followed by a set of registers that describe the
81 * IP state requirements for the given mode. The IP mapping is platform
82 * specific but the same for each block, making for easy analysis.
83 * Platforms only use a subset of the space to track the requirements
84 * for their IPs. Callers provide the requirement registers they use as
85 * a list of indices. Each requirement register is associated with an
86 * IP map that's maintained by the caller.
87 *
88 * Header
89 * +----+----------------------------+----------------------------+
90 * | 0 | REVISION | ENABLED MODES |
91 * +----+--------------+-------------+-------------+--------------+
92 *
93 * Low Power Mode 0 Block
94 * +----+--------------+-------------+-------------+--------------+
95 * | 1 | SUB ID | SIZE | MAJOR | MINOR |
96 * +----+--------------+-------------+-------------+--------------+
97 * | 2 | LPM0 Requirements 0 |
98 * +----+---------------------------------------------------------+
99 * | | ... |
100 * +----+---------------------------------------------------------+
101 * | 29 | LPM0 Requirements 27 |
102 * +----+---------------------------------------------------------+
103 *
104 * ...
105 *
106 * Low Power Mode 7 Block
107 * +----+--------------+-------------+-------------+--------------+
108 * | | SUB ID | SIZE | MAJOR | MINOR |
109 * +----+--------------+-------------+-------------+--------------+
110 * | 60 | LPM7 Requirements 0 |
111 * +----+---------------------------------------------------------+
112 * | | ... |
113 * +----+---------------------------------------------------------+
114 * | 87 | LPM7 Requirements 27 |
115 * +----+---------------------------------------------------------+
116 *
117 */
118 mode_offset = LPM_HEADER_OFFSET + LPM_MODE_OFFSET;
119 pmc_for_each_mode(mode, pmcdev) {
120 u32 *req_offset = pmc->lpm_req_regs + (mode * num_maps);
121 int m;
122
123 for (m = 0; m < num_maps; m++) {
124 u8 sample_id = lpm_indices[m] + mode_offset;
125
126 ret = pmt_telem_read32(ep, sample_id, req_offset, 1);
127 if (ret) {
128 dev_err(&pmcdev->pdev->dev,
129 "couldn't read Low Power Mode requirements: %d\n", ret);
130 devm_kfree(&pmcdev->pdev->dev, pmc->lpm_req_regs);
131 goto unregister_ep;
132 }
133 ++req_offset;
134 }
135 mode_offset += LPM_REG_COUNT + LPM_MODE_OFFSET;
136 }
137
138 unregister_ep:
139 pmt_telem_unregister_endpoint(ep);
140
141 return ret;
142 }
143
pmc_core_ssram_get_lpm_reqs(struct pmc_dev * pmcdev)144 int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev)
145 {
146 int ret, i;
147
148 if (!pmcdev->ssram_pcidev)
149 return -ENODEV;
150
151 for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
152 if (!pmcdev->pmcs[i])
153 continue;
154
155 ret = pmc_core_get_lpm_req(pmcdev, pmcdev->pmcs[i]);
156 if (ret)
157 return ret;
158 }
159
160 return 0;
161 }
162
163 static void
pmc_add_pmt(struct pmc_dev * pmcdev,u64 ssram_base,void __iomem * ssram)164 pmc_add_pmt(struct pmc_dev *pmcdev, u64 ssram_base, void __iomem *ssram)
165 {
166 struct pci_dev *pcidev = pmcdev->ssram_pcidev;
167 struct intel_vsec_platform_info info = {};
168 struct intel_vsec_header *headers[2] = {};
169 struct intel_vsec_header header;
170 void __iomem *dvsec;
171 u32 dvsec_offset;
172 u32 table, hdr;
173
174 ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
175 if (!ssram)
176 return;
177
178 dvsec_offset = readl(ssram + SSRAM_DVSEC_OFFSET);
179 iounmap(ssram);
180
181 dvsec = ioremap(ssram_base + dvsec_offset, SSRAM_DVSEC_SIZE);
182 if (!dvsec)
183 return;
184
185 hdr = readl(dvsec + PCI_DVSEC_HEADER1);
186 header.id = readw(dvsec + PCI_DVSEC_HEADER2);
187 header.rev = PCI_DVSEC_HEADER1_REV(hdr);
188 header.length = PCI_DVSEC_HEADER1_LEN(hdr);
189 header.num_entries = readb(dvsec + INTEL_DVSEC_ENTRIES);
190 header.entry_size = readb(dvsec + INTEL_DVSEC_SIZE);
191
192 table = readl(dvsec + INTEL_DVSEC_TABLE);
193 header.tbir = INTEL_DVSEC_TABLE_BAR(table);
194 header.offset = INTEL_DVSEC_TABLE_OFFSET(table);
195 iounmap(dvsec);
196
197 headers[0] = &header;
198 info.caps = VSEC_CAP_TELEMETRY;
199 info.headers = headers;
200 info.base_addr = ssram_base;
201 info.parent = &pmcdev->pdev->dev;
202
203 intel_vsec_register(pcidev, &info);
204 }
205
pmc_core_find_regmap(struct pmc_info * list,u16 devid)206 static const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 devid)
207 {
208 for (; list->map; ++list)
209 if (devid == list->devid)
210 return list->map;
211
212 return NULL;
213 }
214
get_base(void __iomem * addr,u32 offset)215 static inline u64 get_base(void __iomem *addr, u32 offset)
216 {
217 return lo_hi_readq(addr + offset) & GENMASK_ULL(63, 3);
218 }
219
220 static int
pmc_core_pmc_add(struct pmc_dev * pmcdev,u64 pwrm_base,const struct pmc_reg_map * reg_map,int pmc_index)221 pmc_core_pmc_add(struct pmc_dev *pmcdev, u64 pwrm_base,
222 const struct pmc_reg_map *reg_map, int pmc_index)
223 {
224 struct pmc *pmc = pmcdev->pmcs[pmc_index];
225
226 if (!pwrm_base)
227 return -ENODEV;
228
229 /* Memory for primary PMC has been allocated in core.c */
230 if (!pmc) {
231 pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL);
232 if (!pmc)
233 return -ENOMEM;
234 }
235
236 pmc->map = reg_map;
237 pmc->base_addr = pwrm_base;
238 pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length);
239
240 if (!pmc->regbase) {
241 devm_kfree(&pmcdev->pdev->dev, pmc);
242 return -ENOMEM;
243 }
244
245 pmcdev->pmcs[pmc_index] = pmc;
246
247 return 0;
248 }
249
250 static int
pmc_core_ssram_get_pmc(struct pmc_dev * pmcdev,int pmc_idx,u32 offset)251 pmc_core_ssram_get_pmc(struct pmc_dev *pmcdev, int pmc_idx, u32 offset)
252 {
253 struct pci_dev *ssram_pcidev = pmcdev->ssram_pcidev;
254 void __iomem __free(pmc_core_iounmap) *tmp_ssram = NULL;
255 void __iomem __free(pmc_core_iounmap) *ssram = NULL;
256 const struct pmc_reg_map *map;
257 u64 ssram_base, pwrm_base;
258 u16 devid;
259
260 if (!pmcdev->regmap_list)
261 return -ENOENT;
262
263 ssram_base = ssram_pcidev->resource[0].start;
264 tmp_ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
265 if (!tmp_ssram)
266 return -ENOMEM;
267
268 if (pmc_idx != PMC_IDX_MAIN) {
269 /*
270 * The secondary PMC BARS (which are behind hidden PCI devices)
271 * are read from fixed offsets in MMIO of the primary PMC BAR.
272 */
273 ssram_base = get_base(tmp_ssram, offset);
274 ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
275 if (!ssram)
276 return -ENOMEM;
277
278 } else {
279 ssram = no_free_ptr(tmp_ssram);
280 }
281
282 pwrm_base = get_base(ssram, SSRAM_PWRM_OFFSET);
283 devid = readw(ssram + SSRAM_DEVID_OFFSET);
284
285 /* Find and register and PMC telemetry entries */
286 pmc_add_pmt(pmcdev, ssram_base, ssram);
287
288 map = pmc_core_find_regmap(pmcdev->regmap_list, devid);
289 if (!map)
290 return -ENODEV;
291
292 return pmc_core_pmc_add(pmcdev, pwrm_base, map, pmc_idx);
293 }
294
pmc_core_ssram_init(struct pmc_dev * pmcdev,int func)295 int pmc_core_ssram_init(struct pmc_dev *pmcdev, int func)
296 {
297 struct pci_dev *pcidev;
298 int ret;
299
300 pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, func));
301 if (!pcidev)
302 return -ENODEV;
303
304 ret = pcim_enable_device(pcidev);
305 if (ret)
306 goto release_dev;
307
308 pmcdev->ssram_pcidev = pcidev;
309
310 ret = pmc_core_ssram_get_pmc(pmcdev, PMC_IDX_MAIN, 0);
311 if (ret)
312 goto disable_dev;
313
314 pmc_core_ssram_get_pmc(pmcdev, PMC_IDX_IOE, SSRAM_IOE_OFFSET);
315 pmc_core_ssram_get_pmc(pmcdev, PMC_IDX_PCH, SSRAM_PCH_OFFSET);
316
317 return 0;
318
319 disable_dev:
320 pmcdev->ssram_pcidev = NULL;
321 pci_disable_device(pcidev);
322 release_dev:
323 pci_dev_put(pcidev);
324
325 return ret;
326 }
327 MODULE_IMPORT_NS(INTEL_VSEC);
328 MODULE_IMPORT_NS(INTEL_PMT_TELEMETRY);
329