aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-11-30 20:46:54 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-11-30 20:46:54 -0500
commit2af3411f0e559914b8c6e289ed287e166fd502d7 (patch)
tree8507df49d028045023e11ef62614fc77ae293b31
parent8a497cfdc03412c36ba1689f0e68529d179f4e03 (diff)
parentb4037aaa584bd914bbf578f5ceb2d9884fa7ddb6 (diff)
Merge branch 'pm-opp' into pm-cpufreq
-rw-r--r--drivers/base/power/opp.c196
-rw-r--r--include/linux/pm_opp.h12
2 files changed, 166 insertions, 42 deletions
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 89ced955fafa..2d195f3a1998 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -49,11 +49,12 @@
49 * are protected by the dev_opp_list_lock for integrity. 49 * are protected by the dev_opp_list_lock for integrity.
50 * IMPORTANT: the opp nodes should be maintained in increasing 50 * IMPORTANT: the opp nodes should be maintained in increasing
51 * order. 51 * order.
52 * @dynamic: not-created from static DT entries.
52 * @available: true/false - marks if this OPP as available or not 53 * @available: true/false - marks if this OPP as available or not
53 * @rate: Frequency in hertz 54 * @rate: Frequency in hertz
54 * @u_volt: Nominal voltage in microvolts corresponding to this OPP 55 * @u_volt: Nominal voltage in microvolts corresponding to this OPP
55 * @dev_opp: points back to the device_opp struct this opp belongs to 56 * @dev_opp: points back to the device_opp struct this opp belongs to
56 * @head: RCU callback head used for deferred freeing 57 * @rcu_head: RCU callback head used for deferred freeing
57 * 58 *
58 * This structure stores the OPP information for a given device. 59 * This structure stores the OPP information for a given device.
59 */ 60 */
@@ -61,11 +62,12 @@ struct dev_pm_opp {
61 struct list_head node; 62 struct list_head node;
62 63
63 bool available; 64 bool available;
65 bool dynamic;
64 unsigned long rate; 66 unsigned long rate;
65 unsigned long u_volt; 67 unsigned long u_volt;
66 68
67 struct device_opp *dev_opp; 69 struct device_opp *dev_opp;
68 struct rcu_head head; 70 struct rcu_head rcu_head;
69}; 71};
70 72
71/** 73/**
@@ -76,7 +78,8 @@ struct dev_pm_opp {
76 * RCU usage: nodes are not modified in the list of device_opp, 78 * RCU usage: nodes are not modified in the list of device_opp,
77 * however addition is possible and is secured by dev_opp_list_lock 79 * however addition is possible and is secured by dev_opp_list_lock
78 * @dev: device pointer 80 * @dev: device pointer
79 * @head: notifier head to notify the OPP availability changes. 81 * @srcu_head: notifier head to notify the OPP availability changes.
82 * @rcu_head: RCU callback head used for deferred freeing
80 * @opp_list: list of opps 83 * @opp_list: list of opps
81 * 84 *
82 * This is an internal data structure maintaining the link to opps attached to 85 * This is an internal data structure maintaining the link to opps attached to
@@ -87,7 +90,8 @@ struct device_opp {
87 struct list_head node; 90 struct list_head node;
88 91
89 struct device *dev; 92 struct device *dev;
90 struct srcu_notifier_head head; 93 struct srcu_notifier_head srcu_head;
94 struct rcu_head rcu_head;
91 struct list_head opp_list; 95 struct list_head opp_list;
92}; 96};
93 97
@@ -378,30 +382,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
378} 382}
379EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); 383EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
380 384
381/** 385static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
382 * dev_pm_opp_add() - Add an OPP table from a table definitions 386 unsigned long u_volt, bool dynamic)
383 * @dev: device for which we do this operation
384 * @freq: Frequency in Hz for this OPP
385 * @u_volt: Voltage in uVolts for this OPP
386 *
387 * This function adds an opp definition to the opp list and returns status.
388 * The opp is made available by default and it can be controlled using
389 * dev_pm_opp_enable/disable functions.
390 *
391 * Locking: The internal device_opp and opp structures are RCU protected.
392 * Hence this function internally uses RCU updater strategy with mutex locks
393 * to keep the integrity of the internal data structures. Callers should ensure
394 * that this function is *NOT* called under RCU protection or in contexts where
395 * mutex cannot be locked.
396 *
397 * Return:
398 * 0: On success OR
399 * Duplicate OPPs (both freq and volt are same) and opp->available
400 * -EEXIST: Freq are same and volt are different OR
401 * Duplicate OPPs (both freq and volt are same) and !opp->available
402 * -ENOMEM: Memory allocation failure
403 */
404int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
405{ 387{
406 struct device_opp *dev_opp = NULL; 388 struct device_opp *dev_opp = NULL;
407 struct dev_pm_opp *opp, *new_opp; 389 struct dev_pm_opp *opp, *new_opp;
@@ -417,6 +399,13 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
417 /* Hold our list modification lock here */ 399 /* Hold our list modification lock here */
418 mutex_lock(&dev_opp_list_lock); 400 mutex_lock(&dev_opp_list_lock);
419 401
402 /* populate the opp table */
403 new_opp->dev_opp = dev_opp;
404 new_opp->rate = freq;
405 new_opp->u_volt = u_volt;
406 new_opp->available = true;
407 new_opp->dynamic = dynamic;
408
420 /* Check for existing list for 'dev' */ 409 /* Check for existing list for 'dev' */
421 dev_opp = find_device_opp(dev); 410 dev_opp = find_device_opp(dev);
422 if (IS_ERR(dev_opp)) { 411 if (IS_ERR(dev_opp)) {
@@ -436,19 +425,15 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
436 } 425 }
437 426
438 dev_opp->dev = dev; 427 dev_opp->dev = dev;
439 srcu_init_notifier_head(&dev_opp->head); 428 srcu_init_notifier_head(&dev_opp->srcu_head);
440 INIT_LIST_HEAD(&dev_opp->opp_list); 429 INIT_LIST_HEAD(&dev_opp->opp_list);
441 430
442 /* Secure the device list modification */ 431 /* Secure the device list modification */
443 list_add_rcu(&dev_opp->node, &dev_opp_list); 432 list_add_rcu(&dev_opp->node, &dev_opp_list);
433 head = &dev_opp->opp_list;
434 goto list_add;
444 } 435 }
445 436
446 /* populate the opp table */
447 new_opp->dev_opp = dev_opp;
448 new_opp->rate = freq;
449 new_opp->u_volt = u_volt;
450 new_opp->available = true;
451
452 /* 437 /*
453 * Insert new OPP in order of increasing frequency 438 * Insert new OPP in order of increasing frequency
454 * and discard if already present 439 * and discard if already present
@@ -474,6 +459,7 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
474 return ret; 459 return ret;
475 } 460 }
476 461
462list_add:
477 list_add_rcu(&new_opp->node, head); 463 list_add_rcu(&new_opp->node, head);
478 mutex_unlock(&dev_opp_list_lock); 464 mutex_unlock(&dev_opp_list_lock);
479 465
@@ -481,11 +467,109 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
481 * Notify the changes in the availability of the operable 467 * Notify the changes in the availability of the operable
482 * frequency/voltage list. 468 * frequency/voltage list.
483 */ 469 */
484 srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ADD, new_opp); 470 srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp);
485 return 0; 471 return 0;
486} 472}
473
474/**
475 * dev_pm_opp_add() - Add an OPP table from a table definitions
476 * @dev: device for which we do this operation
477 * @freq: Frequency in Hz for this OPP
478 * @u_volt: Voltage in uVolts for this OPP
479 *
480 * This function adds an opp definition to the opp list and returns status.
481 * The opp is made available by default and it can be controlled using
482 * dev_pm_opp_enable/disable functions.
483 *
484 * Locking: The internal device_opp and opp structures are RCU protected.
485 * Hence this function internally uses RCU updater strategy with mutex locks
486 * to keep the integrity of the internal data structures. Callers should ensure
487 * that this function is *NOT* called under RCU protection or in contexts where
488 * mutex cannot be locked.
489 *
490 * Return:
491 * 0: On success OR
492 * Duplicate OPPs (both freq and volt are same) and opp->available
493 * -EEXIST: Freq are same and volt are different OR
494 * Duplicate OPPs (both freq and volt are same) and !opp->available
495 * -ENOMEM: Memory allocation failure
496 */
497int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
498{
499 return dev_pm_opp_add_dynamic(dev, freq, u_volt, true);
500}
487EXPORT_SYMBOL_GPL(dev_pm_opp_add); 501EXPORT_SYMBOL_GPL(dev_pm_opp_add);
488 502
503static void kfree_opp_rcu(struct rcu_head *head)
504{
505 struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head);
506
507 kfree_rcu(opp, rcu_head);
508}
509
510static void kfree_device_rcu(struct rcu_head *head)
511{
512 struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head);
513
514 kfree(device_opp);
515}
516
517void __dev_pm_opp_remove(struct device_opp *dev_opp, struct dev_pm_opp *opp)
518{
519 /*
520 * Notify the changes in the availability of the operable
521 * frequency/voltage list.
522 */
523 srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp);
524 list_del_rcu(&opp->node);
525 call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
526
527 if (list_empty(&dev_opp->opp_list)) {
528 list_del_rcu(&dev_opp->node);
529 call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head,
530 kfree_device_rcu);
531 }
532}
533
534/**
535 * dev_pm_opp_remove() - Remove an OPP from OPP list
536 * @dev: device for which we do this operation
537 * @freq: OPP to remove with matching 'freq'
538 *
539 * This function removes an opp from the opp list.
540 */
541void dev_pm_opp_remove(struct device *dev, unsigned long freq)
542{
543 struct dev_pm_opp *opp;
544 struct device_opp *dev_opp;
545 bool found = false;
546
547 /* Hold our list modification lock here */
548 mutex_lock(&dev_opp_list_lock);
549
550 dev_opp = find_device_opp(dev);
551 if (IS_ERR(dev_opp))
552 goto unlock;
553
554 list_for_each_entry(opp, &dev_opp->opp_list, node) {
555 if (opp->rate == freq) {
556 found = true;
557 break;
558 }
559 }
560
561 if (!found) {
562 dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n",
563 __func__, freq);
564 goto unlock;
565 }
566
567 __dev_pm_opp_remove(dev_opp, opp);
568unlock:
569 mutex_unlock(&dev_opp_list_lock);
570}
571EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
572
489/** 573/**
490 * opp_set_availability() - helper to set the availability of an opp 574 * opp_set_availability() - helper to set the availability of an opp
491 * @dev: device for which we do this operation 575 * @dev: device for which we do this operation
@@ -557,14 +641,14 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
557 641
558 list_replace_rcu(&opp->node, &new_opp->node); 642 list_replace_rcu(&opp->node, &new_opp->node);
559 mutex_unlock(&dev_opp_list_lock); 643 mutex_unlock(&dev_opp_list_lock);
560 kfree_rcu(opp, head); 644 call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
561 645
562 /* Notify the change of the OPP availability */ 646 /* Notify the change of the OPP availability */
563 if (availability_req) 647 if (availability_req)
564 srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ENABLE, 648 srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ENABLE,
565 new_opp); 649 new_opp);
566 else 650 else
567 srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE, 651 srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_DISABLE,
568 new_opp); 652 new_opp);
569 653
570 return 0; 654 return 0;
@@ -629,7 +713,7 @@ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
629 if (IS_ERR(dev_opp)) 713 if (IS_ERR(dev_opp))
630 return ERR_CAST(dev_opp); /* matching type */ 714 return ERR_CAST(dev_opp); /* matching type */
631 715
632 return &dev_opp->head; 716 return &dev_opp->srcu_head;
633} 717}
634 718
635#ifdef CONFIG_OF 719#ifdef CONFIG_OF
@@ -666,7 +750,7 @@ int of_init_opp_table(struct device *dev)
666 unsigned long freq = be32_to_cpup(val++) * 1000; 750 unsigned long freq = be32_to_cpup(val++) * 1000;
667 unsigned long volt = be32_to_cpup(val++); 751 unsigned long volt = be32_to_cpup(val++);
668 752
669 if (dev_pm_opp_add(dev, freq, volt)) 753 if (dev_pm_opp_add_dynamic(dev, freq, volt, false))
670 dev_warn(dev, "%s: Failed to add OPP %ld\n", 754 dev_warn(dev, "%s: Failed to add OPP %ld\n",
671 __func__, freq); 755 __func__, freq);
672 nr -= 2; 756 nr -= 2;
@@ -675,4 +759,34 @@ int of_init_opp_table(struct device *dev)
675 return 0; 759 return 0;
676} 760}
677EXPORT_SYMBOL_GPL(of_init_opp_table); 761EXPORT_SYMBOL_GPL(of_init_opp_table);
762
763/**
764 * of_free_opp_table() - Free OPP table entries created from static DT entries
765 * @dev: device pointer used to lookup device OPPs.
766 *
767 * Free OPPs created using static entries present in DT.
768 */
769void of_free_opp_table(struct device *dev)
770{
771 struct device_opp *dev_opp = find_device_opp(dev);
772 struct dev_pm_opp *opp, *tmp;
773
774 /* Check for existing list for 'dev' */
775 dev_opp = find_device_opp(dev);
776 if (WARN(IS_ERR(dev_opp), "%s: dev_opp: %ld\n", dev_name(dev),
777 PTR_ERR(dev_opp)))
778 return;
779
780 /* Hold our list modification lock here */
781 mutex_lock(&dev_opp_list_lock);
782
783 /* Free static OPPs */
784 list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) {
785 if (!opp->dynamic)
786 __dev_pm_opp_remove(dev_opp, opp);
787 }
788
789 mutex_unlock(&dev_opp_list_lock);
790}
791EXPORT_SYMBOL_GPL(of_free_opp_table);
678#endif 792#endif
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 0330217abfad..cec2d4540914 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -21,7 +21,7 @@ struct dev_pm_opp;
21struct device; 21struct device;
22 22
23enum dev_pm_opp_event { 23enum dev_pm_opp_event {
24 OPP_EVENT_ADD, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE, 24 OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
25}; 25};
26 26
27#if defined(CONFIG_PM_OPP) 27#if defined(CONFIG_PM_OPP)
@@ -44,6 +44,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
44 44
45int dev_pm_opp_add(struct device *dev, unsigned long freq, 45int dev_pm_opp_add(struct device *dev, unsigned long freq,
46 unsigned long u_volt); 46 unsigned long u_volt);
47void dev_pm_opp_remove(struct device *dev, unsigned long freq);
47 48
48int dev_pm_opp_enable(struct device *dev, unsigned long freq); 49int dev_pm_opp_enable(struct device *dev, unsigned long freq);
49 50
@@ -90,6 +91,10 @@ static inline int dev_pm_opp_add(struct device *dev, unsigned long freq,
90 return -EINVAL; 91 return -EINVAL;
91} 92}
92 93
94static inline void dev_pm_opp_remove(struct device *dev, unsigned long freq)
95{
96}
97
93static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq) 98static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq)
94{ 99{
95 return 0; 100 return 0;
@@ -109,11 +114,16 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier(
109 114
110#if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) 115#if defined(CONFIG_PM_OPP) && defined(CONFIG_OF)
111int of_init_opp_table(struct device *dev); 116int of_init_opp_table(struct device *dev);
117void of_free_opp_table(struct device *dev);
112#else 118#else
113static inline int of_init_opp_table(struct device *dev) 119static inline int of_init_opp_table(struct device *dev)
114{ 120{
115 return -EINVAL; 121 return -EINVAL;
116} 122}
123
124static inline void of_free_opp_table(struct device *dev)
125{
126}
117#endif 127#endif
118 128
119#endif /* __LINUX_OPP_H__ */ 129#endif /* __LINUX_OPP_H__ */