十牛校园是乱收费吗:runtime_suspend runtime_resume

来源:百度文库 编辑:中财网 时间:2024/04/28 22:20:39

Run-time PM. 

每个device或者bus都会向run-time PM core注册3个callback
struct dev_pm_ops {...int (*runtime_suspend)(struct device *dev);int (*runtime_resume)(struct device *dev);int (*runtime_idle)(struct device *dev);...};
每个device或者bus都会有2个计数器,一个是device的usage counter,一个是device的active状态的children个数。当这个device的两个counter都减少为0的时候。run-time PM core就会去调用runtime_idle函数,但是这里的idle函数可不是当前device的idle函数。代码如下:if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {spin_unlock_irq(&dev->power.lock);
dev->bus->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);} else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {spin_unlock_irq(&dev->power.lock);
dev->type->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);} else if (dev->class && dev->class->pm   && dev->class->pm->runtime_idle) {spin_unlock_irq(&dev->power.lock);
dev->class->pm->runtime_idle(dev);
spin_lock_irq(&dev->power.lock);}按照dev->bus, dev->type, dev->class的顺序去调用。大家会问了,那runtime_suspend函数什么时候调用?runtime_suspend函数不会被RPM core主动去调用,一般情况下是在bus,或者class的idle函数里去调用。例如:static int xxx_runtime_idle(struct device *dev){return pm_schedule_suspend(dev, 50);}
pm_schedule_suspend函数会去调用device里的suspend函数,调用顺序代码如下:if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {spin_unlock_irq(&dev->power.lock);
retval = dev->bus->pm->runtime_suspend(dev);
spin_lock_irq(&dev->power.lock);dev->power.runtime_error = retval;} else if (dev->type && dev->type->pm   && dev->type->pm->runtime_suspend) {spin_unlock_irq(&dev->power.lock);
retval = dev->type->pm->runtime_suspend(dev);
spin_lock_irq(&dev->power.lock);dev->power.runtime_error = retval;} else if (dev->class && dev->class->pm   && dev->class->pm->runtime_suspend) {spin_unlock_irq(&dev->power.lock);
retval = dev->class->pm->runtime_suspend(dev);
spin_lock_irq(&dev->power.lock);dev->power.runtime_error = retval;} else {retval = -ENOSYS;}发现了吧,和idle顺序是一模一样哒。当然肯定也会有不一样了,否则runtime_suspend函数没存在意义了。在跑完此dev的bus or type or class的suspend函数以后。紧接着会做一个巨艰巨的任务,就是if (parent && !parent->power.ignore_children) {spin_unlock_irq(&dev->power.lock);
pm_request_idle(parent);
spin_lock_irq(&dev->power.lock);}会去调用当前这个device的parent device的idle函数!!!之后会去递归的往上层调用。为啥会这么做呢???其实RPM机制总体来说就是管理总线结构和主次设备结构的电源。假如一个bus上有2个device。这个bus首先会有一个bus_type,其次还会有一个代表bus的device(谁说bus不是device了!)首先命名以下,bus device叫做Bdev, 两个bus上的子device是dev1, dev2。dev1,dev2是Bdev的子设备,也就是说dev1,dev2的parent是Bdev。其中bus_type里会有一套runtime_pm的三个callback,Bdev自身还有另一套runtime_pm的三个callback。当dev1的两个counter都为零了,就会调用bus_type里的runtime_idle,一般情况下这个idle会调用pm_runtime_suspend,仅按照上面的介绍,就会调用这个bus_type里的runtime_suspend call back。之后是不是就该是最重要的那一步了?pm_request_idle(parent);pm_request_idle里的一系列操作会首先判断parent的两个counter是否为零了,因为dev2还活着呢,所以条件不满足,返回!当dev2也来这么一套之后,再调用pm_request_idle(parent);的时候,Bdev里的runtime_idle就能跑啦。总结一下,bus_type的runtime_系列回调函数是用来处理bus上的device函数的。而bus自己的device的函数是用来处理自己的。因为体系结构的因素,bus套bus的情况,最后就会形成一个device大树。runtime这套机制就可以从根到树顶都能管理得到。比如:I2C device挂在I2C bus上,I2C bus controller是PCI的一个设备,因为挂在PCI上。这个PCI bus一般还是在南桥上,然后再通过南桥在跑到北桥PCI上。。。。是不是块疯了。。。。但是有这么个递归电源管理。一切搞定。
说完了睡流程了。还有醒流程。当device调用完suspend函数后,这个device就处于了一个suspended状态。当某个device被唤醒后,就会调用pm_runtime_get_sync类似的函数。这个函数做了啥捏?通过上述的睡过程,有点脑子的人就能想出醒流程,反着来呗!!!必须从大树顶往下跑,才能最后让根伸出来。代码如下:
if (!parent && dev->parent) {/** Increment the parent's resume counter and resume it if* necessary.*/parent = dev->parent;spin_unlock(&dev->power.lock);
pm_runtime_get_noresume(parent);
spin_lock(&parent->power.lock);/** We can resume if the parent's run-time PM is disabled or it* is set to ignore children.*/if (!parent->power.disable_depth   && !parent->power.ignore_children) {__pm_runtime_resume(parent, false);if (parent->power.runtime_status != RPM_ACTIVE)retval = -EBUSY;}spin_unlock(&parent->power.lock);
spin_lock(&dev->power.lock);if (retval)goto out;goto repeat;}首先跑这个device的parent的resume函数。之后if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {spin_unlock_irq(&dev->power.lock);
retval = dev->bus->pm->runtime_resume(dev);
spin_lock_irq(&dev->power.lock);dev->power.runtime_error = retval;} else if (dev->type && dev->type->pm   && dev->type->pm->runtime_resume) {spin_unlock_irq(&dev->power.lock);
retval = dev->type->pm->runtime_resume(dev);
spin_lock_irq(&dev->power.lock);dev->power.runtime_error = retval;} else if (dev->class && dev->class->pm   && dev->class->pm->runtime_resume) {spin_unlock_irq(&dev->power.lock);
retval = dev->class->pm->runtime_resume(dev);
spin_lock_irq(&dev->power.lock);dev->power.runtime_error = retval;} else {retval = -ENOSYS;}跑的是bus的resume函数。通过这个函数进行递归,直到递归到树顶后,树顶的resume就开始run了,run完一个往下面继续传,直到我们的这一连串device的resume函数都跑完,我们的device就算醒了。RPM常用接口如下: void pm_runtime_init(struct device *dev);    - initialize the device run-time PM fields in 'struct dev_pm_info'
  void pm_runtime_remove(struct device *dev);    - make sure that the run-time PM of the device will be disabled after      removing the device from device hierarchy
  int pm_runtime_idle(struct device *dev);    - execute the subsystem-level idle callback for the device; returns 0 on      success or error code on failure, where -EINPROGRESS means that      ->runtime_idle() is already being executed
  int pm_runtime_suspend(struct device *dev);    - execute the subsystem-level suspend callback for the device; returns 0 on      success, 1 if the device's run-time PM status was already 'suspended', or      error code on failure, where -EAGAIN or -EBUSY means it is safe to attempt      to suspend the device again in future
  int pm_runtime_resume(struct device *dev);    - execute the subsystem-level resume callback for the device; returns 0 on      success, 1 if the device's run-time PM status was already 'active' or      error code on failure, where -EAGAIN means it may be safe to attempt to      resume the device again in future, but 'power.runtime_error' should be      checked additionally
  int pm_request_idle(struct device *dev);    - submit a request to execute the subsystem-level idle callback for the      device (the request is represented by a work item in pm_wq); returns 0 on      success or error code if the request has not been queued up
  int pm_schedule_suspend(struct device *dev, unsigned int delay);    - schedule the execution of the subsystem-level suspend callback for the      device in future, where 'delay' is the time to wait before queuing up a      suspend work item in pm_wq, in milliseconds (if 'delay' is zero, the work      item is queued up immediately); returns 0 on success, 1 if the device's PM      run-time status was already 'suspended', or error code if the request      hasn't been scheduled (or queued up if 'delay' is 0); if the execution of      ->runtime_suspend() is already scheduled and not yet expired, the new      value of 'delay' will be used as the time to wait
  int pm_request_resume(struct device *dev);    - submit a request to execute the subsystem-level resume callback for the      device (the request is represented by a work item in pm_wq); returns 0 on      success, 1 if the device's run-time PM status was already 'active', or      error code if the request hasn't been queued up
  void pm_runtime_get_noresume(struct device *dev);    - increment the device's usage counter
  int pm_runtime_get(struct device *dev);    - increment the device's usage counter, run pm_request_resume(dev) and      return its result
  int pm_runtime_get_sync(struct device *dev);    - increment the device's usage counter, run pm_runtime_resume(dev) and      return its result
  void pm_runtime_put_noidle(struct device *dev);    - decrement the device's usage counter
  int pm_runtime_put(struct device *dev);    - decrement the device's usage counter, run pm_request_idle(dev) and return      its result
  int pm_runtime_put_sync(struct device *dev);    - decrement the device's usage counter, run pm_runtime_idle(dev) and return      its result
  void pm_runtime_enable(struct device *dev);    - enable the run-time PM helper functions to run the device bus type's      run-time PM callbacks described in Section 2
  int pm_runtime_disable(struct device *dev);    - prevent the run-time PM helper functions from running subsystem-level      run-time PM callbacks for the device, make sure that all of the pending      run-time PM operations on the device are either completed or canceled;      returns 1 if there was a resume request pending and it was necessary to      execute the subsystem-level resume callback for the device to satisfy that      request, otherwise 0 is returned
  void pm_suspend_ignore_children(struct device *dev, bool enable);    - set/unset the power.ignore_children flag of the device
  int pm_runtime_set_active(struct device *dev);    - clear the device's 'power.runtime_error' flag, set the device's run-time      PM status to 'active' and update its parent's counter of 'active'      children as appropriate (it is only valid to use this function if      'power.runtime_error' is set or 'power.disable_depth' is greater than      zero); it will fail and return error code if the device has a parent      which is not active and the 'power.ignore_children' flag of which is unset
  void pm_runtime_set_suspended(struct device *dev);    - clear the device's 'power.runtime_error' flag, set the device's run-time      PM status to 'suspended' and update its parent's counter of 'active'      children as appropriate (it is only valid to use this function if      'power.runtime_error' is set or 'power.disable_depth' is greater than      zero)
  bool pm_runtime_suspended(struct device *dev);    - return true if the device's runtime PM status is 'suspended', or false      otherwise
  void pm_runtime_allow(struct device *dev);    - set the power.runtime_auto flag for the device and decrease its usage      counter (used by the /sys/devices/.../power/control interface to      effectively allow the device to be power managed at run time)
  void pm_runtime_forbid(struct device *dev);    - unset the power.runtime_auto flag for the device and increase its usage      counter (used by the /sys/devices/.../power/control interface to      effectively prevent the device from being power managed at run time)可以中断里跑的接口:pm_request_idle()pm_schedule_suspend()pm_request_resume()pm_runtime_get_noresume()pm_runtime_get()pm_runtime_put_noidle()pm_runtime_put()pm_suspend_ignore_children()pm_runtime_set_active()pm_runtime_set_suspended()pm_runtime_enable()