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   * @ioss_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   * @ioss_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_get_pltdata() - Return telemetry platform config
357   *
358   * May be used by other telemetry modules to get platform specific
359   * configuration.
360   */
telemetry_get_pltdata(void)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  
telemetry_get_pssevtname(enum telemetry_unit telem_unit,const char ** name,int len)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  
telemetry_get_iossevtname(enum telemetry_unit telem_unit,const char ** name,int len)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   */
telemetry_get_evtname(enum telemetry_unit telem_unit,const char ** name,int len)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  
telemetry_module_init(void)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  
telemetry_module_exit(void)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");
451