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