1 /* 2 * driver.c - driver support 3 * 4 * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> 5 * Shaohua Li <shaohua.li@intel.com> 6 * Adam Belay <abelay@novell.com> 7 * 8 * This code is licenced under the GPL. 9 */ 10 11 #include <linux/mutex.h> 12 #include <linux/module.h> 13 #include <linux/cpuidle.h> 14 15 #include "cpuidle.h" 16 17 static struct cpuidle_driver *cpuidle_curr_driver; 18 DEFINE_SPINLOCK(cpuidle_driver_lock); 19 int cpuidle_driver_refcount; 20 21 static void __cpuidle_register_driver(struct cpuidle_driver *drv) 22 { 23 int i; 24 /* 25 * cpuidle driver should set the drv->power_specified bit 26 * before registering if the driver provides 27 * power_usage numbers. 28 * 29 * If power_specified is not set, 30 * we fill in power_usage with decreasing values as the 31 * cpuidle code has an implicit assumption that state Cn 32 * uses less power than C(n-1). 33 * 34 * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned 35 * an power value of -1. So we use -2, -3, etc, for other 36 * c-states. 37 */ 38 if (!drv->power_specified) { 39 for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) 40 drv->states[i].power_usage = -1 - i; 41 } 42 } 43 44 /** 45 * cpuidle_register_driver - registers a driver 46 * @drv: the driver 47 */ 48 int cpuidle_register_driver(struct cpuidle_driver *drv) 49 { 50 if (!drv || !drv->state_count) 51 return -EINVAL; 52 53 if (cpuidle_disabled()) 54 return -ENODEV; 55 56 spin_lock(&cpuidle_driver_lock); 57 if (cpuidle_curr_driver) { 58 spin_unlock(&cpuidle_driver_lock); 59 return -EBUSY; 60 } 61 __cpuidle_register_driver(drv); 62 cpuidle_curr_driver = drv; 63 spin_unlock(&cpuidle_driver_lock); 64 65 return 0; 66 } 67 EXPORT_SYMBOL_GPL(cpuidle_register_driver); 68 69 /** 70 * cpuidle_get_driver - return the current driver 71 */ 72 struct cpuidle_driver *cpuidle_get_driver(void) 73 { 74 return cpuidle_curr_driver; 75 } 76 EXPORT_SYMBOL_GPL(cpuidle_get_driver); 77 78 /** 79 * cpuidle_unregister_driver - unregisters a driver 80 * @drv: the driver 81 */ 82 void cpuidle_unregister_driver(struct cpuidle_driver *drv) 83 { 84 if (drv != cpuidle_curr_driver) { 85 WARN(1, "invalid cpuidle_unregister_driver(%s)\n", 86 drv->name); 87 return; 88 } 89 90 spin_lock(&cpuidle_driver_lock); 91 92 if (!WARN_ON(cpuidle_driver_refcount > 0)) 93 cpuidle_curr_driver = NULL; 94 95 spin_unlock(&cpuidle_driver_lock); 96 } 97 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); 98 99 struct cpuidle_driver *cpuidle_driver_ref(void) 100 { 101 struct cpuidle_driver *drv; 102 103 spin_lock(&cpuidle_driver_lock); 104 105 drv = cpuidle_curr_driver; 106 cpuidle_driver_refcount++; 107 108 spin_unlock(&cpuidle_driver_lock); 109 return drv; 110 } 111 112 void cpuidle_driver_unref(void) 113 { 114 spin_lock(&cpuidle_driver_lock); 115 116 if (!WARN_ON(cpuidle_driver_refcount <= 0)) 117 cpuidle_driver_refcount--; 118 119 spin_unlock(&cpuidle_driver_lock); 120 } 121