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 
telemetry_def_update_events(struct telemetry_evtconfig pss_evtconfig,struct telemetry_evtconfig ioss_evtconfig)24 static int telemetry_def_update_events(struct telemetry_evtconfig pss_evtconfig,
25 				      struct telemetry_evtconfig ioss_evtconfig)
26 {
27 	return 0;
28 }
29 
telemetry_def_set_sampling_period(u8 pss_period,u8 ioss_period)30 static int telemetry_def_set_sampling_period(u8 pss_period, u8 ioss_period)
31 {
32 	return 0;
33 }
34 
telemetry_def_get_sampling_period(u8 * pss_min_period,u8 * pss_max_period,u8 * ioss_min_period,u8 * ioss_max_period)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 
telemetry_def_get_eventconfig(struct telemetry_evtconfig * pss_evtconfig,struct telemetry_evtconfig * ioss_evtconfig,int pss_len,int ioss_len)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 
telemetry_def_get_trace_verbosity(enum telemetry_unit telem_unit,u32 * verbosity)51 static int telemetry_def_get_trace_verbosity(enum telemetry_unit telem_unit,
52 					     u32 *verbosity)
53 {
54 	return 0;
55 }
56 
57 
telemetry_def_set_trace_verbosity(enum telemetry_unit telem_unit,u32 verbosity)58 static int telemetry_def_set_trace_verbosity(enum telemetry_unit telem_unit,
59 					     u32 verbosity)
60 {
61 	return 0;
62 }
63 
telemetry_def_raw_read_eventlog(enum telemetry_unit telem_unit,struct telemetry_evtlog * evtlog,int len,int log_all_evts)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 
telemetry_def_read_eventlog(enum telemetry_unit telem_unit,struct telemetry_evtlog * evtlog,int len,int log_all_evts)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 
telemetry_def_add_events(u8 num_pss_evts,u8 num_ioss_evts,u32 * pss_evtmap,u32 * ioss_evtmap)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 
telemetry_def_reset_events(void)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  */
telemetry_update_events(struct telemetry_evtconfig pss_evtconfig,struct telemetry_evtconfig ioss_evtconfig)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  */
telemetry_set_sampling_period(u8 pss_period,u8 ioss_period)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  */
telemetry_get_sampling_period(u8 * pss_min_period,u8 * pss_max_period,u8 * ioss_min_period,u8 * ioss_max_period)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  */
telemetry_reset_events(void)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  */
telemetry_get_eventconfig(struct telemetry_evtconfig * pss_evtconfig,struct telemetry_evtconfig * ioss_evtconfig,int pss_len,int ioss_len)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  */
telemetry_add_events(u8 num_pss_evts,u8 num_ioss_evts,u32 * pss_evtmap,u32 * ioss_evtmap)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  */
telemetry_read_events(enum telemetry_unit telem_unit,struct telemetry_evtlog * evtlog,int len)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  */
telemetry_raw_read_events(enum telemetry_unit telem_unit,struct telemetry_evtlog * evtlog,int len)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  */
telemetry_read_eventlog(enum telemetry_unit telem_unit,struct telemetry_evtlog * evtlog,int len)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  */
telemetry_raw_read_eventlog(enum telemetry_unit telem_unit,struct telemetry_evtlog * evtlog,int len)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  */
telemetry_get_trace_verbosity(enum telemetry_unit telem_unit,u32 * verbosity)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  */
telemetry_set_trace_verbosity(enum telemetry_unit telem_unit,u32 verbosity)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  */
telemetry_set_pltdata(const struct telemetry_core_ops * ops,struct telemetry_plt_config * pltconfig)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  */
telemetry_clear_pltdata(void)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_pltconfig_valid() - Checkif platform config is valid
357  *
358  * Usage by other than telemetry module is invalid
359  *
360  * Return: 0 success, < 0 for failure
361  */
telemetry_pltconfig_valid(void)362 int telemetry_pltconfig_valid(void)
363 {
364 	if (telm_core_conf.plt_config)
365 		return 0;
366 
367 	else
368 		return -EINVAL;
369 }
370 EXPORT_SYMBOL_GPL(telemetry_pltconfig_valid);
371 
telemetry_get_pssevtname(enum telemetry_unit telem_unit,const char ** name,int len)372 static inline int telemetry_get_pssevtname(enum telemetry_unit telem_unit,
373 					   const char **name, int len)
374 {
375 	struct telemetry_unit_config psscfg;
376 	int i;
377 
378 	if (!telm_core_conf.plt_config)
379 		return -EINVAL;
380 
381 	psscfg = telm_core_conf.plt_config->pss_config;
382 
383 	if (len > psscfg.ssram_evts_used)
384 		len = psscfg.ssram_evts_used;
385 
386 	for (i = 0; i < len; i++)
387 		name[i] = psscfg.telem_evts[i].name;
388 
389 	return 0;
390 }
391 
telemetry_get_iossevtname(enum telemetry_unit telem_unit,const char ** name,int len)392 static inline int telemetry_get_iossevtname(enum telemetry_unit telem_unit,
393 					    const char **name, int len)
394 {
395 	struct telemetry_unit_config iosscfg;
396 	int i;
397 
398 	if (!(telm_core_conf.plt_config))
399 		return -EINVAL;
400 
401 	iosscfg = telm_core_conf.plt_config->ioss_config;
402 
403 	if (len > iosscfg.ssram_evts_used)
404 		len = iosscfg.ssram_evts_used;
405 
406 	for (i = 0; i < len; i++)
407 		name[i] = iosscfg.telem_evts[i].name;
408 
409 	return 0;
410 
411 }
412 
413 /**
414  * telemetry_get_evtname() - Checkif platform config is valid
415  * @telem_unit:	Telemetry Unit to check
416  * @name:	Array of character pointers to contain name
417  * @len:	length of array name provided by user
418  *
419  * Usage by other than telemetry debugfs module is invalid
420  *
421  * Return: 0 success, < 0 for failure
422  */
telemetry_get_evtname(enum telemetry_unit telem_unit,const char ** name,int len)423 int telemetry_get_evtname(enum telemetry_unit telem_unit,
424 			  const char **name, int len)
425 {
426 	int ret = -EINVAL;
427 
428 	if (telem_unit == TELEM_PSS)
429 		ret = telemetry_get_pssevtname(telem_unit, name, len);
430 
431 	else if (telem_unit == TELEM_IOSS)
432 		ret = telemetry_get_iossevtname(telem_unit, name, len);
433 
434 	return ret;
435 }
436 EXPORT_SYMBOL_GPL(telemetry_get_evtname);
437 
telemetry_module_init(void)438 static int __init telemetry_module_init(void)
439 {
440 	pr_info(pr_fmt(DRIVER_NAME) " Init\n");
441 
442 	telm_core_conf.telem_ops = &telm_defpltops;
443 	return 0;
444 }
445 
telemetry_module_exit(void)446 static void __exit telemetry_module_exit(void)
447 {
448 }
449 
450 module_init(telemetry_module_init);
451 module_exit(telemetry_module_exit);
452 
453 MODULE_AUTHOR("Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>");
454 MODULE_DESCRIPTION("Intel SoC Telemetry Interface");
455 MODULE_LICENSE("GPL v2");
456