]> git.ipfire.org Git - thirdparty/kernel/stable.git/blob - drivers/platform/x86/intel/telemetry/core.c
KVM: Harden copying of userspace-array against overflow
[thirdparty/kernel/stable.git] / drivers / platform / x86 / intel / telemetry / core.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Intel SoC Core Telemetry Driver
4 * Copyright (C) 2015, Intel Corporation.
5 * All Rights Reserved.
6 *
7 * Telemetry Framework provides platform related PM and performance statistics.
8 * This file provides the core telemetry API implementation.
9 */
10 #include <linux/device.h>
11 #include <linux/module.h>
12
13 #include <asm/intel_telemetry.h>
14
15 #define DRIVER_NAME "intel_telemetry_core"
16
17 struct telemetry_core_config {
18 struct telemetry_plt_config *plt_config;
19 const struct telemetry_core_ops *telem_ops;
20 };
21
22 static struct telemetry_core_config telm_core_conf;
23
24 static int telemetry_def_update_events(struct telemetry_evtconfig pss_evtconfig,
25 struct telemetry_evtconfig ioss_evtconfig)
26 {
27 return 0;
28 }
29
30 static int telemetry_def_set_sampling_period(u8 pss_period, u8 ioss_period)
31 {
32 return 0;
33 }
34
35 static int telemetry_def_get_sampling_period(u8 *pss_min_period,
36 u8 *pss_max_period,
37 u8 *ioss_min_period,
38 u8 *ioss_max_period)
39 {
40 return 0;
41 }
42
43 static int telemetry_def_get_eventconfig(
44 struct telemetry_evtconfig *pss_evtconfig,
45 struct telemetry_evtconfig *ioss_evtconfig,
46 int pss_len, int ioss_len)
47 {
48 return 0;
49 }
50
51 static int telemetry_def_get_trace_verbosity(enum telemetry_unit telem_unit,
52 u32 *verbosity)
53 {
54 return 0;
55 }
56
57
58 static int telemetry_def_set_trace_verbosity(enum telemetry_unit telem_unit,
59 u32 verbosity)
60 {
61 return 0;
62 }
63
64 static int telemetry_def_raw_read_eventlog(enum telemetry_unit telem_unit,
65 struct telemetry_evtlog *evtlog,
66 int len, int log_all_evts)
67 {
68 return 0;
69 }
70
71 static int telemetry_def_read_eventlog(enum telemetry_unit telem_unit,
72 struct telemetry_evtlog *evtlog,
73 int len, int log_all_evts)
74 {
75 return 0;
76 }
77
78 static int telemetry_def_add_events(u8 num_pss_evts, u8 num_ioss_evts,
79 u32 *pss_evtmap, u32 *ioss_evtmap)
80 {
81 return 0;
82 }
83
84 static int telemetry_def_reset_events(void)
85 {
86 return 0;
87 }
88
89 static const struct telemetry_core_ops telm_defpltops = {
90 .set_sampling_period = telemetry_def_set_sampling_period,
91 .get_sampling_period = telemetry_def_get_sampling_period,
92 .get_trace_verbosity = telemetry_def_get_trace_verbosity,
93 .set_trace_verbosity = telemetry_def_set_trace_verbosity,
94 .raw_read_eventlog = telemetry_def_raw_read_eventlog,
95 .get_eventconfig = telemetry_def_get_eventconfig,
96 .read_eventlog = telemetry_def_read_eventlog,
97 .update_events = telemetry_def_update_events,
98 .reset_events = telemetry_def_reset_events,
99 .add_events = telemetry_def_add_events,
100 };
101
102 /**
103 * telemetry_update_events() - Update telemetry Configuration
104 * @pss_evtconfig: PSS related config. No change if num_evts = 0.
105 * @pss_evtconfig: IOSS related config. No change if num_evts = 0.
106 *
107 * This API updates the IOSS & PSS Telemetry configuration. Old config
108 * is overwritten. Call telemetry_reset_events when logging is over
109 * All sample period values should be in the form of:
110 * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent)
111 *
112 * Return: 0 success, < 0 for failure
113 */
114 int telemetry_update_events(struct telemetry_evtconfig pss_evtconfig,
115 struct telemetry_evtconfig ioss_evtconfig)
116 {
117 return telm_core_conf.telem_ops->update_events(pss_evtconfig,
118 ioss_evtconfig);
119 }
120 EXPORT_SYMBOL_GPL(telemetry_update_events);
121
122
123 /**
124 * telemetry_set_sampling_period() - Sets the IOSS & PSS sampling period
125 * @pss_period: placeholder for PSS Period to be set.
126 * Set to 0 if not required to be updated
127 * @ioss_period: placeholder for IOSS Period to be set
128 * Set to 0 if not required to be updated
129 *
130 * All values should be in the form of:
131 * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent)
132 *
133 * Return: 0 success, < 0 for failure
134 */
135 int telemetry_set_sampling_period(u8 pss_period, u8 ioss_period)
136 {
137 return telm_core_conf.telem_ops->set_sampling_period(pss_period,
138 ioss_period);
139 }
140 EXPORT_SYMBOL_GPL(telemetry_set_sampling_period);
141
142 /**
143 * telemetry_get_sampling_period() - Get IOSS & PSS min & max sampling period
144 * @pss_min_period: placeholder for PSS Min Period supported
145 * @pss_max_period: placeholder for PSS Max Period supported
146 * @ioss_min_period: placeholder for IOSS Min Period supported
147 * @ioss_max_period: placeholder for IOSS Max Period supported
148 *
149 * All values should be in the form of:
150 * bits[6:3] -> value; bits [0:2]-> Exponent; Period = (Value *16^Exponent)
151 *
152 * Return: 0 success, < 0 for failure
153 */
154 int telemetry_get_sampling_period(u8 *pss_min_period, u8 *pss_max_period,
155 u8 *ioss_min_period, u8 *ioss_max_period)
156 {
157 return telm_core_conf.telem_ops->get_sampling_period(pss_min_period,
158 pss_max_period,
159 ioss_min_period,
160 ioss_max_period);
161 }
162 EXPORT_SYMBOL_GPL(telemetry_get_sampling_period);
163
164
165 /**
166 * telemetry_reset_events() - Restore the IOSS & PSS configuration to default
167 *
168 * Return: 0 success, < 0 for failure
169 */
170 int telemetry_reset_events(void)
171 {
172 return telm_core_conf.telem_ops->reset_events();
173 }
174 EXPORT_SYMBOL_GPL(telemetry_reset_events);
175
176 /**
177 * telemetry_get_eventconfig() - Returns the pss and ioss events enabled
178 * @pss_evtconfig: Pointer to PSS related configuration.
179 * @pss_evtconfig: Pointer to IOSS related configuration.
180 * @pss_len: Number of u32 elements allocated for pss_evtconfig array
181 * @ioss_len: Number of u32 elements allocated for ioss_evtconfig array
182 *
183 * Return: 0 success, < 0 for failure
184 */
185 int telemetry_get_eventconfig(struct telemetry_evtconfig *pss_evtconfig,
186 struct telemetry_evtconfig *ioss_evtconfig,
187 int pss_len, int ioss_len)
188 {
189 return telm_core_conf.telem_ops->get_eventconfig(pss_evtconfig,
190 ioss_evtconfig,
191 pss_len, ioss_len);
192 }
193 EXPORT_SYMBOL_GPL(telemetry_get_eventconfig);
194
195 /**
196 * telemetry_add_events() - Add IOSS & PSS configuration to existing settings.
197 * @num_pss_evts: Number of PSS Events (<29) in pss_evtmap. Can be 0.
198 * @num_ioss_evts: Number of IOSS Events (<29) in ioss_evtmap. Can be 0.
199 * @pss_evtmap: Array of PSS Event-IDs to Enable
200 * @ioss_evtmap: Array of PSS Event-IDs to Enable
201 *
202 * Events are appended to Old Configuration. In case of total events > 28, it
203 * returns error. Call telemetry_reset_events to reset after eventlog done
204 *
205 * Return: 0 success, < 0 for failure
206 */
207 int telemetry_add_events(u8 num_pss_evts, u8 num_ioss_evts,
208 u32 *pss_evtmap, u32 *ioss_evtmap)
209 {
210 return telm_core_conf.telem_ops->add_events(num_pss_evts,
211 num_ioss_evts, pss_evtmap,
212 ioss_evtmap);
213 }
214 EXPORT_SYMBOL_GPL(telemetry_add_events);
215
216 /**
217 * telemetry_read_events() - Fetches samples as specified by evtlog.telem_evt_id
218 * @telem_unit: Specify whether IOSS or PSS Read
219 * @evtlog: Array of telemetry_evtlog structs to fill data
220 * evtlog.telem_evt_id specifies the ids to read
221 * @len: Length of array of evtlog
222 *
223 * Return: number of eventlogs read for success, < 0 for failure
224 */
225 int telemetry_read_events(enum telemetry_unit telem_unit,
226 struct telemetry_evtlog *evtlog, int len)
227 {
228 return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog,
229 len, 0);
230 }
231 EXPORT_SYMBOL_GPL(telemetry_read_events);
232
233 /**
234 * telemetry_raw_read_events() - Fetch samples specified by evtlog.telem_evt_id
235 * @telem_unit: Specify whether IOSS or PSS Read
236 * @evtlog: Array of telemetry_evtlog structs to fill data
237 * evtlog.telem_evt_id specifies the ids to read
238 * @len: Length of array of evtlog
239 *
240 * The caller must take care of locking in this case.
241 *
242 * Return: number of eventlogs read for success, < 0 for failure
243 */
244 int telemetry_raw_read_events(enum telemetry_unit telem_unit,
245 struct telemetry_evtlog *evtlog, int len)
246 {
247 return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog,
248 len, 0);
249 }
250 EXPORT_SYMBOL_GPL(telemetry_raw_read_events);
251
252 /**
253 * telemetry_read_eventlog() - Fetch the Telemetry log from PSS or IOSS
254 * @telem_unit: Specify whether IOSS or PSS Read
255 * @evtlog: Array of telemetry_evtlog structs to fill data
256 * @len: Length of array of evtlog
257 *
258 * Return: number of eventlogs read for success, < 0 for failure
259 */
260 int telemetry_read_eventlog(enum telemetry_unit telem_unit,
261 struct telemetry_evtlog *evtlog, int len)
262 {
263 return telm_core_conf.telem_ops->read_eventlog(telem_unit, evtlog,
264 len, 1);
265 }
266 EXPORT_SYMBOL_GPL(telemetry_read_eventlog);
267
268 /**
269 * telemetry_raw_read_eventlog() - Fetch the Telemetry log from PSS or IOSS
270 * @telem_unit: Specify whether IOSS or PSS Read
271 * @evtlog: Array of telemetry_evtlog structs to fill data
272 * @len: Length of array of evtlog
273 *
274 * The caller must take care of locking in this case.
275 *
276 * Return: number of eventlogs read for success, < 0 for failure
277 */
278 int telemetry_raw_read_eventlog(enum telemetry_unit telem_unit,
279 struct telemetry_evtlog *evtlog, int len)
280 {
281 return telm_core_conf.telem_ops->raw_read_eventlog(telem_unit, evtlog,
282 len, 1);
283 }
284 EXPORT_SYMBOL_GPL(telemetry_raw_read_eventlog);
285
286
287 /**
288 * telemetry_get_trace_verbosity() - Get the IOSS & PSS Trace verbosity
289 * @telem_unit: Specify whether IOSS or PSS Read
290 * @verbosity: Pointer to return Verbosity
291 *
292 * Return: 0 success, < 0 for failure
293 */
294 int telemetry_get_trace_verbosity(enum telemetry_unit telem_unit,
295 u32 *verbosity)
296 {
297 return telm_core_conf.telem_ops->get_trace_verbosity(telem_unit,
298 verbosity);
299 }
300 EXPORT_SYMBOL_GPL(telemetry_get_trace_verbosity);
301
302
303 /**
304 * telemetry_set_trace_verbosity() - Update the IOSS & PSS Trace verbosity
305 * @telem_unit: Specify whether IOSS or PSS Read
306 * @verbosity: Verbosity to set
307 *
308 * Return: 0 success, < 0 for failure
309 */
310 int telemetry_set_trace_verbosity(enum telemetry_unit telem_unit, u32 verbosity)
311 {
312 return telm_core_conf.telem_ops->set_trace_verbosity(telem_unit,
313 verbosity);
314 }
315 EXPORT_SYMBOL_GPL(telemetry_set_trace_verbosity);
316
317 /**
318 * telemetry_set_pltdata() - Set the platform specific Data
319 * @ops: Pointer to ops structure
320 * @pltconfig: Platform config data
321 *
322 * Usage by other than telemetry pltdrv module is invalid
323 *
324 * Return: 0 success, < 0 for failure
325 */
326 int telemetry_set_pltdata(const struct telemetry_core_ops *ops,
327 struct telemetry_plt_config *pltconfig)
328 {
329 if (ops)
330 telm_core_conf.telem_ops = ops;
331
332 if (pltconfig)
333 telm_core_conf.plt_config = pltconfig;
334
335 return 0;
336 }
337 EXPORT_SYMBOL_GPL(telemetry_set_pltdata);
338
339 /**
340 * telemetry_clear_pltdata() - Clear the platform specific Data
341 *
342 * Usage by other than telemetry pltdrv module is invalid
343 *
344 * Return: 0 success, < 0 for failure
345 */
346 int telemetry_clear_pltdata(void)
347 {
348 telm_core_conf.telem_ops = &telm_defpltops;
349 telm_core_conf.plt_config = NULL;
350
351 return 0;
352 }
353 EXPORT_SYMBOL_GPL(telemetry_clear_pltdata);
354
355 /**
356 * telemetry_get_pltdata() - Return telemetry platform config
357 *
358 * May be used by other telemetry modules to get platform specific
359 * configuration.
360 */
361 struct telemetry_plt_config *telemetry_get_pltdata(void)
362 {
363 return telm_core_conf.plt_config;
364 }
365 EXPORT_SYMBOL_GPL(telemetry_get_pltdata);
366
367 static inline int telemetry_get_pssevtname(enum telemetry_unit telem_unit,
368 const char **name, int len)
369 {
370 struct telemetry_unit_config psscfg;
371 int i;
372
373 if (!telm_core_conf.plt_config)
374 return -EINVAL;
375
376 psscfg = telm_core_conf.plt_config->pss_config;
377
378 if (len > psscfg.ssram_evts_used)
379 len = psscfg.ssram_evts_used;
380
381 for (i = 0; i < len; i++)
382 name[i] = psscfg.telem_evts[i].name;
383
384 return 0;
385 }
386
387 static inline int telemetry_get_iossevtname(enum telemetry_unit telem_unit,
388 const char **name, int len)
389 {
390 struct telemetry_unit_config iosscfg;
391 int i;
392
393 if (!(telm_core_conf.plt_config))
394 return -EINVAL;
395
396 iosscfg = telm_core_conf.plt_config->ioss_config;
397
398 if (len > iosscfg.ssram_evts_used)
399 len = iosscfg.ssram_evts_used;
400
401 for (i = 0; i < len; i++)
402 name[i] = iosscfg.telem_evts[i].name;
403
404 return 0;
405
406 }
407
408 /**
409 * telemetry_get_evtname() - Checkif platform config is valid
410 * @telem_unit: Telemetry Unit to check
411 * @name: Array of character pointers to contain name
412 * @len: length of array name provided by user
413 *
414 * Usage by other than telemetry debugfs module is invalid
415 *
416 * Return: 0 success, < 0 for failure
417 */
418 int telemetry_get_evtname(enum telemetry_unit telem_unit,
419 const char **name, int len)
420 {
421 int ret = -EINVAL;
422
423 if (telem_unit == TELEM_PSS)
424 ret = telemetry_get_pssevtname(telem_unit, name, len);
425
426 else if (telem_unit == TELEM_IOSS)
427 ret = telemetry_get_iossevtname(telem_unit, name, len);
428
429 return ret;
430 }
431 EXPORT_SYMBOL_GPL(telemetry_get_evtname);
432
433 static int __init telemetry_module_init(void)
434 {
435 pr_info(pr_fmt(DRIVER_NAME) " Init\n");
436
437 telm_core_conf.telem_ops = &telm_defpltops;
438 return 0;
439 }
440
441 static void __exit telemetry_module_exit(void)
442 {
443 }
444
445 module_init(telemetry_module_init);
446 module_exit(telemetry_module_exit);
447
448 MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
449 MODULE_DESCRIPTION("Intel SoC Telemetry Interface");
450 MODULE_LICENSE("GPL v2");