1/* 2 * This module exposes the interface to kernel space for specifying 3 * QoS dependencies. It provides infrastructure for registration of: 4 * 5 * Dependents on a QoS value : register requests 6 * Watchers of QoS value : get notified when target QoS value changes 7 * 8 * This QoS design is best effort based. Dependents register their QoS needs. 9 * Watchers register to keep track of the current QoS needs of the system. 10 * 11 * There are 3 basic classes of QoS parameter: latency, timeout, throughput 12 * each have defined units: 13 * latency: usec 14 * timeout: usec <-- currently not used. 15 * throughput: kbs (kilo byte / sec) 16 * 17 * There are lists of pm_qos_objects each one wrapping requests, notifiers 18 * 19 * User mode requests on a QOS parameter register themselves to the 20 * subsystem by opening the device node /dev/... and writing there request to 21 * the node. As long as the process holds a file handle open to the node the 22 * client continues to be accounted for. Upon file release the usermode 23 * request is removed and a new qos target is computed. This way when the 24 * request that the application has is cleaned up when closes the file 25 * pointer or exits the pm_qos_object will get an opportunity to clean up. 26 * 27 * Mark Gross <mgross@linux.intel.com> 28 */ 29 30/*#define DEBUG*/ 31 32#include <linux/pm_qos_params.h> 33#include <linux/sched.h> 34#include <linux/spinlock.h> 35#include <linux/slab.h> 36#include <linux/time.h> 37#include <linux/fs.h> 38#include <linux/device.h> 39#include <linux/miscdevice.h> 40#include <linux/string.h> 41#include <linux/platform_device.h> 42#include <linux/init.h> 43 44#include <linux/uaccess.h> 45 46/* 47 * locking rule: all changes to requests or notifiers lists 48 * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock 49 * held, taken with _irqsave. One lock to rule them all 50 */ 51enum pm_qos_type { 52 PM_QOS_MAX, /* return the largest value */ 53 PM_QOS_MIN /* return the smallest value */ 54}; 55 56struct pm_qos_object { 57 struct plist_head requests; 58 struct blocking_notifier_head *notifiers; 59 struct miscdevice pm_qos_power_miscdev; 60 char *name; 61 s32 default_value; 62 enum pm_qos_type type; 63}; 64 65static DEFINE_SPINLOCK(pm_qos_lock); 66 67static struct pm_qos_object null_pm_qos; 68static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier); 69static struct pm_qos_object cpu_dma_pm_qos = { 70 .requests = PLIST_HEAD_INIT(cpu_dma_pm_qos.requests, pm_qos_lock), 71 .notifiers = &cpu_dma_lat_notifier, 72 .name = "cpu_dma_latency", 73 .default_value = 2000 * USEC_PER_SEC, 74 .type = PM_QOS_MIN, 75}; 76 77static BLOCKING_NOTIFIER_HEAD(network_lat_notifier); 78static struct pm_qos_object network_lat_pm_qos = { 79 .requests = PLIST_HEAD_INIT(network_lat_pm_qos.requests, pm_qos_lock), 80 .notifiers = &network_lat_notifier, 81 .name = "network_latency", 82 .default_value = 2000 * USEC_PER_SEC, 83 .type = PM_QOS_MIN 84}; 85 86 87static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier); 88static struct pm_qos_object network_throughput_pm_qos = { 89 .requests = PLIST_HEAD_INIT(network_throughput_pm_qos.requests, pm_qos_lock), 90 .notifiers = &network_throughput_notifier, 91 .name = "network_throughput", 92 .default_value = 0, 93 .type = PM_QOS_MAX, 94}; 95 96 97static struct pm_qos_object *pm_qos_array[] = { 98 &null_pm_qos, 99 &cpu_dma_pm_qos, 100 &network_lat_pm_qos, 101 &network_throughput_pm_qos 102}; 103 104static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, 105 size_t count, loff_t *f_pos); 106static int pm_qos_power_open(struct inode *inode, struct file *filp); 107static int pm_qos_power_release(struct inode *inode, struct file *filp); 108 109static const struct file_operations pm_qos_power_fops = { 110 .write = pm_qos_power_write, 111 .open = pm_qos_power_open, 112 .release = pm_qos_power_release, 113}; 114 115/* unlocked internal variant */ 116static inline int pm_qos_get_value(struct pm_qos_object *o) 117{ 118 if (plist_head_empty(&o->requests)) 119 return o->default_value; 120 121 switch (o->type) { 122 case PM_QOS_MIN: 123 return plist_first(&o->requests)->prio; 124 125 case PM_QOS_MAX: 126 return plist_last(&o->requests)->prio; 127 128 default: 129 /* runtime check for not using enum */ 130 BUG(); 131 } 132} 133 134static void update_target(struct pm_qos_object *o, struct plist_node *node, 135 int del, int value) 136{ 137 unsigned long flags; 138 int prev_value, curr_value; 139 140 spin_lock_irqsave(&pm_qos_lock, flags); 141 prev_value = pm_qos_get_value(o); 142 /* PM_QOS_DEFAULT_VALUE is a signal that the value is unchanged */ 143 if (value != PM_QOS_DEFAULT_VALUE) { 144 /* 145 * to change the list, we atomically remove, reinit 146 * with new value and add, then see if the extremal 147 * changed 148 */ 149 plist_del(node, &o->requests); 150 plist_node_init(node, value); 151 plist_add(node, &o->requests); 152 } else if (del) { 153 plist_del(node, &o->requests); 154 } else { 155 plist_add(node, &o->requests); 156 } 157 curr_value = pm_qos_get_value(o); 158 spin_unlock_irqrestore(&pm_qos_lock, flags); 159 160 if (prev_value != curr_value) 161 blocking_notifier_call_chain(o->notifiers, 162 (unsigned long)curr_value, 163 NULL); 164} 165 166static int register_pm_qos_misc(struct pm_qos_object *qos) 167{ 168 qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR; 169 qos->pm_qos_power_miscdev.name = qos->name; 170 qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops; 171 172 return misc_register(&qos->pm_qos_power_miscdev); 173} 174 175static int find_pm_qos_object_by_minor(int minor) 176{ 177 int pm_qos_class; 178 179 for (pm_qos_class = 0; 180 pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) { 181 if (minor == 182 pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor) 183 return pm_qos_class; 184 } 185 return -1; 186} 187 188/** 189 * pm_qos_request - returns current system wide qos expectation 190 * @pm_qos_class: identification of which qos value is requested 191 * 192 * This function returns the current target value in an atomic manner. 193 */ 194int pm_qos_request(int pm_qos_class) 195{ 196 unsigned long flags; 197 int value; 198 199 spin_lock_irqsave(&pm_qos_lock, flags); 200 value = pm_qos_get_value(pm_qos_array[pm_qos_class]); 201 spin_unlock_irqrestore(&pm_qos_lock, flags); 202 203 return value; 204} 205EXPORT_SYMBOL_GPL(pm_qos_request); 206 207int pm_qos_request_active(struct pm_qos_request_list *req) 208{ 209 return req->pm_qos_class != 0; 210} 211EXPORT_SYMBOL_GPL(pm_qos_request_active); 212 213/** 214 * pm_qos_add_request - inserts new qos request into the list 215 * @dep: pointer to a preallocated handle 216 * @pm_qos_class: identifies which list of qos request to use 217 * @value: defines the qos request 218 * 219 * This function inserts a new entry in the pm_qos_class list of requested qos 220 * performance characteristics. It recomputes the aggregate QoS expectations 221 * for the pm_qos_class of parameters and initializes the pm_qos_request_list 222 * handle. Caller needs to save this handle for later use in updates and 223 * removal. 224 */ 225 226void pm_qos_add_request(struct pm_qos_request_list *dep, 227 int pm_qos_class, s32 value) 228{ 229 struct pm_qos_object *o = pm_qos_array[pm_qos_class]; 230 int new_value; 231 232 if (pm_qos_request_active(dep)) { 233 WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n"); 234 return; 235 } 236 if (value == PM_QOS_DEFAULT_VALUE) 237 new_value = o->default_value; 238 else 239 new_value = value; 240 plist_node_init(&dep->list, new_value); 241 dep->pm_qos_class = pm_qos_class; 242 update_target(o, &dep->list, 0, PM_QOS_DEFAULT_VALUE); 243} 244EXPORT_SYMBOL_GPL(pm_qos_add_request); 245 246/** 247 * pm_qos_update_request - modifies an existing qos request 248 * @pm_qos_req : handle to list element holding a pm_qos request to use 249 * @value: defines the qos request 250 * 251 * Updates an existing qos request for the pm_qos_class of parameters along 252 * with updating the target pm_qos_class value. 253 * 254 * Attempts are made to make this code callable on hot code paths. 255 */ 256void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req, 257 s32 new_value) 258{ 259 s32 temp; 260 struct pm_qos_object *o; 261 262 if (!pm_qos_req) /*guard against callers passing in null */ 263 return; 264 265 if (!pm_qos_request_active(pm_qos_req)) { 266 WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n"); 267 return; 268 } 269 270 o = pm_qos_array[pm_qos_req->pm_qos_class]; 271 272 if (new_value == PM_QOS_DEFAULT_VALUE) 273 temp = o->default_value; 274 else 275 temp = new_value; 276 277 if (temp != pm_qos_req->list.prio) 278 update_target(o, &pm_qos_req->list, 0, temp); 279} 280EXPORT_SYMBOL_GPL(pm_qos_update_request); 281 282/** 283 * pm_qos_remove_request - modifies an existing qos request 284 * @pm_qos_req: handle to request list element 285 * 286 * Will remove pm qos request from the list of requests and 287 * recompute the current target value for the pm_qos_class. Call this 288 * on slow code paths. 289 */ 290void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req) 291{ 292 struct pm_qos_object *o; 293 294 if (pm_qos_req == NULL) 295 return; 296 /* silent return to keep pcm code cleaner */ 297 298 if (!pm_qos_request_active(pm_qos_req)) { 299 WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n"); 300 return; 301 } 302 303 o = pm_qos_array[pm_qos_req->pm_qos_class]; 304 update_target(o, &pm_qos_req->list, 1, PM_QOS_DEFAULT_VALUE); 305 memset(pm_qos_req, 0, sizeof(*pm_qos_req)); 306} 307EXPORT_SYMBOL_GPL(pm_qos_remove_request); 308 309/** 310 * pm_qos_add_notifier - sets notification entry for changes to target value 311 * @pm_qos_class: identifies which qos target changes should be notified. 312 * @notifier: notifier block managed by caller. 313 * 314 * will register the notifier into a notification chain that gets called 315 * upon changes to the pm_qos_class target value. 316 */ 317int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier) 318{ 319 int retval; 320 321 retval = blocking_notifier_chain_register( 322 pm_qos_array[pm_qos_class]->notifiers, notifier); 323 324 return retval; 325} 326EXPORT_SYMBOL_GPL(pm_qos_add_notifier); 327 328/** 329 * pm_qos_remove_notifier - deletes notification entry from chain. 330 * @pm_qos_class: identifies which qos target changes are notified. 331 * @notifier: notifier block to be removed. 332 * 333 * will remove the notifier from the notification chain that gets called 334 * upon changes to the pm_qos_class target value. 335 */ 336int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier) 337{ 338 int retval; 339 340 retval = blocking_notifier_chain_unregister( 341 pm_qos_array[pm_qos_class]->notifiers, notifier); 342 343 return retval; 344} 345EXPORT_SYMBOL_GPL(pm_qos_remove_notifier); 346 347static int pm_qos_power_open(struct inode *inode, struct file *filp) 348{ 349 long pm_qos_class; 350 351 pm_qos_class = find_pm_qos_object_by_minor(iminor(inode)); 352 if (pm_qos_class >= 0) { 353 struct pm_qos_request_list *req = kzalloc(sizeof(*req), GFP_KERNEL); 354 if (!req) 355 return -ENOMEM; 356 357 pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE); 358 filp->private_data = req; 359 360 if (filp->private_data) 361 return 0; 362 } 363 return -EPERM; 364} 365 366static int pm_qos_power_release(struct inode *inode, struct file *filp) 367{ 368 struct pm_qos_request_list *req; 369 370 req = filp->private_data; 371 pm_qos_remove_request(req); 372 kfree(req); 373 374 return 0; 375} 376 377 378static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, 379 size_t count, loff_t *f_pos) 380{ 381 s32 value; 382 int x; 383 char ascii_value[11]; 384 struct pm_qos_request_list *pm_qos_req; 385 386 if (count == sizeof(s32)) { 387 if (copy_from_user(&value, buf, sizeof(s32))) 388 return -EFAULT; 389 } else if (count == 11) { /* len('0x12345678/0') */ 390 if (copy_from_user(ascii_value, buf, 11)) 391 return -EFAULT; 392 if (strlen(ascii_value) != 10) 393 return -EINVAL; 394 x = sscanf(ascii_value, "%x", &value); 395 if (x != 1) 396 return -EINVAL; 397 pr_debug("%s, %d, 0x%x\n", ascii_value, x, value); 398 } else 399 return -EINVAL; 400 401 pm_qos_req = (struct pm_qos_request_list *)filp->private_data; 402 pm_qos_update_request(pm_qos_req, value); 403 404 return count; 405} 406 407 408static int __init pm_qos_power_init(void) 409{ 410 int ret = 0; 411 412 ret = register_pm_qos_misc(&cpu_dma_pm_qos); 413 if (ret < 0) { 414 printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n"); 415 return ret; 416 } 417 ret = register_pm_qos_misc(&network_lat_pm_qos); 418 if (ret < 0) { 419 printk(KERN_ERR "pm_qos_param: network_latency setup failed\n"); 420 return ret; 421 } 422 ret = register_pm_qos_misc(&network_throughput_pm_qos); 423 if (ret < 0) 424 printk(KERN_ERR 425 "pm_qos_param: network_throughput setup failed\n"); 426 427 return ret; 428} 429 430late_initcall(pm_qos_power_init); 431