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 /** 46 * cpuidle_register_driver - registers a driver 47 * @drv: the driver 48 */ 49 int cpuidle_register_driver(struct cpuidle_driver *drv) 50 { 51 if (!drv || !drv->state_count) 52 return -EINVAL; 53 54 if (cpuidle_disabled()) 55 return -ENODEV; 56 57 spin_lock(&cpuidle_driver_lock); 58 if (cpuidle_curr_driver) { 59 spin_unlock(&cpuidle_driver_lock); 60 return -EBUSY; 61 } 62 __cpuidle_register_driver(drv); 63 cpuidle_curr_driver = drv; 64 spin_unlock(&cpuidle_driver_lock); 65 66 return 0; 67 } 68 69 EXPORT_SYMBOL_GPL(cpuidle_register_driver); 70 71 /** 72 * cpuidle_get_driver - return the current driver 73 */ 74 struct cpuidle_driver *cpuidle_get_driver(void) 75 { 76 return cpuidle_curr_driver; 77 } 78 EXPORT_SYMBOL_GPL(cpuidle_get_driver); 79 80 /** 81 * cpuidle_unregister_driver - unregisters a driver 82 * @drv: the driver 83 */ 84 void cpuidle_unregister_driver(struct cpuidle_driver *drv) 85 { 86 if (drv != cpuidle_curr_driver) { 87 WARN(1, "invalid cpuidle_unregister_driver(%s)\n", 88 drv->name); 89 return; 90 } 91 92 spin_lock(&cpuidle_driver_lock); 93 94 if (!WARN_ON(cpuidle_driver_refcount > 0)) 95 cpuidle_curr_driver = NULL; 96 97 spin_unlock(&cpuidle_driver_lock); 98 } 99 100 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); 101 102 struct cpuidle_driver *cpuidle_driver_ref(void) 103 { 104 struct cpuidle_driver *drv; 105 106 spin_lock(&cpuidle_driver_lock); 107 108 drv = cpuidle_curr_driver; 109 cpuidle_driver_refcount++; 110 111 spin_unlock(&cpuidle_driver_lock); 112 return drv; 113 } 114 115 void cpuidle_driver_unref(void) 116 { 117 spin_lock(&cpuidle_driver_lock); 118 119 if (!WARN_ON(cpuidle_driver_refcount <= 0)) 120 cpuidle_driver_refcount--; 121 122 spin_unlock(&cpuidle_driver_lock); 123 } 124