diff options
-rw-r--r-- | drivers/base/power/clock_ops.c | 85 | ||||
-rw-r--r-- | drivers/base/power/opp.c | 196 | ||||
-rw-r--r-- | drivers/powercap/Kconfig | 2 | ||||
-rw-r--r-- | drivers/powercap/intel_rapl.c | 264 | ||||
-rw-r--r-- | include/linux/pm_clock.h | 8 | ||||
-rw-r--r-- | include/linux/pm_opp.h | 12 | ||||
-rw-r--r-- | kernel/power/Kconfig | 1 |
7 files changed, 405 insertions, 163 deletions
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 78369305e069..b32b5d47b3c5 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/pm.h> | 12 | #include <linux/pm.h> |
13 | #include <linux/pm_clock.h> | 13 | #include <linux/pm_clock.h> |
14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
15 | #include <linux/clkdev.h> | ||
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
16 | #include <linux/err.h> | 17 | #include <linux/err.h> |
17 | 18 | ||
@@ -34,14 +35,20 @@ struct pm_clock_entry { | |||
34 | /** | 35 | /** |
35 | * pm_clk_enable - Enable a clock, reporting any errors | 36 | * pm_clk_enable - Enable a clock, reporting any errors |
36 | * @dev: The device for the given clock | 37 | * @dev: The device for the given clock |
37 | * @clk: The clock being enabled. | 38 | * @ce: PM clock entry corresponding to the clock. |
38 | */ | 39 | */ |
39 | static inline int __pm_clk_enable(struct device *dev, struct clk *clk) | 40 | static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce) |
40 | { | 41 | { |
41 | int ret = clk_enable(clk); | 42 | int ret; |
42 | if (ret) | 43 | |
43 | dev_err(dev, "%s: failed to enable clk %p, error %d\n", | 44 | if (ce->status < PCE_STATUS_ERROR) { |
44 | __func__, clk, ret); | 45 | ret = clk_enable(ce->clk); |
46 | if (!ret) | ||
47 | ce->status = PCE_STATUS_ENABLED; | ||
48 | else | ||
49 | dev_err(dev, "%s: failed to enable clk %p, error %d\n", | ||
50 | __func__, ce->clk, ret); | ||
51 | } | ||
45 | 52 | ||
46 | return ret; | 53 | return ret; |
47 | } | 54 | } |
@@ -53,7 +60,8 @@ static inline int __pm_clk_enable(struct device *dev, struct clk *clk) | |||
53 | */ | 60 | */ |
54 | static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) | 61 | static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) |
55 | { | 62 | { |
56 | ce->clk = clk_get(dev, ce->con_id); | 63 | if (!ce->clk) |
64 | ce->clk = clk_get(dev, ce->con_id); | ||
57 | if (IS_ERR(ce->clk)) { | 65 | if (IS_ERR(ce->clk)) { |
58 | ce->status = PCE_STATUS_ERROR; | 66 | ce->status = PCE_STATUS_ERROR; |
59 | } else { | 67 | } else { |
@@ -63,15 +71,8 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) | |||
63 | } | 71 | } |
64 | } | 72 | } |
65 | 73 | ||
66 | /** | 74 | static int __pm_clk_add(struct device *dev, const char *con_id, |
67 | * pm_clk_add - Start using a device clock for power management. | 75 | struct clk *clk) |
68 | * @dev: Device whose clock is going to be used for power management. | ||
69 | * @con_id: Connection ID of the clock. | ||
70 | * | ||
71 | * Add the clock represented by @con_id to the list of clocks used for | ||
72 | * the power management of @dev. | ||
73 | */ | ||
74 | int pm_clk_add(struct device *dev, const char *con_id) | ||
75 | { | 76 | { |
76 | struct pm_subsys_data *psd = dev_to_psd(dev); | 77 | struct pm_subsys_data *psd = dev_to_psd(dev); |
77 | struct pm_clock_entry *ce; | 78 | struct pm_clock_entry *ce; |
@@ -93,6 +94,12 @@ int pm_clk_add(struct device *dev, const char *con_id) | |||
93 | kfree(ce); | 94 | kfree(ce); |
94 | return -ENOMEM; | 95 | return -ENOMEM; |
95 | } | 96 | } |
97 | } else { | ||
98 | if (IS_ERR(ce->clk) || !__clk_get(clk)) { | ||
99 | kfree(ce); | ||
100 | return -ENOENT; | ||
101 | } | ||
102 | ce->clk = clk; | ||
96 | } | 103 | } |
97 | 104 | ||
98 | pm_clk_acquire(dev, ce); | 105 | pm_clk_acquire(dev, ce); |
@@ -104,6 +111,32 @@ int pm_clk_add(struct device *dev, const char *con_id) | |||
104 | } | 111 | } |
105 | 112 | ||
106 | /** | 113 | /** |
114 | * pm_clk_add - Start using a device clock for power management. | ||
115 | * @dev: Device whose clock is going to be used for power management. | ||
116 | * @con_id: Connection ID of the clock. | ||
117 | * | ||
118 | * Add the clock represented by @con_id to the list of clocks used for | ||
119 | * the power management of @dev. | ||
120 | */ | ||
121 | int pm_clk_add(struct device *dev, const char *con_id) | ||
122 | { | ||
123 | return __pm_clk_add(dev, con_id, NULL); | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * pm_clk_add_clk - Start using a device clock for power management. | ||
128 | * @dev: Device whose clock is going to be used for power management. | ||
129 | * @clk: Clock pointer | ||
130 | * | ||
131 | * Add the clock to the list of clocks used for the power management of @dev. | ||
132 | * It will increment refcount on clock pointer, use clk_put() on it when done. | ||
133 | */ | ||
134 | int pm_clk_add_clk(struct device *dev, struct clk *clk) | ||
135 | { | ||
136 | return __pm_clk_add(dev, NULL, clk); | ||
137 | } | ||
138 | |||
139 | /** | ||
107 | * __pm_clk_remove - Destroy PM clock entry. | 140 | * __pm_clk_remove - Destroy PM clock entry. |
108 | * @ce: PM clock entry to destroy. | 141 | * @ce: PM clock entry to destroy. |
109 | */ | 142 | */ |
@@ -266,7 +299,6 @@ int pm_clk_resume(struct device *dev) | |||
266 | struct pm_subsys_data *psd = dev_to_psd(dev); | 299 | struct pm_subsys_data *psd = dev_to_psd(dev); |
267 | struct pm_clock_entry *ce; | 300 | struct pm_clock_entry *ce; |
268 | unsigned long flags; | 301 | unsigned long flags; |
269 | int ret; | ||
270 | 302 | ||
271 | dev_dbg(dev, "%s()\n", __func__); | 303 | dev_dbg(dev, "%s()\n", __func__); |
272 | 304 | ||
@@ -275,13 +307,8 @@ int pm_clk_resume(struct device *dev) | |||
275 | 307 | ||
276 | spin_lock_irqsave(&psd->lock, flags); | 308 | spin_lock_irqsave(&psd->lock, flags); |
277 | 309 | ||
278 | list_for_each_entry(ce, &psd->clock_list, node) { | 310 | list_for_each_entry(ce, &psd->clock_list, node) |
279 | if (ce->status < PCE_STATUS_ERROR) { | 311 | __pm_clk_enable(dev, ce); |
280 | ret = __pm_clk_enable(dev, ce->clk); | ||
281 | if (!ret) | ||
282 | ce->status = PCE_STATUS_ENABLED; | ||
283 | } | ||
284 | } | ||
285 | 312 | ||
286 | spin_unlock_irqrestore(&psd->lock, flags); | 313 | spin_unlock_irqrestore(&psd->lock, flags); |
287 | 314 | ||
@@ -390,7 +417,6 @@ int pm_clk_resume(struct device *dev) | |||
390 | struct pm_subsys_data *psd = dev_to_psd(dev); | 417 | struct pm_subsys_data *psd = dev_to_psd(dev); |
391 | struct pm_clock_entry *ce; | 418 | struct pm_clock_entry *ce; |
392 | unsigned long flags; | 419 | unsigned long flags; |
393 | int ret; | ||
394 | 420 | ||
395 | dev_dbg(dev, "%s()\n", __func__); | 421 | dev_dbg(dev, "%s()\n", __func__); |
396 | 422 | ||
@@ -400,13 +426,8 @@ int pm_clk_resume(struct device *dev) | |||
400 | 426 | ||
401 | spin_lock_irqsave(&psd->lock, flags); | 427 | spin_lock_irqsave(&psd->lock, flags); |
402 | 428 | ||
403 | list_for_each_entry(ce, &psd->clock_list, node) { | 429 | list_for_each_entry(ce, &psd->clock_list, node) |
404 | if (ce->status < PCE_STATUS_ERROR) { | 430 | __pm_clk_enable(dev, ce); |
405 | ret = __pm_clk_enable(dev, ce->clk); | ||
406 | if (!ret) | ||
407 | ce->status = PCE_STATUS_ENABLED; | ||
408 | } | ||
409 | } | ||
410 | 431 | ||
411 | spin_unlock_irqrestore(&psd->lock, flags); | 432 | spin_unlock_irqrestore(&psd->lock, flags); |
412 | 433 | ||
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 | } |
379 | EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); | 383 | EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); |
380 | 384 | ||
381 | /** | 385 | static 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 | */ | ||
404 | int 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 | ||
462 | list_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 | */ | ||
497 | int 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 | } | ||
487 | EXPORT_SYMBOL_GPL(dev_pm_opp_add); | 501 | EXPORT_SYMBOL_GPL(dev_pm_opp_add); |
488 | 502 | ||
503 | static 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 | |||
510 | static 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 | |||
517 | void __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 | */ | ||
541 | void 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); | ||
568 | unlock: | ||
569 | mutex_unlock(&dev_opp_list_lock); | ||
570 | } | ||
571 | EXPORT_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 | } |
677 | EXPORT_SYMBOL_GPL(of_init_opp_table); | 761 | EXPORT_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 | */ | ||
769 | void 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 | } | ||
791 | EXPORT_SYMBOL_GPL(of_free_opp_table); | ||
678 | #endif | 792 | #endif |
diff --git a/drivers/powercap/Kconfig b/drivers/powercap/Kconfig index a7c81b53d88a..85727ef6ce8e 100644 --- a/drivers/powercap/Kconfig +++ b/drivers/powercap/Kconfig | |||
@@ -17,7 +17,7 @@ if POWERCAP | |||
17 | # Client driver configurations go here. | 17 | # Client driver configurations go here. |
18 | config INTEL_RAPL | 18 | config INTEL_RAPL |
19 | tristate "Intel RAPL Support" | 19 | tristate "Intel RAPL Support" |
20 | depends on X86 | 20 | depends on X86 && IOSF_MBI |
21 | default n | 21 | default n |
22 | ---help--- | 22 | ---help--- |
23 | This enables support for the Intel Running Average Power Limit (RAPL) | 23 | This enables support for the Intel Running Average Power Limit (RAPL) |
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index 45e05b32f9b6..c71443c4f265 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/sysfs.h> | 29 | #include <linux/sysfs.h> |
30 | #include <linux/cpu.h> | 30 | #include <linux/cpu.h> |
31 | #include <linux/powercap.h> | 31 | #include <linux/powercap.h> |
32 | #include <asm/iosf_mbi.h> | ||
32 | 33 | ||
33 | #include <asm/processor.h> | 34 | #include <asm/processor.h> |
34 | #include <asm/cpu_device_id.h> | 35 | #include <asm/cpu_device_id.h> |
@@ -70,11 +71,6 @@ | |||
70 | #define RAPL_PRIMITIVE_DERIVED BIT(1) /* not from raw data */ | 71 | #define RAPL_PRIMITIVE_DERIVED BIT(1) /* not from raw data */ |
71 | #define RAPL_PRIMITIVE_DUMMY BIT(2) | 72 | #define RAPL_PRIMITIVE_DUMMY BIT(2) |
72 | 73 | ||
73 | /* scale RAPL units to avoid floating point math inside kernel */ | ||
74 | #define POWER_UNIT_SCALE (1000000) | ||
75 | #define ENERGY_UNIT_SCALE (1000000) | ||
76 | #define TIME_UNIT_SCALE (1000000) | ||
77 | |||
78 | #define TIME_WINDOW_MAX_MSEC 40000 | 74 | #define TIME_WINDOW_MAX_MSEC 40000 |
79 | #define TIME_WINDOW_MIN_MSEC 250 | 75 | #define TIME_WINDOW_MIN_MSEC 250 |
80 | 76 | ||
@@ -175,9 +171,9 @@ struct rapl_package { | |||
175 | unsigned int id; /* physical package/socket id */ | 171 | unsigned int id; /* physical package/socket id */ |
176 | unsigned int nr_domains; | 172 | unsigned int nr_domains; |
177 | unsigned long domain_map; /* bit map of active domains */ | 173 | unsigned long domain_map; /* bit map of active domains */ |
178 | unsigned int power_unit_divisor; | 174 | unsigned int power_unit; |
179 | unsigned int energy_unit_divisor; | 175 | unsigned int energy_unit; |
180 | unsigned int time_unit_divisor; | 176 | unsigned int time_unit; |
181 | struct rapl_domain *domains; /* array of domains, sized at runtime */ | 177 | struct rapl_domain *domains; /* array of domains, sized at runtime */ |
182 | struct powercap_zone *power_zone; /* keep track of parent zone */ | 178 | struct powercap_zone *power_zone; /* keep track of parent zone */ |
183 | int nr_cpus; /* active cpus on the package, topology info is lost during | 179 | int nr_cpus; /* active cpus on the package, topology info is lost during |
@@ -188,6 +184,18 @@ struct rapl_package { | |||
188 | */ | 184 | */ |
189 | struct list_head plist; | 185 | struct list_head plist; |
190 | }; | 186 | }; |
187 | |||
188 | struct rapl_defaults { | ||
189 | int (*check_unit)(struct rapl_package *rp, int cpu); | ||
190 | void (*set_floor_freq)(struct rapl_domain *rd, bool mode); | ||
191 | u64 (*compute_time_window)(struct rapl_package *rp, u64 val, | ||
192 | bool to_raw); | ||
193 | }; | ||
194 | static struct rapl_defaults *rapl_defaults; | ||
195 | |||
196 | /* Sideband MBI registers */ | ||
197 | #define IOSF_CPU_POWER_BUDGET_CTL (0x2) | ||
198 | |||
191 | #define PACKAGE_PLN_INT_SAVED BIT(0) | 199 | #define PACKAGE_PLN_INT_SAVED BIT(0) |
192 | #define MAX_PRIM_NAME (32) | 200 | #define MAX_PRIM_NAME (32) |
193 | 201 | ||
@@ -339,23 +347,13 @@ static int find_nr_power_limit(struct rapl_domain *rd) | |||
339 | static int set_domain_enable(struct powercap_zone *power_zone, bool mode) | 347 | static int set_domain_enable(struct powercap_zone *power_zone, bool mode) |
340 | { | 348 | { |
341 | struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone); | 349 | struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone); |
342 | int nr_powerlimit; | ||
343 | 350 | ||
344 | if (rd->state & DOMAIN_STATE_BIOS_LOCKED) | 351 | if (rd->state & DOMAIN_STATE_BIOS_LOCKED) |
345 | return -EACCES; | 352 | return -EACCES; |
353 | |||
346 | get_online_cpus(); | 354 | get_online_cpus(); |
347 | nr_powerlimit = find_nr_power_limit(rd); | ||
348 | /* here we activate/deactivate the hardware for power limiting */ | ||
349 | rapl_write_data_raw(rd, PL1_ENABLE, mode); | 355 | rapl_write_data_raw(rd, PL1_ENABLE, mode); |
350 | /* always enable clamp such that p-state can go below OS requested | 356 | rapl_defaults->set_floor_freq(rd, mode); |
351 | * range. power capping priority over guranteed frequency. | ||
352 | */ | ||
353 | rapl_write_data_raw(rd, PL1_CLAMP, mode); | ||
354 | /* some domains have pl2 */ | ||
355 | if (nr_powerlimit > 1) { | ||
356 | rapl_write_data_raw(rd, PL2_ENABLE, mode); | ||
357 | rapl_write_data_raw(rd, PL2_CLAMP, mode); | ||
358 | } | ||
359 | put_online_cpus(); | 357 | put_online_cpus(); |
360 | 358 | ||
361 | return 0; | 359 | return 0; |
@@ -653,9 +651,7 @@ static void rapl_init_domains(struct rapl_package *rp) | |||
653 | static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value, | 651 | static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value, |
654 | int to_raw) | 652 | int to_raw) |
655 | { | 653 | { |
656 | u64 divisor = 1; | 654 | u64 units = 1; |
657 | int scale = 1; /* scale to user friendly data without floating point */ | ||
658 | u64 f, y; /* fraction and exp. used for time unit */ | ||
659 | struct rapl_package *rp; | 655 | struct rapl_package *rp; |
660 | 656 | ||
661 | rp = find_package_by_id(package); | 657 | rp = find_package_by_id(package); |
@@ -664,42 +660,24 @@ static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value, | |||
664 | 660 | ||
665 | switch (type) { | 661 | switch (type) { |
666 | case POWER_UNIT: | 662 | case POWER_UNIT: |
667 | divisor = rp->power_unit_divisor; | 663 | units = rp->power_unit; |
668 | scale = POWER_UNIT_SCALE; | ||
669 | break; | 664 | break; |
670 | case ENERGY_UNIT: | 665 | case ENERGY_UNIT: |
671 | scale = ENERGY_UNIT_SCALE; | 666 | units = rp->energy_unit; |
672 | divisor = rp->energy_unit_divisor; | ||
673 | break; | 667 | break; |
674 | case TIME_UNIT: | 668 | case TIME_UNIT: |
675 | divisor = rp->time_unit_divisor; | 669 | return rapl_defaults->compute_time_window(rp, value, to_raw); |
676 | scale = TIME_UNIT_SCALE; | ||
677 | /* special processing based on 2^Y*(1+F)/4 = val/divisor, refer | ||
678 | * to Intel Software Developer's manual Vol. 3a, CH 14.7.4. | ||
679 | */ | ||
680 | if (!to_raw) { | ||
681 | f = (value & 0x60) >> 5; | ||
682 | y = value & 0x1f; | ||
683 | value = (1 << y) * (4 + f) * scale / 4; | ||
684 | return div64_u64(value, divisor); | ||
685 | } else { | ||
686 | do_div(value, scale); | ||
687 | value *= divisor; | ||
688 | y = ilog2(value); | ||
689 | f = div64_u64(4 * (value - (1 << y)), 1 << y); | ||
690 | value = (y & 0x1f) | ((f & 0x3) << 5); | ||
691 | return value; | ||
692 | } | ||
693 | break; | ||
694 | case ARBITRARY_UNIT: | 670 | case ARBITRARY_UNIT: |
695 | default: | 671 | default: |
696 | return value; | 672 | return value; |
697 | }; | 673 | }; |
698 | 674 | ||
699 | if (to_raw) | 675 | if (to_raw) |
700 | return div64_u64(value * divisor, scale); | 676 | return div64_u64(value, units); |
701 | else | 677 | |
702 | return div64_u64(value * scale, divisor); | 678 | value *= units; |
679 | |||
680 | return value; | ||
703 | } | 681 | } |
704 | 682 | ||
705 | /* in the order of enum rapl_primitives */ | 683 | /* in the order of enum rapl_primitives */ |
@@ -833,12 +811,18 @@ static int rapl_write_data_raw(struct rapl_domain *rd, | |||
833 | return 0; | 811 | return 0; |
834 | } | 812 | } |
835 | 813 | ||
836 | static const struct x86_cpu_id energy_unit_quirk_ids[] = { | 814 | /* |
837 | { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */ | 815 | * Raw RAPL data stored in MSRs are in certain scales. We need to |
838 | {} | 816 | * convert them into standard units based on the units reported in |
839 | }; | 817 | * the RAPL unit MSRs. This is specific to CPUs as the method to |
840 | 818 | * calculate units differ on different CPUs. | |
841 | static int rapl_check_unit(struct rapl_package *rp, int cpu) | 819 | * We convert the units to below format based on CPUs. |
820 | * i.e. | ||
821 | * energy unit: microJoules : Represented in microJoules by default | ||
822 | * power unit : microWatts : Represented in milliWatts by default | ||
823 | * time unit : microseconds: Represented in seconds by default | ||
824 | */ | ||
825 | static int rapl_check_unit_core(struct rapl_package *rp, int cpu) | ||
842 | { | 826 | { |
843 | u64 msr_val; | 827 | u64 msr_val; |
844 | u32 value; | 828 | u32 value; |
@@ -849,36 +833,47 @@ static int rapl_check_unit(struct rapl_package *rp, int cpu) | |||
849 | return -ENODEV; | 833 | return -ENODEV; |
850 | } | 834 | } |
851 | 835 | ||
852 | /* Raw RAPL data stored in MSRs are in certain scales. We need to | ||
853 | * convert them into standard units based on the divisors reported in | ||
854 | * the RAPL unit MSRs. | ||
855 | * i.e. | ||
856 | * energy unit: 1/enery_unit_divisor Joules | ||
857 | * power unit: 1/power_unit_divisor Watts | ||
858 | * time unit: 1/time_unit_divisor Seconds | ||
859 | */ | ||
860 | value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET; | 836 | value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET; |
861 | /* some CPUs have different way to calculate energy unit */ | 837 | rp->energy_unit = 1000000 / (1 << value); |
862 | if (x86_match_cpu(energy_unit_quirk_ids)) | ||
863 | rp->energy_unit_divisor = 1000000 / (1 << value); | ||
864 | else | ||
865 | rp->energy_unit_divisor = 1 << value; | ||
866 | 838 | ||
867 | value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET; | 839 | value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET; |
868 | rp->power_unit_divisor = 1 << value; | 840 | rp->power_unit = 1000000 / (1 << value); |
869 | 841 | ||
870 | value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET; | 842 | value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET; |
871 | rp->time_unit_divisor = 1 << value; | 843 | rp->time_unit = 1000000 / (1 << value); |
872 | 844 | ||
873 | pr_debug("Physical package %d units: energy=%d, time=%d, power=%d\n", | 845 | pr_debug("Core CPU package %d energy=%duJ, time=%dus, power=%duW\n", |
874 | rp->id, | 846 | rp->id, rp->energy_unit, rp->time_unit, rp->power_unit); |
875 | rp->energy_unit_divisor, | ||
876 | rp->time_unit_divisor, | ||
877 | rp->power_unit_divisor); | ||
878 | 847 | ||
879 | return 0; | 848 | return 0; |
880 | } | 849 | } |
881 | 850 | ||
851 | static int rapl_check_unit_atom(struct rapl_package *rp, int cpu) | ||
852 | { | ||
853 | u64 msr_val; | ||
854 | u32 value; | ||
855 | |||
856 | if (rdmsrl_safe_on_cpu(cpu, MSR_RAPL_POWER_UNIT, &msr_val)) { | ||
857 | pr_err("Failed to read power unit MSR 0x%x on CPU %d, exit.\n", | ||
858 | MSR_RAPL_POWER_UNIT, cpu); | ||
859 | return -ENODEV; | ||
860 | } | ||
861 | value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET; | ||
862 | rp->energy_unit = 1 << value; | ||
863 | |||
864 | value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET; | ||
865 | rp->power_unit = (1 << value) * 1000; | ||
866 | |||
867 | value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET; | ||
868 | rp->time_unit = 1000000 / (1 << value); | ||
869 | |||
870 | pr_debug("Atom package %d energy=%duJ, time=%dus, power=%duW\n", | ||
871 | rp->id, rp->energy_unit, rp->time_unit, rp->power_unit); | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | |||
882 | /* REVISIT: | 877 | /* REVISIT: |
883 | * When package power limit is set artificially low by RAPL, LVT | 878 | * When package power limit is set artificially low by RAPL, LVT |
884 | * thermal interrupt for package power limit should be ignored | 879 | * thermal interrupt for package power limit should be ignored |
@@ -946,16 +941,107 @@ static void package_power_limit_irq_restore(int package_id) | |||
946 | wrmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); | 941 | wrmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); |
947 | } | 942 | } |
948 | 943 | ||
944 | static void set_floor_freq_default(struct rapl_domain *rd, bool mode) | ||
945 | { | ||
946 | int nr_powerlimit = find_nr_power_limit(rd); | ||
947 | |||
948 | /* always enable clamp such that p-state can go below OS requested | ||
949 | * range. power capping priority over guranteed frequency. | ||
950 | */ | ||
951 | rapl_write_data_raw(rd, PL1_CLAMP, mode); | ||
952 | |||
953 | /* some domains have pl2 */ | ||
954 | if (nr_powerlimit > 1) { | ||
955 | rapl_write_data_raw(rd, PL2_ENABLE, mode); | ||
956 | rapl_write_data_raw(rd, PL2_CLAMP, mode); | ||
957 | } | ||
958 | } | ||
959 | |||
960 | static void set_floor_freq_atom(struct rapl_domain *rd, bool enable) | ||
961 | { | ||
962 | static u32 power_ctrl_orig_val; | ||
963 | u32 mdata; | ||
964 | |||
965 | if (!power_ctrl_orig_val) | ||
966 | iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_PMC_READ, | ||
967 | IOSF_CPU_POWER_BUDGET_CTL, &power_ctrl_orig_val); | ||
968 | mdata = power_ctrl_orig_val; | ||
969 | if (enable) { | ||
970 | mdata &= ~(0x7f << 8); | ||
971 | mdata |= 1 << 8; | ||
972 | } | ||
973 | iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_PMC_WRITE, | ||
974 | IOSF_CPU_POWER_BUDGET_CTL, mdata); | ||
975 | } | ||
976 | |||
977 | static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value, | ||
978 | bool to_raw) | ||
979 | { | ||
980 | u64 f, y; /* fraction and exp. used for time unit */ | ||
981 | |||
982 | /* | ||
983 | * Special processing based on 2^Y*(1+F/4), refer | ||
984 | * to Intel Software Developer's manual Vol.3B: CH 14.9.3. | ||
985 | */ | ||
986 | if (!to_raw) { | ||
987 | f = (value & 0x60) >> 5; | ||
988 | y = value & 0x1f; | ||
989 | value = (1 << y) * (4 + f) * rp->time_unit / 4; | ||
990 | } else { | ||
991 | do_div(value, rp->time_unit); | ||
992 | y = ilog2(value); | ||
993 | f = div64_u64(4 * (value - (1 << y)), 1 << y); | ||
994 | value = (y & 0x1f) | ((f & 0x3) << 5); | ||
995 | } | ||
996 | return value; | ||
997 | } | ||
998 | |||
999 | static u64 rapl_compute_time_window_atom(struct rapl_package *rp, u64 value, | ||
1000 | bool to_raw) | ||
1001 | { | ||
1002 | /* | ||
1003 | * Atom time unit encoding is straight forward val * time_unit, | ||
1004 | * where time_unit is default to 1 sec. Never 0. | ||
1005 | */ | ||
1006 | if (!to_raw) | ||
1007 | return (value) ? value *= rp->time_unit : rp->time_unit; | ||
1008 | else | ||
1009 | value = div64_u64(value, rp->time_unit); | ||
1010 | |||
1011 | return value; | ||
1012 | } | ||
1013 | |||
1014 | static const struct rapl_defaults rapl_defaults_core = { | ||
1015 | .check_unit = rapl_check_unit_core, | ||
1016 | .set_floor_freq = set_floor_freq_default, | ||
1017 | .compute_time_window = rapl_compute_time_window_core, | ||
1018 | }; | ||
1019 | |||
1020 | static const struct rapl_defaults rapl_defaults_atom = { | ||
1021 | .check_unit = rapl_check_unit_atom, | ||
1022 | .set_floor_freq = set_floor_freq_atom, | ||
1023 | .compute_time_window = rapl_compute_time_window_atom, | ||
1024 | }; | ||
1025 | |||
1026 | #define RAPL_CPU(_model, _ops) { \ | ||
1027 | .vendor = X86_VENDOR_INTEL, \ | ||
1028 | .family = 6, \ | ||
1029 | .model = _model, \ | ||
1030 | .driver_data = (kernel_ulong_t)&_ops, \ | ||
1031 | } | ||
1032 | |||
949 | static const struct x86_cpu_id rapl_ids[] = { | 1033 | static const struct x86_cpu_id rapl_ids[] = { |
950 | { X86_VENDOR_INTEL, 6, 0x2a},/* Sandy Bridge */ | 1034 | RAPL_CPU(0x2a, rapl_defaults_core),/* Sandy Bridge */ |
951 | { X86_VENDOR_INTEL, 6, 0x2d},/* Sandy Bridge EP */ | 1035 | RAPL_CPU(0x2d, rapl_defaults_core),/* Sandy Bridge EP */ |
952 | { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */ | 1036 | RAPL_CPU(0x37, rapl_defaults_atom),/* Valleyview */ |
953 | { X86_VENDOR_INTEL, 6, 0x3a},/* Ivy Bridge */ | 1037 | RAPL_CPU(0x3a, rapl_defaults_core),/* Ivy Bridge */ |
954 | { X86_VENDOR_INTEL, 6, 0x3c},/* Haswell */ | 1038 | RAPL_CPU(0x3c, rapl_defaults_core),/* Haswell */ |
955 | { X86_VENDOR_INTEL, 6, 0x3d},/* Broadwell */ | 1039 | RAPL_CPU(0x3d, rapl_defaults_core),/* Broadwell */ |
956 | { X86_VENDOR_INTEL, 6, 0x3f},/* Haswell */ | 1040 | RAPL_CPU(0x3f, rapl_defaults_core),/* Haswell */ |
957 | { X86_VENDOR_INTEL, 6, 0x45},/* Haswell ULT */ | 1041 | RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */ |
958 | /* TODO: Add more CPU IDs after testing */ | 1042 | RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */ |
1043 | RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */ | ||
1044 | RAPL_CPU(0x5A, rapl_defaults_atom),/* Annidale */ | ||
959 | {} | 1045 | {} |
960 | }; | 1046 | }; |
961 | MODULE_DEVICE_TABLE(x86cpu, rapl_ids); | 1047 | MODULE_DEVICE_TABLE(x86cpu, rapl_ids); |
@@ -1241,7 +1327,7 @@ static int rapl_detect_topology(void) | |||
1241 | 1327 | ||
1242 | /* check if the package contains valid domains */ | 1328 | /* check if the package contains valid domains */ |
1243 | if (rapl_detect_domains(new_package, i) || | 1329 | if (rapl_detect_domains(new_package, i) || |
1244 | rapl_check_unit(new_package, i)) { | 1330 | rapl_defaults->check_unit(new_package, i)) { |
1245 | kfree(new_package->domains); | 1331 | kfree(new_package->domains); |
1246 | kfree(new_package); | 1332 | kfree(new_package); |
1247 | /* free up the packages already initialized */ | 1333 | /* free up the packages already initialized */ |
@@ -1296,7 +1382,7 @@ static int rapl_add_package(int cpu) | |||
1296 | rp->nr_cpus = 1; | 1382 | rp->nr_cpus = 1; |
1297 | /* check if the package contains valid domains */ | 1383 | /* check if the package contains valid domains */ |
1298 | if (rapl_detect_domains(rp, cpu) || | 1384 | if (rapl_detect_domains(rp, cpu) || |
1299 | rapl_check_unit(rp, cpu)) { | 1385 | rapl_defaults->check_unit(rp, cpu)) { |
1300 | ret = -ENODEV; | 1386 | ret = -ENODEV; |
1301 | goto err_free_package; | 1387 | goto err_free_package; |
1302 | } | 1388 | } |
@@ -1358,14 +1444,18 @@ static struct notifier_block rapl_cpu_notifier = { | |||
1358 | static int __init rapl_init(void) | 1444 | static int __init rapl_init(void) |
1359 | { | 1445 | { |
1360 | int ret = 0; | 1446 | int ret = 0; |
1447 | const struct x86_cpu_id *id; | ||
1361 | 1448 | ||
1362 | if (!x86_match_cpu(rapl_ids)) { | 1449 | id = x86_match_cpu(rapl_ids); |
1450 | if (!id) { | ||
1363 | pr_err("driver does not support CPU family %d model %d\n", | 1451 | pr_err("driver does not support CPU family %d model %d\n", |
1364 | boot_cpu_data.x86, boot_cpu_data.x86_model); | 1452 | boot_cpu_data.x86, boot_cpu_data.x86_model); |
1365 | 1453 | ||
1366 | return -ENODEV; | 1454 | return -ENODEV; |
1367 | } | 1455 | } |
1368 | 1456 | ||
1457 | rapl_defaults = (struct rapl_defaults *)id->driver_data; | ||
1458 | |||
1369 | cpu_notifier_register_begin(); | 1459 | cpu_notifier_register_begin(); |
1370 | 1460 | ||
1371 | /* prevent CPU hotplug during detection */ | 1461 | /* prevent CPU hotplug during detection */ |
diff --git a/include/linux/pm_clock.h b/include/linux/pm_clock.h index 8348866e7b05..0b0039634410 100644 --- a/include/linux/pm_clock.h +++ b/include/linux/pm_clock.h | |||
@@ -18,6 +18,8 @@ struct pm_clk_notifier_block { | |||
18 | char *con_ids[]; | 18 | char *con_ids[]; |
19 | }; | 19 | }; |
20 | 20 | ||
21 | struct clk; | ||
22 | |||
21 | #ifdef CONFIG_PM_CLK | 23 | #ifdef CONFIG_PM_CLK |
22 | static inline bool pm_clk_no_clocks(struct device *dev) | 24 | static inline bool pm_clk_no_clocks(struct device *dev) |
23 | { | 25 | { |
@@ -29,6 +31,7 @@ extern void pm_clk_init(struct device *dev); | |||
29 | extern int pm_clk_create(struct device *dev); | 31 | extern int pm_clk_create(struct device *dev); |
30 | extern void pm_clk_destroy(struct device *dev); | 32 | extern void pm_clk_destroy(struct device *dev); |
31 | extern int pm_clk_add(struct device *dev, const char *con_id); | 33 | extern int pm_clk_add(struct device *dev, const char *con_id); |
34 | extern int pm_clk_add_clk(struct device *dev, struct clk *clk); | ||
32 | extern void pm_clk_remove(struct device *dev, const char *con_id); | 35 | extern void pm_clk_remove(struct device *dev, const char *con_id); |
33 | extern int pm_clk_suspend(struct device *dev); | 36 | extern int pm_clk_suspend(struct device *dev); |
34 | extern int pm_clk_resume(struct device *dev); | 37 | extern int pm_clk_resume(struct device *dev); |
@@ -51,6 +54,11 @@ static inline int pm_clk_add(struct device *dev, const char *con_id) | |||
51 | { | 54 | { |
52 | return -EINVAL; | 55 | return -EINVAL; |
53 | } | 56 | } |
57 | |||
58 | static inline int pm_clk_add_clk(struct device *dev, struct clk *clk) | ||
59 | { | ||
60 | return -EINVAL; | ||
61 | } | ||
54 | static inline void pm_clk_remove(struct device *dev, const char *con_id) | 62 | static inline void pm_clk_remove(struct device *dev, const char *con_id) |
55 | { | 63 | { |
56 | } | 64 | } |
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; | |||
21 | struct device; | 21 | struct device; |
22 | 22 | ||
23 | enum dev_pm_opp_event { | 23 | enum 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 | ||
45 | int dev_pm_opp_add(struct device *dev, unsigned long freq, | 45 | int dev_pm_opp_add(struct device *dev, unsigned long freq, |
46 | unsigned long u_volt); | 46 | unsigned long u_volt); |
47 | void dev_pm_opp_remove(struct device *dev, unsigned long freq); | ||
47 | 48 | ||
48 | int dev_pm_opp_enable(struct device *dev, unsigned long freq); | 49 | int 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 | ||
94 | static inline void dev_pm_opp_remove(struct device *dev, unsigned long freq) | ||
95 | { | ||
96 | } | ||
97 | |||
93 | static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq) | 98 | static 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) |
111 | int of_init_opp_table(struct device *dev); | 116 | int of_init_opp_table(struct device *dev); |
117 | void of_free_opp_table(struct device *dev); | ||
112 | #else | 118 | #else |
113 | static inline int of_init_opp_table(struct device *dev) | 119 | static inline int of_init_opp_table(struct device *dev) |
114 | { | 120 | { |
115 | return -EINVAL; | 121 | return -EINVAL; |
116 | } | 122 | } |
123 | |||
124 | static 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__ */ |
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index bbef57f5bdfd..1eb7da7bc8e8 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig | |||
@@ -308,4 +308,3 @@ config PM_GENERIC_DOMAINS_OF | |||
308 | 308 | ||
309 | config CPU_PM | 309 | config CPU_PM |
310 | bool | 310 | bool |
311 | depends on SUSPEND || CPU_IDLE | ||