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