Blame view

drivers/base/power/opp.c 24.1 KB
e1f60b292   Nishanth Menon   PM: Introduce lib...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   * Generic OPP Interface
   *
   * Copyright (C) 2009-2010 Texas Instruments Incorporated.
   *	Nishanth Menon
   *	Romit Dasgupta
   *	Kevin Hilman
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/err.h>
e1f60b292   Nishanth Menon   PM: Introduce lib...
17
  #include <linux/slab.h>
51990e825   Paul Gortmaker   device.h: cleanup...
18
  #include <linux/device.h>
e1f60b292   Nishanth Menon   PM: Introduce lib...
19
20
21
  #include <linux/list.h>
  #include <linux/rculist.h>
  #include <linux/rcupdate.h>
e4db1c743   Nishanth Menon   PM / OPP: rename ...
22
  #include <linux/pm_opp.h>
b496dfbc9   Shawn Guo   PM / OPP: Initial...
23
  #include <linux/of.h>
80126ce7a   Liam Girdwood   PM / OPP: Export ...
24
  #include <linux/export.h>
e1f60b292   Nishanth Menon   PM: Introduce lib...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  
  /*
   * Internal data structure organization with the OPP layer library is as
   * follows:
   * dev_opp_list (root)
   *	|- device 1 (represents voltage domain 1)
   *	|	|- opp 1 (availability, freq, voltage)
   *	|	|- opp 2 ..
   *	...	...
   *	|	`- opp n ..
   *	|- device 2 (represents the next voltage domain)
   *	...
   *	`- device m (represents mth voltage domain)
   * device 1, 2.. are represented by dev_opp structure while each opp
   * is represented by the opp structure.
   */
  
  /**
47d43ba73   Nishanth Menon   PM / OPP: rename ...
43
   * struct dev_pm_opp - Generic OPP description structure
e1f60b292   Nishanth Menon   PM: Introduce lib...
44
45
46
47
48
49
50
51
   * @node:	opp list node. The nodes are maintained throughout the lifetime
   *		of boot. It is expected only an optimal set of OPPs are
   *		added to the library by the SoC framework.
   *		RCU usage: opp list is traversed with RCU locks. node
   *		modification is possible realtime, hence the modifications
   *		are protected by the dev_opp_list_lock for integrity.
   *		IMPORTANT: the opp nodes should be maintained in increasing
   *		order.
38393409d   Viresh Kumar   PM / OPP mark OPP...
52
   * @dynamic:	not-created from static DT entries.
e1f60b292   Nishanth Menon   PM: Introduce lib...
53
54
55
56
   * @available:	true/false - marks if this OPP as available or not
   * @rate:	Frequency in hertz
   * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
   * @dev_opp:	points back to the device_opp struct this opp belongs to
cd1a068a5   Viresh Kumar   PM / OPP rename '...
57
   * @rcu_head:	RCU callback head used for deferred freeing
e1f60b292   Nishanth Menon   PM: Introduce lib...
58
59
60
   *
   * This structure stores the OPP information for a given device.
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
61
  struct dev_pm_opp {
e1f60b292   Nishanth Menon   PM: Introduce lib...
62
63
64
  	struct list_head node;
  
  	bool available;
38393409d   Viresh Kumar   PM / OPP mark OPP...
65
  	bool dynamic;
e1f60b292   Nishanth Menon   PM: Introduce lib...
66
67
68
69
  	unsigned long rate;
  	unsigned long u_volt;
  
  	struct device_opp *dev_opp;
cd1a068a5   Viresh Kumar   PM / OPP rename '...
70
  	struct rcu_head rcu_head;
e1f60b292   Nishanth Menon   PM: Introduce lib...
71
72
73
74
75
76
77
78
79
80
  };
  
  /**
   * struct device_opp - Device opp structure
   * @node:	list node - contains the devices with OPPs that
   *		have been registered. Nodes once added are not modified in this
   *		list.
   *		RCU usage: nodes are not modified in the list of device_opp,
   *		however addition is possible and is secured by dev_opp_list_lock
   * @dev:	device pointer
cd1a068a5   Viresh Kumar   PM / OPP rename '...
81
   * @srcu_head:	notifier head to notify the OPP availability changes.
129eec55d   Viresh Kumar   PM / OPP Introduc...
82
   * @rcu_head:	RCU callback head used for deferred freeing
e1f60b292   Nishanth Menon   PM: Introduce lib...
83
84
85
86
   * @opp_list:	list of opps
   *
   * This is an internal data structure maintaining the link to opps attached to
   * a device. This structure is not meant to be shared to users as it is
1c6a662f8   Viresh Kumar   PM / OPP: replace...
87
88
89
90
91
   * meant for book keeping and private to OPP library.
   *
   * Because the opp structures can be used from both rcu and srcu readers, we
   * need to wait for the grace period of both of them before freeing any
   * resources. And so we have used kfree_rcu() from within call_srcu() handlers.
e1f60b292   Nishanth Menon   PM: Introduce lib...
92
93
94
95
96
   */
  struct device_opp {
  	struct list_head node;
  
  	struct device *dev;
cd1a068a5   Viresh Kumar   PM / OPP rename '...
97
  	struct srcu_notifier_head srcu_head;
129eec55d   Viresh Kumar   PM / OPP Introduc...
98
  	struct rcu_head rcu_head;
e1f60b292   Nishanth Menon   PM: Introduce lib...
99
100
101
102
103
104
105
106
107
108
109
  	struct list_head opp_list;
  };
  
  /*
   * The root of the list of all devices. All device_opp structures branch off
   * from here, with each device_opp containing the list of opp it supports in
   * various states of availability.
   */
  static LIST_HEAD(dev_opp_list);
  /* Lock to allow exclusive modification to the device and opp lists */
  static DEFINE_MUTEX(dev_opp_list_lock);
b02ded246   Dmitry Torokhov   PM / OPP: add som...
110
111
112
113
114
115
116
  #define opp_rcu_lockdep_assert()					\
  do {									\
  	rcu_lockdep_assert(rcu_read_lock_held() ||			\
  				lockdep_is_held(&dev_opp_list_lock),	\
  			   "Missing rcu_read_lock() or "		\
  			   "dev_opp_list_lock protection");		\
  } while (0)
e1f60b292   Nishanth Menon   PM: Introduce lib...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  /**
   * find_device_opp() - find device_opp struct using device pointer
   * @dev:	device pointer used to lookup device OPPs
   *
   * Search list of device OPPs for one containing matching device. Does a RCU
   * reader operation to grab the pointer needed.
   *
   * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or
   * -EINVAL based on type of error.
   *
   * Locking: This function must be called under rcu_read_lock(). device_opp
   * is a RCU protected pointer. This means that device_opp is valid as long
   * as we are under RCU lock.
   */
  static struct device_opp *find_device_opp(struct device *dev)
  {
  	struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV);
  
  	if (unlikely(IS_ERR_OR_NULL(dev))) {
  		pr_err("%s: Invalid parameters
  ", __func__);
  		return ERR_PTR(-EINVAL);
  	}
  
  	list_for_each_entry_rcu(tmp_dev_opp, &dev_opp_list, node) {
  		if (tmp_dev_opp->dev == dev) {
  			dev_opp = tmp_dev_opp;
  			break;
  		}
  	}
  
  	return dev_opp;
  }
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
152
   * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an available opp
e1f60b292   Nishanth Menon   PM: Introduce lib...
153
154
155
156
157
158
159
160
161
162
163
164
165
   * @opp:	opp for which voltage has to be returned for
   *
   * Return voltage in micro volt corresponding to the opp, else
   * return 0
   *
   * Locking: This function must be called under rcu_read_lock(). opp is a rcu
   * protected pointer. This means that opp which could have been fetched by
   * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
   * under RCU lock. The pointer returned by the opp_find_freq family must be
   * used in the same section as the usage of this function with the pointer
   * prior to unlocking with rcu_read_unlock() to maintain the integrity of the
   * pointer.
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
166
  unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
e1f60b292   Nishanth Menon   PM: Introduce lib...
167
  {
47d43ba73   Nishanth Menon   PM / OPP: rename ...
168
  	struct dev_pm_opp *tmp_opp;
e1f60b292   Nishanth Menon   PM: Introduce lib...
169
170
171
172
173
174
175
176
177
178
179
  	unsigned long v = 0;
  
  	tmp_opp = rcu_dereference(opp);
  	if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
  		pr_err("%s: Invalid parameters
  ", __func__);
  	else
  		v = tmp_opp->u_volt;
  
  	return v;
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
180
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
e1f60b292   Nishanth Menon   PM: Introduce lib...
181
182
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
183
   * dev_pm_opp_get_freq() - Gets the frequency corresponding to an available opp
e1f60b292   Nishanth Menon   PM: Introduce lib...
184
185
186
187
188
189
190
191
192
193
194
195
196
   * @opp:	opp for which frequency has to be returned for
   *
   * Return frequency in hertz corresponding to the opp, else
   * return 0
   *
   * Locking: This function must be called under rcu_read_lock(). opp is a rcu
   * protected pointer. This means that opp which could have been fetched by
   * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
   * under RCU lock. The pointer returned by the opp_find_freq family must be
   * used in the same section as the usage of this function with the pointer
   * prior to unlocking with rcu_read_unlock() to maintain the integrity of the
   * pointer.
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
197
  unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
e1f60b292   Nishanth Menon   PM: Introduce lib...
198
  {
47d43ba73   Nishanth Menon   PM / OPP: rename ...
199
  	struct dev_pm_opp *tmp_opp;
e1f60b292   Nishanth Menon   PM: Introduce lib...
200
201
202
203
204
205
206
207
208
209
210
  	unsigned long f = 0;
  
  	tmp_opp = rcu_dereference(opp);
  	if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
  		pr_err("%s: Invalid parameters
  ", __func__);
  	else
  		f = tmp_opp->rate;
  
  	return f;
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
211
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
e1f60b292   Nishanth Menon   PM: Introduce lib...
212
213
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
214
   * dev_pm_opp_get_opp_count() - Get number of opps available in the opp list
e1f60b292   Nishanth Menon   PM: Introduce lib...
215
216
217
218
219
   * @dev:	device for which we do this operation
   *
   * This function returns the number of available opps if there are any,
   * else returns 0 if none or the corresponding error value.
   *
b4718c02f   Dmitry Torokhov   PM / OPP: take RC...
220
   * Locking: This function takes rcu_read_lock().
e1f60b292   Nishanth Menon   PM: Introduce lib...
221
   */
5d4879cda   Nishanth Menon   PM / OPP: rename ...
222
  int dev_pm_opp_get_opp_count(struct device *dev)
e1f60b292   Nishanth Menon   PM: Introduce lib...
223
224
  {
  	struct device_opp *dev_opp;
47d43ba73   Nishanth Menon   PM / OPP: rename ...
225
  	struct dev_pm_opp *temp_opp;
e1f60b292   Nishanth Menon   PM: Introduce lib...
226
  	int count = 0;
b4718c02f   Dmitry Torokhov   PM / OPP: take RC...
227
  	rcu_read_lock();
b02ded246   Dmitry Torokhov   PM / OPP: add som...
228

e1f60b292   Nishanth Menon   PM: Introduce lib...
229
230
  	dev_opp = find_device_opp(dev);
  	if (IS_ERR(dev_opp)) {
b4718c02f   Dmitry Torokhov   PM / OPP: take RC...
231
232
233
234
235
  		count = PTR_ERR(dev_opp);
  		dev_err(dev, "%s: device OPP not found (%d)
  ",
  			__func__, count);
  		goto out_unlock;
e1f60b292   Nishanth Menon   PM: Introduce lib...
236
237
238
239
240
241
  	}
  
  	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
  		if (temp_opp->available)
  			count++;
  	}
b4718c02f   Dmitry Torokhov   PM / OPP: take RC...
242
243
  out_unlock:
  	rcu_read_unlock();
e1f60b292   Nishanth Menon   PM: Introduce lib...
244
245
  	return count;
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
246
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
e1f60b292   Nishanth Menon   PM: Introduce lib...
247
248
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
249
   * dev_pm_opp_find_freq_exact() - search for an exact frequency
e1f60b292   Nishanth Menon   PM: Introduce lib...
250
251
   * @dev:		device for which we do this operation
   * @freq:		frequency to search for
7ae496187   Nishanth Menon   PM / OPP: opp_fin...
252
   * @available:		true/false - match for available opp
e1f60b292   Nishanth Menon   PM: Introduce lib...
253
254
255
   *
   * Searches for exact match in the opp list and returns pointer to the matching
   * opp if found, else returns ERR_PTR in case of error and should be handled
0779726cc   Nishanth Menon   PM / OPP: predict...
256
257
258
259
   * using IS_ERR. Error return values can be:
   * EINVAL:	for bad pointer
   * ERANGE:	no match found for search
   * ENODEV:	if device not found in list of registered devices
e1f60b292   Nishanth Menon   PM: Introduce lib...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
   *
   * Note: available is a modifier for the search. if available=true, then the
   * match is for exact matching frequency and is available in the stored OPP
   * table. if false, the match is for exact frequency which is not available.
   *
   * This provides a mechanism to enable an opp which is not available currently
   * or the opposite as well.
   *
   * Locking: This function must be called under rcu_read_lock(). opp is a rcu
   * protected pointer. The reason for the same is that the opp pointer which is
   * returned will remain valid for use with opp_get_{voltage, freq} only while
   * under the locked area. The pointer returned must be used prior to unlocking
   * with rcu_read_unlock() to maintain the integrity of the pointer.
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
274
275
276
  struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
  					      unsigned long freq,
  					      bool available)
e1f60b292   Nishanth Menon   PM: Introduce lib...
277
278
  {
  	struct device_opp *dev_opp;
47d43ba73   Nishanth Menon   PM / OPP: rename ...
279
  	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
e1f60b292   Nishanth Menon   PM: Introduce lib...
280

b02ded246   Dmitry Torokhov   PM / OPP: add som...
281
  	opp_rcu_lockdep_assert();
e1f60b292   Nishanth Menon   PM: Introduce lib...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
  	dev_opp = find_device_opp(dev);
  	if (IS_ERR(dev_opp)) {
  		int r = PTR_ERR(dev_opp);
  		dev_err(dev, "%s: device OPP not found (%d)
  ", __func__, r);
  		return ERR_PTR(r);
  	}
  
  	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
  		if (temp_opp->available == available &&
  				temp_opp->rate == freq) {
  			opp = temp_opp;
  			break;
  		}
  	}
  
  	return opp;
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
300
  EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
e1f60b292   Nishanth Menon   PM: Introduce lib...
301
302
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
303
   * dev_pm_opp_find_freq_ceil() - Search for an rounded ceil freq
e1f60b292   Nishanth Menon   PM: Introduce lib...
304
305
306
307
308
309
310
   * @dev:	device for which we do this operation
   * @freq:	Start frequency
   *
   * Search for the matching ceil *available* OPP from a starting freq
   * for a device.
   *
   * Returns matching *opp and refreshes *freq accordingly, else returns
0779726cc   Nishanth Menon   PM / OPP: predict...
311
312
313
314
315
   * ERR_PTR in case of error and should be handled using IS_ERR. Error return
   * values can be:
   * EINVAL:	for bad pointer
   * ERANGE:	no match found for search
   * ENODEV:	if device not found in list of registered devices
e1f60b292   Nishanth Menon   PM: Introduce lib...
316
317
318
319
320
321
322
   *
   * Locking: This function must be called under rcu_read_lock(). opp is a rcu
   * protected pointer. The reason for the same is that the opp pointer which is
   * returned will remain valid for use with opp_get_{voltage, freq} only while
   * under the locked area. The pointer returned must be used prior to unlocking
   * with rcu_read_unlock() to maintain the integrity of the pointer.
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
323
324
  struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
  					     unsigned long *freq)
e1f60b292   Nishanth Menon   PM: Introduce lib...
325
326
  {
  	struct device_opp *dev_opp;
47d43ba73   Nishanth Menon   PM / OPP: rename ...
327
  	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
e1f60b292   Nishanth Menon   PM: Introduce lib...
328

b02ded246   Dmitry Torokhov   PM / OPP: add som...
329
  	opp_rcu_lockdep_assert();
e1f60b292   Nishanth Menon   PM: Introduce lib...
330
331
332
333
334
335
336
337
  	if (!dev || !freq) {
  		dev_err(dev, "%s: Invalid argument freq=%p
  ", __func__, freq);
  		return ERR_PTR(-EINVAL);
  	}
  
  	dev_opp = find_device_opp(dev);
  	if (IS_ERR(dev_opp))
0779726cc   Nishanth Menon   PM / OPP: predict...
338
  		return ERR_CAST(dev_opp);
e1f60b292   Nishanth Menon   PM: Introduce lib...
339
340
341
342
343
344
345
346
347
348
349
  
  	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
  		if (temp_opp->available && temp_opp->rate >= *freq) {
  			opp = temp_opp;
  			*freq = opp->rate;
  			break;
  		}
  	}
  
  	return opp;
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
350
  EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
e1f60b292   Nishanth Menon   PM: Introduce lib...
351
352
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
353
   * dev_pm_opp_find_freq_floor() - Search for a rounded floor freq
e1f60b292   Nishanth Menon   PM: Introduce lib...
354
355
356
357
358
359
360
   * @dev:	device for which we do this operation
   * @freq:	Start frequency
   *
   * Search for the matching floor *available* OPP from a starting freq
   * for a device.
   *
   * Returns matching *opp and refreshes *freq accordingly, else returns
0779726cc   Nishanth Menon   PM / OPP: predict...
361
362
363
364
365
   * ERR_PTR in case of error and should be handled using IS_ERR. Error return
   * values can be:
   * EINVAL:	for bad pointer
   * ERANGE:	no match found for search
   * ENODEV:	if device not found in list of registered devices
e1f60b292   Nishanth Menon   PM: Introduce lib...
366
367
368
369
370
371
372
   *
   * Locking: This function must be called under rcu_read_lock(). opp is a rcu
   * protected pointer. The reason for the same is that the opp pointer which is
   * returned will remain valid for use with opp_get_{voltage, freq} only while
   * under the locked area. The pointer returned must be used prior to unlocking
   * with rcu_read_unlock() to maintain the integrity of the pointer.
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
373
374
  struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
  					      unsigned long *freq)
e1f60b292   Nishanth Menon   PM: Introduce lib...
375
376
  {
  	struct device_opp *dev_opp;
47d43ba73   Nishanth Menon   PM / OPP: rename ...
377
  	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
e1f60b292   Nishanth Menon   PM: Introduce lib...
378

b02ded246   Dmitry Torokhov   PM / OPP: add som...
379
  	opp_rcu_lockdep_assert();
e1f60b292   Nishanth Menon   PM: Introduce lib...
380
381
382
383
384
385
386
387
  	if (!dev || !freq) {
  		dev_err(dev, "%s: Invalid argument freq=%p
  ", __func__, freq);
  		return ERR_PTR(-EINVAL);
  	}
  
  	dev_opp = find_device_opp(dev);
  	if (IS_ERR(dev_opp))
0779726cc   Nishanth Menon   PM / OPP: predict...
388
  		return ERR_CAST(dev_opp);
e1f60b292   Nishanth Menon   PM: Introduce lib...
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  
  	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
  		if (temp_opp->available) {
  			/* go to the next node, before choosing prev */
  			if (temp_opp->rate > *freq)
  				break;
  			else
  				opp = temp_opp;
  		}
  	}
  	if (!IS_ERR(opp))
  		*freq = opp->rate;
  
  	return opp;
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
404
  EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
e1f60b292   Nishanth Menon   PM: Introduce lib...
405

07cce74a7   Viresh Kumar   PM / OPP: handle ...
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
  static struct device_opp *add_device_opp(struct device *dev)
  {
  	struct device_opp *dev_opp;
  
  	/*
  	 * Allocate a new device OPP table. In the infrequent case where a new
  	 * device is needed to be added, we pay this penalty.
  	 */
  	dev_opp = kzalloc(sizeof(*dev_opp), GFP_KERNEL);
  	if (!dev_opp)
  		return NULL;
  
  	dev_opp->dev = dev;
  	srcu_init_notifier_head(&dev_opp->srcu_head);
  	INIT_LIST_HEAD(&dev_opp->opp_list);
  
  	/* Secure the device list modification */
  	list_add_rcu(&dev_opp->node, &dev_opp_list);
  	return dev_opp;
  }
38393409d   Viresh Kumar   PM / OPP mark OPP...
426
427
  static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
  				  unsigned long u_volt, bool dynamic)
e1f60b292   Nishanth Menon   PM: Introduce lib...
428
429
  {
  	struct device_opp *dev_opp = NULL;
47d43ba73   Nishanth Menon   PM / OPP: rename ...
430
  	struct dev_pm_opp *opp, *new_opp;
e1f60b292   Nishanth Menon   PM: Introduce lib...
431
  	struct list_head *head;
6ce4184d0   Viresh Kumar   PM / OPP: do erro...
432
  	int ret;
e1f60b292   Nishanth Menon   PM: Introduce lib...
433
434
  
  	/* allocate new OPP node */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
435
  	new_opp = kzalloc(sizeof(*new_opp), GFP_KERNEL);
e1f60b292   Nishanth Menon   PM: Introduce lib...
436
437
438
439
440
441
442
443
  	if (!new_opp) {
  		dev_warn(dev, "%s: Unable to create new OPP node
  ", __func__);
  		return -ENOMEM;
  	}
  
  	/* Hold our list modification lock here */
  	mutex_lock(&dev_opp_list_lock);
a7470db6f   Viresh Kumar   PM / OPP don't ma...
444
  	/* populate the opp table */
a7470db6f   Viresh Kumar   PM / OPP don't ma...
445
446
447
  	new_opp->rate = freq;
  	new_opp->u_volt = u_volt;
  	new_opp->available = true;
38393409d   Viresh Kumar   PM / OPP mark OPP...
448
  	new_opp->dynamic = dynamic;
a7470db6f   Viresh Kumar   PM / OPP don't ma...
449

e1f60b292   Nishanth Menon   PM: Introduce lib...
450
451
452
  	/* Check for existing list for 'dev' */
  	dev_opp = find_device_opp(dev);
  	if (IS_ERR(dev_opp)) {
07cce74a7   Viresh Kumar   PM / OPP: handle ...
453
  		dev_opp = add_device_opp(dev);
e1f60b292   Nishanth Menon   PM: Introduce lib...
454
  		if (!dev_opp) {
6ce4184d0   Viresh Kumar   PM / OPP: do erro...
455
456
  			ret = -ENOMEM;
  			goto free_opp;
e1f60b292   Nishanth Menon   PM: Introduce lib...
457
  		}
a7470db6f   Viresh Kumar   PM / OPP don't ma...
458
459
  		head = &dev_opp->opp_list;
  		goto list_add;
e1f60b292   Nishanth Menon   PM: Introduce lib...
460
  	}
64ce85457   Chander Kashyap   PM / OPP: discard...
461
462
463
464
  	/*
  	 * Insert new OPP in order of increasing frequency
  	 * and discard if already present
  	 */
e1f60b292   Nishanth Menon   PM: Introduce lib...
465
466
  	head = &dev_opp->opp_list;
  	list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) {
64ce85457   Chander Kashyap   PM / OPP: discard...
467
  		if (new_opp->rate <= opp->rate)
e1f60b292   Nishanth Menon   PM: Introduce lib...
468
469
470
471
  			break;
  		else
  			head = &opp->node;
  	}
64ce85457   Chander Kashyap   PM / OPP: discard...
472
473
  	/* Duplicate OPPs ? */
  	if (new_opp->rate == opp->rate) {
6ce4184d0   Viresh Kumar   PM / OPP: do erro...
474
  		ret = opp->available && new_opp->u_volt == opp->u_volt ?
64ce85457   Chander Kashyap   PM / OPP: discard...
475
476
477
478
479
480
  			0 : -EEXIST;
  
  		dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d
  ",
  			 __func__, opp->rate, opp->u_volt, opp->available,
  			 new_opp->rate, new_opp->u_volt, new_opp->available);
6ce4184d0   Viresh Kumar   PM / OPP: do erro...
481
  		goto free_opp;
64ce85457   Chander Kashyap   PM / OPP: discard...
482
  	}
a7470db6f   Viresh Kumar   PM / OPP don't ma...
483
  list_add:
7284a00f1   Viresh Kumar   PM / OPP: set new...
484
  	new_opp->dev_opp = dev_opp;
e1f60b292   Nishanth Menon   PM: Introduce lib...
485
486
  	list_add_rcu(&new_opp->node, head);
  	mutex_unlock(&dev_opp_list_lock);
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
487
488
489
490
  	/*
  	 * Notify the changes in the availability of the operable
  	 * frequency/voltage list.
  	 */
cd1a068a5   Viresh Kumar   PM / OPP rename '...
491
  	srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp);
e1f60b292   Nishanth Menon   PM: Introduce lib...
492
  	return 0;
6ce4184d0   Viresh Kumar   PM / OPP: do erro...
493
494
495
496
497
  
  free_opp:
  	mutex_unlock(&dev_opp_list_lock);
  	kfree(new_opp);
  	return ret;
e1f60b292   Nishanth Menon   PM: Introduce lib...
498
  }
38393409d   Viresh Kumar   PM / OPP mark OPP...
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
  
  /**
   * dev_pm_opp_add()  - Add an OPP table from a table definitions
   * @dev:	device for which we do this operation
   * @freq:	Frequency in Hz for this OPP
   * @u_volt:	Voltage in uVolts for this OPP
   *
   * This function adds an opp definition to the opp list and returns status.
   * The opp is made available by default and it can be controlled using
   * dev_pm_opp_enable/disable functions.
   *
   * Locking: The internal device_opp and opp structures are RCU protected.
   * Hence this function internally uses RCU updater strategy with mutex locks
   * to keep the integrity of the internal data structures. Callers should ensure
   * that this function is *NOT* called under RCU protection or in contexts where
   * mutex cannot be locked.
   *
   * Return:
   * 0:		On success OR
   *		Duplicate OPPs (both freq and volt are same) and opp->available
   * -EEXIST:	Freq are same and volt are different OR
   *		Duplicate OPPs (both freq and volt are same) and !opp->available
   * -ENOMEM:	Memory allocation failure
   */
  int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
  {
  	return dev_pm_opp_add_dynamic(dev, freq, u_volt, true);
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
527
  EXPORT_SYMBOL_GPL(dev_pm_opp_add);
e1f60b292   Nishanth Menon   PM: Introduce lib...
528

129eec55d   Viresh Kumar   PM / OPP Introduc...
529
530
531
532
533
534
535
536
537
538
  static void kfree_opp_rcu(struct rcu_head *head)
  {
  	struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head);
  
  	kfree_rcu(opp, rcu_head);
  }
  
  static void kfree_device_rcu(struct rcu_head *head)
  {
  	struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head);
1c6a662f8   Viresh Kumar   PM / OPP: replace...
539
  	kfree_rcu(device_opp, rcu_head);
129eec55d   Viresh Kumar   PM / OPP Introduc...
540
  }
86453b473   Viresh Kumar   PM / OPP: Statici...
541
542
  static void __dev_pm_opp_remove(struct device_opp *dev_opp,
  				struct dev_pm_opp *opp)
129eec55d   Viresh Kumar   PM / OPP Introduc...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
  {
  	/*
  	 * Notify the changes in the availability of the operable
  	 * frequency/voltage list.
  	 */
  	srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp);
  	list_del_rcu(&opp->node);
  	call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
  
  	if (list_empty(&dev_opp->opp_list)) {
  		list_del_rcu(&dev_opp->node);
  		call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head,
  			  kfree_device_rcu);
  	}
  }
  
  /**
   * dev_pm_opp_remove()  - Remove an OPP from OPP list
   * @dev:	device for which we do this operation
   * @freq:	OPP to remove with matching 'freq'
   *
   * This function removes an opp from the opp list.
   */
  void dev_pm_opp_remove(struct device *dev, unsigned long freq)
  {
  	struct dev_pm_opp *opp;
  	struct device_opp *dev_opp;
  	bool found = false;
  
  	/* Hold our list modification lock here */
  	mutex_lock(&dev_opp_list_lock);
  
  	dev_opp = find_device_opp(dev);
  	if (IS_ERR(dev_opp))
  		goto unlock;
  
  	list_for_each_entry(opp, &dev_opp->opp_list, node) {
  		if (opp->rate == freq) {
  			found = true;
  			break;
  		}
  	}
  
  	if (!found) {
  		dev_warn(dev, "%s: Couldn't find OPP with freq: %lu
  ",
  			 __func__, freq);
  		goto unlock;
  	}
  
  	__dev_pm_opp_remove(dev_opp, opp);
  unlock:
  	mutex_unlock(&dev_opp_list_lock);
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
e1f60b292   Nishanth Menon   PM: Introduce lib...
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  /**
   * opp_set_availability() - helper to set the availability of an opp
   * @dev:		device for which we do this operation
   * @freq:		OPP frequency to modify availability
   * @availability_req:	availability status requested for this opp
   *
   * Set the availability of an OPP with an RCU operation, opp_{enable,disable}
   * share a common logic which is isolated here.
   *
   * Returns -EINVAL for bad pointers, -ENOMEM if no memory available for the
   * copy operation, returns 0 if no modifcation was done OR modification was
   * successful.
   *
   * Locking: The internal device_opp and opp structures are RCU protected.
   * Hence this function internally uses RCU updater strategy with mutex locks to
   * keep the integrity of the internal data structures. Callers should ensure
   * that this function is *NOT* called under RCU protection or in contexts where
   * mutex locking or synchronize_rcu() blocking calls cannot be used.
   */
  static int opp_set_availability(struct device *dev, unsigned long freq,
  		bool availability_req)
  {
29df0ee1b   Viresh Kumar   PM / OPP: reuse f...
620
  	struct device_opp *dev_opp;
47d43ba73   Nishanth Menon   PM / OPP: rename ...
621
  	struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV);
e1f60b292   Nishanth Menon   PM: Introduce lib...
622
623
624
  	int r = 0;
  
  	/* keep the node allocated */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
625
  	new_opp = kmalloc(sizeof(*new_opp), GFP_KERNEL);
e1f60b292   Nishanth Menon   PM: Introduce lib...
626
627
628
629
630
631
632
633
634
  	if (!new_opp) {
  		dev_warn(dev, "%s: Unable to create OPP
  ", __func__);
  		return -ENOMEM;
  	}
  
  	mutex_lock(&dev_opp_list_lock);
  
  	/* Find the device_opp */
29df0ee1b   Viresh Kumar   PM / OPP: reuse f...
635
  	dev_opp = find_device_opp(dev);
e1f60b292   Nishanth Menon   PM: Introduce lib...
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
  	if (IS_ERR(dev_opp)) {
  		r = PTR_ERR(dev_opp);
  		dev_warn(dev, "%s: Device OPP not found (%d)
  ", __func__, r);
  		goto unlock;
  	}
  
  	/* Do we have the frequency? */
  	list_for_each_entry(tmp_opp, &dev_opp->opp_list, node) {
  		if (tmp_opp->rate == freq) {
  			opp = tmp_opp;
  			break;
  		}
  	}
  	if (IS_ERR(opp)) {
  		r = PTR_ERR(opp);
  		goto unlock;
  	}
  
  	/* Is update really needed? */
  	if (opp->available == availability_req)
  		goto unlock;
  	/* copy the old data over */
  	*new_opp = *opp;
  
  	/* plug in new node */
  	new_opp->available = availability_req;
  
  	list_replace_rcu(&opp->node, &new_opp->node);
  	mutex_unlock(&dev_opp_list_lock);
b4037aaa5   Viresh Kumar   PM / OPP replace ...
666
  	call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
e1f60b292   Nishanth Menon   PM: Introduce lib...
667

03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
668
669
  	/* Notify the change of the OPP availability */
  	if (availability_req)
cd1a068a5   Viresh Kumar   PM / OPP rename '...
670
  		srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ENABLE,
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
671
672
  					 new_opp);
  	else
cd1a068a5   Viresh Kumar   PM / OPP rename '...
673
  		srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_DISABLE,
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
674
  					 new_opp);
dde8437d0   Vincent Guittot   PM / OPP: RCU rec...
675
  	return 0;
e1f60b292   Nishanth Menon   PM: Introduce lib...
676
677
678
  
  unlock:
  	mutex_unlock(&dev_opp_list_lock);
e1f60b292   Nishanth Menon   PM: Introduce lib...
679
680
681
682
683
  	kfree(new_opp);
  	return r;
  }
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
684
   * dev_pm_opp_enable() - Enable a specific OPP
e1f60b292   Nishanth Menon   PM: Introduce lib...
685
686
687
688
689
   * @dev:	device for which we do this operation
   * @freq:	OPP frequency to enable
   *
   * Enables a provided opp. If the operation is valid, this returns 0, else the
   * corresponding error value. It is meant to be used for users an OPP available
5d4879cda   Nishanth Menon   PM / OPP: rename ...
690
   * after being temporarily made unavailable with dev_pm_opp_disable.
e1f60b292   Nishanth Menon   PM: Introduce lib...
691
692
693
694
695
696
697
   *
   * Locking: The internal device_opp and opp structures are RCU protected.
   * Hence this function indirectly uses RCU and mutex locks to keep the
   * integrity of the internal data structures. Callers should ensure that
   * this function is *NOT* called under RCU protection or in contexts where
   * mutex locking or synchronize_rcu() blocking calls cannot be used.
   */
5d4879cda   Nishanth Menon   PM / OPP: rename ...
698
  int dev_pm_opp_enable(struct device *dev, unsigned long freq)
e1f60b292   Nishanth Menon   PM: Introduce lib...
699
700
701
  {
  	return opp_set_availability(dev, freq, true);
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
702
  EXPORT_SYMBOL_GPL(dev_pm_opp_enable);
e1f60b292   Nishanth Menon   PM: Introduce lib...
703
704
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
705
   * dev_pm_opp_disable() - Disable a specific OPP
e1f60b292   Nishanth Menon   PM: Introduce lib...
706
707
708
709
710
711
   * @dev:	device for which we do this operation
   * @freq:	OPP frequency to disable
   *
   * Disables a provided opp. If the operation is valid, this returns
   * 0, else the corresponding error value. It is meant to be a temporary
   * control by users to make this OPP not available until the circumstances are
5d4879cda   Nishanth Menon   PM / OPP: rename ...
712
   * right to make it available again (with a call to dev_pm_opp_enable).
e1f60b292   Nishanth Menon   PM: Introduce lib...
713
714
715
716
717
718
719
   *
   * Locking: The internal device_opp and opp structures are RCU protected.
   * Hence this function indirectly uses RCU and mutex locks to keep the
   * integrity of the internal data structures. Callers should ensure that
   * this function is *NOT* called under RCU protection or in contexts where
   * mutex locking or synchronize_rcu() blocking calls cannot be used.
   */
5d4879cda   Nishanth Menon   PM / OPP: rename ...
720
  int dev_pm_opp_disable(struct device *dev, unsigned long freq)
e1f60b292   Nishanth Menon   PM: Introduce lib...
721
722
723
  {
  	return opp_set_availability(dev, freq, false);
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
724
  EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
e1f60b292   Nishanth Menon   PM: Introduce lib...
725

03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
726
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
727
   * dev_pm_opp_get_notifier() - find notifier_head of the device with opp
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
728
729
   * @dev:	device pointer used to lookup device OPPs.
   */
5d4879cda   Nishanth Menon   PM / OPP: rename ...
730
  struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
731
732
733
734
  {
  	struct device_opp *dev_opp = find_device_opp(dev);
  
  	if (IS_ERR(dev_opp))
156acb166   Thomas Meyer   PM / OPP: Use ERR...
735
  		return ERR_CAST(dev_opp); /* matching type */
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
736

cd1a068a5   Viresh Kumar   PM / OPP rename '...
737
  	return &dev_opp->srcu_head;
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
738
  }
b496dfbc9   Shawn Guo   PM / OPP: Initial...
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
  
  #ifdef CONFIG_OF
  /**
   * of_init_opp_table() - Initialize opp table from device tree
   * @dev:	device pointer used to lookup device OPPs.
   *
   * Register the initial OPP table with the OPP library for given device.
   */
  int of_init_opp_table(struct device *dev)
  {
  	const struct property *prop;
  	const __be32 *val;
  	int nr;
  
  	prop = of_find_property(dev->of_node, "operating-points", NULL);
  	if (!prop)
  		return -ENODEV;
  	if (!prop->value)
  		return -ENODATA;
  
  	/*
  	 * Each OPP is a set of tuples consisting of frequency and
  	 * voltage like <freq-kHz vol-uV>.
  	 */
  	nr = prop->length / sizeof(u32);
  	if (nr % 2) {
  		dev_err(dev, "%s: Invalid OPP list
  ", __func__);
  		return -EINVAL;
  	}
  
  	val = prop->value;
  	while (nr) {
  		unsigned long freq = be32_to_cpup(val++) * 1000;
  		unsigned long volt = be32_to_cpup(val++);
38393409d   Viresh Kumar   PM / OPP mark OPP...
774
  		if (dev_pm_opp_add_dynamic(dev, freq, volt, false))
b496dfbc9   Shawn Guo   PM / OPP: Initial...
775
776
777
  			dev_warn(dev, "%s: Failed to add OPP %ld
  ",
  				 __func__, freq);
b496dfbc9   Shawn Guo   PM / OPP: Initial...
778
779
780
781
782
  		nr -= 2;
  	}
  
  	return 0;
  }
74c46c6ea   Mark Langsdorf   PM / OPP: Export ...
783
  EXPORT_SYMBOL_GPL(of_init_opp_table);
129eec55d   Viresh Kumar   PM / OPP Introduc...
784
785
786
787
788
789
790
791
792
  
  /**
   * of_free_opp_table() - Free OPP table entries created from static DT entries
   * @dev:	device pointer used to lookup device OPPs.
   *
   * Free OPPs created using static entries present in DT.
   */
  void of_free_opp_table(struct device *dev)
  {
2a6127d03   Viresh Kumar   PM / OPP: remove ...
793
  	struct device_opp *dev_opp;
129eec55d   Viresh Kumar   PM / OPP Introduc...
794
795
796
797
  	struct dev_pm_opp *opp, *tmp;
  
  	/* Check for existing list for 'dev' */
  	dev_opp = find_device_opp(dev);
0fe30da2c   Dmitry Torokhov   PM / OPP: fix war...
798
799
800
801
802
803
804
805
  	if (IS_ERR(dev_opp)) {
  		int error = PTR_ERR(dev_opp);
  		if (error != -ENODEV)
  			WARN(1, "%s: dev_opp: %d
  ",
  			     IS_ERR_OR_NULL(dev) ?
  					"Invalid device" : dev_name(dev),
  			     error);
129eec55d   Viresh Kumar   PM / OPP Introduc...
806
  		return;
0fe30da2c   Dmitry Torokhov   PM / OPP: fix war...
807
  	}
129eec55d   Viresh Kumar   PM / OPP Introduc...
808
809
810
811
812
813
814
815
816
817
818
819
820
  
  	/* Hold our list modification lock here */
  	mutex_lock(&dev_opp_list_lock);
  
  	/* Free static OPPs */
  	list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) {
  		if (!opp->dynamic)
  			__dev_pm_opp_remove(dev_opp, opp);
  	}
  
  	mutex_unlock(&dev_opp_list_lock);
  }
  EXPORT_SYMBOL_GPL(of_free_opp_table);
b496dfbc9   Shawn Guo   PM / OPP: Initial...
821
  #endif