cpufreq.c 源码分析 //待修改

AUTHOR: Joseph Yang (杨红刚) <ganggexiongqi@gmail.com>
CONTENT: cpufreq.c 源码分析
NOTE: linux-3.0
LAST MODIFIED:09-19-2011
-----------------------------------------------------------------------------------------------------------
Distributed and Embedded System Lab (分布式嵌入式系统实验室,兰州大学)


=========================================================================================================================

----------------------- function list
|-   function
||     unlock_policy_rwsem_read +
||     unlock_policy_rwsem_write +
||     init_cpufreq_transition_notifier_list +
||     cpufreq_cpu_get +
||     cpufreq_cpu_put +
||     adjust_jiffies +
||     cpufreq_notify_transition +
||     __find_governor +
||     cpufreq_parse_governor +
||     show_cpuinfo_cur_freq  +
||     show_scaling_governor +
||     store_scaling_governor +
||     show_scaling_driver +
||     show_scaling_available_governors +
||     show_cpus +
||     show_related_cpus +
||     show_affected_cpus +
||     store_scaling_setspeed +
||     show_scaling_setspeed +
||     show_bios_limit +
||     show +
||     store +
||     cpufreq_sysfs_release +
||     cpufreq_add_dev_policy +
||     cpufreq_add_dev_symlink  +
||     cpufreq_add_dev_interface +
||     cpufreq_add_dev +
||     __cpufreq_remove_dev
||     cpufreq_remove_dev

||     handle_update +
||     cpufreq_out_of_sync +
||     cpufreq_quick_get +
||     __cpufreq_get +
||     cpufreq_get +
||     cpufreq_bp_suspend +
||     cpufreq_bp_resume +
||     cpufreq_register_notifier +
||     cpufreq_unregister_notifier +
||     __cpufreq_driver_target +
||     cpufreq_driver_target +
||     __cpufreq_driver_getavg +
||     __cpufreq_governor +
||     cpufreq_register_governor +
||     cpufreq_unregister_governor +
||     cpufreq_get_policy +
||     __cpufreq_set_policy +
||     cpufreq_update_policy +
||     cpufreq_cpu_callback +
||     cpufreq_register_driver  +
||     cpufreq_unregister_driver +
||     cpufreq_core_init +
 
==========================================================
1.
 函数: static int __init cpufreq_core_init(void)
 参数:
 返回值:
 功能:  初始化用到的一些全局变量,创建cpufreq文件夹,注册系统核心操作
 调用模块:
 执行流程:
            初始化per cpu变量 cpufreq_policy_cpu
            初始化per cpu 类型的semaphore 变量cpu_policy_rwsem
            
            创建一个名为cpufreq的kobject对象//其结果是,在/sys/devices/system/cpu/cpuX下创建了cpufreq文件夹
                                                                                 //kobject_create_and_add
            在对象创建失败时引发oops
            注册系统核心操作cpufreq_syscore_ops //register_syscore_ops     ?????不知道被谁,什么时候调用
 2.
  函数:
 /**
 * cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
 *
 * This function is only executed for the boot processor.  The other CPUs
 * have been put offline by means of CPU hotplug.
 */
static int cpufreq_bp_suspend(void)
 参数:
 返回值:
 功能:  在当前CPU上调用cpufreq_driver->suspend // Prepare the boot CPU for system suspend.
 调用模块:
 执行流程:
          获得代码运行在的cpu 号  //smp_processor_id
          取得cpufreq_policy 类型的值的指针data,并增一data所指向结构的引用计数   //cpufreq_cpu_get
          如果cpufreq_driver->suspend不空,则调用之
          对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
 3.
  函数: struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
 参数:
 返回值:
 功能:  取得cpufreq_policy 类型的cpufreq_cpu_data的副本,对cpufreq_cpu_data引用计数增一
 调用模块:
 执行流程:
           得到cpufreq_driver_lock锁 // spin_lock_irqsave
           如果cpufreq_driver->owner模块已经插入内核,则递增该模块引用计数;
            如果该模块还没有插入内核,则返回0表示出错。//try_module_get,
                                                                   
           获得cpufreq_policy类型变量cpufreq_cpu_data的指针,保存在data中//per_cpu  <-----------------<<<<在哪里进行的设置?
           对cpufreq_cpu_data引用计数增一//kobject_get
           释放cpufreq_driver_lock锁//spin_unlock_irqrestore
           返回cpufreq_policy 类型的cpufreq_cpu_data的副本
           
4.
 函数: void cpufreq_cpu_put(struct cpufreq_policy *data)
 参数:
 返回值:
 功能:  对data的引用计数减一
 调用模块:
 执行流程:
            对data的引用计数减一  // kobject_put
             **  //module_put
5.
 函数:
 /**
 * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU.
 *
 *  1.) resume CPUfreq hardware support (cpufreq_driver->resume())
 *  2.) schedule call cpufreq_update_policy() ASAP as interrupts are
 *      restored. It will verify that the current freq is in sync with
 *      what we believe it to be. This is a bit later than when it
 *      should be, but nonethteless it's better than calling
 *      cpufreq_driver->get() here which might re-enable interrupts...
 *
 * This function is only executed for the boot CPU.  The other CPUs have not
 * been turned on yet.
 */
static void cpufreq_bp_resume(void);
 参数:
 返回值:
 功能: Restore proper frequency handling of the boot CPU. //执行policy的resume调用,并调用update_policy()
 调用模块:
 执行流程:
            得到当前CPU的id号  //smp_processor_id
            取得cpufreq_policy 类型的值data //cpufreq_cpu_get
            如果当前CPU的policy为空,则函数返回
                  否则,执行resume调用
            将policy的update函数成员添加到全局工作队列(workqueue)// schedule_work
                                                               //为了在中断环境下,调用update_policy() 函数
 
  6.
  函数: int cpufreq_register_governor(struct cpufreq_governor *governor)
 参数:
 返回值:
 功能:  将cpufreq_governor添加到全局governor表(cpufreq_governor_list)中
 调用模块:
 执行流程:
              获得保护cpufreq_governor_list的锁cpufreq_governor_mutex//mutex_lock
              如果要添加的cpufreq_governor不在cpufreq_governor_list中,则添加//__find_governor, list_add
              释放锁//mutex_unlock
 7.
  函数: static struct cpufreq_governor *__find_governor(const char *str_governor)
 参数:str_governor:要查找的cpufreq_governor的名字
 返回值:
 功能:  获得cpufreq_governor_list中名为str_governor 的cpufreq_governor的指针,
                  不存在时返回NULL
 调用模块:
 执行流程:
           按名字在cpufreq_governor_list中顺序查找相关cpufreq_governor
                  如果有,则返回指向它的指针
                     否则,返回空 //list_for_each_entry,strnicmp
 8.
  函数:  void cpufreq_unregister_governor(struct cpufreq_governor *governor)
 参数:
 返回值:
 功能: 将cpufreq_cpu_governor置为“空串“, 从governor->governor_list 中删除governor
 调用模块:
 执行流程:
            检查cpu号CPU是否可以调度(检查cpu是否在cpu_online_mask中)// cpu_online
             如果可以调度,则跳过该CPU
             如果governor跟当前设置的 cpufreq_governor相同,则将cpufreq_cpu_governor置为“空串“//strcpy
             获取cpufreq_governor_mutex锁 //mutex_lock
             从governor->governor_list 中删除governor //list_del
             释放cpufreq_governor_mutex锁 //mutex_unlock
             
/* This one keeps track of the previously set governor of a removed CPU */
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);

9.
 函数:
 /*
 * when "event" is CPUFREQ_GOV_LIMITS
 */

static int __cpufreq_governor(struct cpufreq_policy *policy,
                    unsigned int event);
 参数:
 返回值:
 功能:  使用policy处理event事件
 调用模块:
 执行流程:
           如果policy的transition_latency大于它的max_transition_latency,
               则,把policy的governor设置为cpufreq_gov_performance
               
             如果policy->governor->owner模块已经插入内核,则递增该模块引用计数;
              如果该模块还没有插入内核,则返回0//try_module_get
              
              调用policy->governor->governor
              当 event 是CPUFREQ_GOV_STOP 或CPUFREQ_GOV_LIMITS时
               或者  policy->governor->governor执行失败
               或者 event 是 CPUFREQ_GOV_STOP 并且policy->governor->governor执行成功时
              则,卸载模块 //module_put
             
            struct cpufreq_governor cpufreq_gov_performance = {
                .name       = "performance",
                .governor   = cpufreq_governor_performance,//一个governor,它静态地把cpu frequency 设置为最大可用值
                .owner      = THIS_MODULE,
            };

10.
 函数:
 /**
 * cpufreq_register_driver - register a CPU Frequency driver
 * @driver_data: A struct cpufreq_driver containing the values#
 * submitted by the CPU Frequency driver.
 *
 *   Registers a CPU Frequency driver to this core code. This code
 * returns zero on success, -EBUSY when another driver got here first
 * (and isn't unregistered in the meantime).
 *
 */
int cpufreq_register_driver(struct cpufreq_driver *driver_data);
 参数:
 返回值:
 功能:   注册cpufreq_driver驱动, 并注册cpu notifier 回调函数
 调用模块:
 执行流程:
            参数检查
            为driver_data->flags设置CPUFREQ_CONST_LOOPS标志
            获得cpufreq_driver_lock  // spin_lock_irqsave
            如果cpufreq_driver已经有值了,
                则,释放cpufreq_driver_lock锁 // spin_unlock_irqrestore
            使用传入的值,更新cpufreq_driver的值
            释放cpufreq_driver_lock锁//spin_unlock_irqrestore
             注册辅助驱动 //sysdev_driver_register,cpufreq_sysdev_driver is inserted into cpu_sysdev_class->drivers to be
                         // called on each operation on devices of that class. The refcount  of cpu_sysdev_class is incremented.
            driver_data->flag没有设置CPUFREQ_STICKY标志,
                  则,找到一个working CPU //cpu_possible, per_cpu
                                                  // 对这个CPU的要求:1. CPU may be pluged in at any time.
                                                  // 2. cpufreq_cpu_data非空//已经设置了cpufreq policy
                  如果没有找到一个working CPU,
                  那么,卸载辅助驱动 //sysdev_driver_unregister
                 
                  如果找到了一个working CPU,那么
                  Add notifier to "cpu_chain" raw notifier chain   //register_hotcpu_notifier
                                            
                                           
              ------------------------------             
           #define register_hotcpu_notifier(nb)    register_cpu_notifier(nb)
           /* Need to know about CPUs going up/down? */
            int __ref register_cpu_notifier(struct notifier_block *nb)
            {
                int ret;
                cpu_maps_update_begin();
                ret = raw_notifier_chain_register(&cpu_chain, nb); //Add notifier to "cpu_chain" raw notifier chain
                cpu_maps_update_done();
                return ret;
            }
             
             static RAW_NOTIFIER_HEAD(cpu_chain);     
                          ---------------------  
          #define cpu_possible(cpu)   cpumask_test_cpu((cpu), cpu_possible_mask)            
          /* flags */
            #define CPUFREQ_STICKY      0x01    /* the driver isn't removed even if
                                 * all ->init() calls failed */
            #define CPUFREQ_CONST_LOOPS 0x02    /* loops_per_jiffy or other kernel
                                 * "constants" aren't affected by
                                 * frequency transitions */ ????????<-----------------------<<<<<<<<
            #define CPUFREQ_PM_NO_WARN  0x04    /* don't warn on suspend/resume speed
                                 * mismatches */
        /**
         * The "cpufreq driver" - the arch- or hardware-dependent low
         * level driver of CPUFreq support, and its spinlock. This lock
         * also protects the cpufreq_cpu_data array.
         */
        static struct cpufreq_driver *cpufreq_driver; //"cpufreq driver"
        static DEFINE_SPINLOCK(cpufreq_driver_lock);


        static struct sysdev_driver cpufreq_sysdev_driver = {
            .add        = cpufreq_add_dev,
            .remove     = cpufreq_remove_dev,
        };
 static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); //在cpufreq_add_dev_policy中被设置用来保存cpufreq_policy
 
 11.
 函数:
 static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
                    unsigned long action, void *hcpu)
 参数:
 返回值:
 功能:  根据不同的action,决定“添加”cpufreq interface, 或者 “删除”cpufreq interface
 调用模块:
 执行流程:
            得到//get_cpu_sysdev
            如果action是:CPU_ONLINE// CPU (unsigned)v is up
                                          或者CPU_ONLINE_FROZEN// + tasks are frozen due to a suspend
                     则,Adds the cpufreq interface for a CPU device //cpufreq_add_dev
                     
           如果action是:CPU_DOWN_PREPARE //CPU (unsigned)v going down
                                         或者 CPU_DOWN_PREPARE_FROZEN // + tasks are frozen due to a suspend
                      则,Removes the cpufreq interface for a CPU device. //__cpufreq_remove_dev
           如果action是:CPU_DOWN_FAILED //CPU (unsigned)v NOT going down
                                         或者 CPU_DOWN_FAILED_FROZEN // + tasks are frozen due to a suspend
                       则,Adds the cpufreq interface for a CPU device //cpufreq_add_dev
 
  12.
 函数:  
/**
 * cpufreq_unregister_driver - unregister the current CPUFreq driver
 *
 *    Unregister the current CPUFreq driver. Only call this if you have
 * the right to do so, i.e. if you have succeeded in initialising before!
 * Returns zero if successful, and -EINVAL if the cpufreq_driver is
 * currently not initialised.
 */
int cpufreq_unregister_driver(struct cpufreq_driver *driver)
 参数:
 返回值:
 功能:  卸载辅助驱动, Remove notifier to "cpu_chain" raw notifier chain, cpufreq_driver置为空
 调用模块:
 执行流程:
             卸载辅助驱动 //sysdev_driver_unregister
             Remove notifier to "cpu_chain" raw notifier chain//unregister_hotcpu_notifier
             cpufreq_driver置为空
 13.
  函数:
 /**    
 * cpufreq_get_policy - get the current cpufreq_policy
 * @policy: struct cpufreq_policy into which the current cpufreq_policy
 *  is written
 * Reads the current cpufreq policy.
 */    
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
 参数:
 返回值:
 功能:  Reads the current cpufreq policy.
 调用模块:
 执行流程:
              取得cpufreq_policy 类型的cpufreq_cpu_data的副本,对cpufreq_cpu_data引用计数增一 //cpufreq_cpu_get
              复制cpufreq_cpu_data的副本到返回值//memcpy
              对cpu_policy的引用计数减一 //cpufreq_cpu_put
 14.  ************ 时钟相关
  函数:
/*
 * data   : current policy.
 * policy : policy to be set.
 */
static int __cpufreq_set_policy(struct cpufreq_policy *data,
                struct cpufreq_policy *policy)
 参数:
 返回值:
 功能:  设置新的policy
 调用模块:
 执行流程:
            复制旧policy 的cpuinfo域到新的policy的cpuinfo域//memcpy
             检查频率范围是否合理
            verify the cpu speed can be set within this limit//cpufreq_driver->verify(policy)
            通知链上的各个事件监听者,调整(CPUFREQ_ADJUST) cpufreq_policy// blocking_notifier_call_chain
            通知链上的各个事件监听者, (CPUFREQ_INCOMPATIBLE) // blocking_notifier_call_chain
                                              
             verify the cpu speed can be set within this limit//cpufreq_driver->verify(policy)
             notification of the new policy(CPUFREQ_NOTIFY) // blocking_notifier_call_chain
             记录频率协商结果到旧的policy中
               如果cpufreq_driver->setpolicy非空,则 调用cpufreq_driver中setpolicy函数 //cpufreq_driver->setpolicy(policy)
              如果cpufreq_driver->setpolicy 空,
                          则,  save old, working values(data->governor)  
                                       end old governor (CPUFREQ_GOV_STOP)//__cpufreq_governor
 
               ---------------------------                        
 struct cpufreq_cpuinfo { //该结构内成员值,由driver负责填写
    unsigned int        max_freq; //the minimum and maximum frequency (in kHz) which is supported by this CPU
    unsigned int        min_freq;
    /* in 10^(-9) s = nanoseconds */
    unsigned int        transition_latency; //the time it takes on this CPU to switch between two frequencies innanoseconds
                                                                 // (if appropriate, else  specify CPUFREQ_ETERNAL)
};

/**
 * Two notifier lists: the "policy" list is involved in the
 * validation process for a new CPU frequency policy; the
 * "transition" list for kernel code that needs to handle
 * changes to devices when the CPU clock speed changes.
 * The mutex locks both lists.
 */
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);//新 CPU frequency policy 更新通知链
static struct srcu_notifier_head cpufreq_transition_notifier_list;     //CPU clock speed chagne 更新通知链                 
 
 15.  
 函数:
 /**
 *  cpufreq_update_policy - re-evaluate an existing cpufreq policy
 *  @cpu: CPU which shall be re-evaluated
 *  Useful for policy notifiers which have different necessities
 *  at different times.
 */
int cpufreq_update_policy(unsigned int cpu);
 参数:
 返回值:
 功能:    re-evaluate an existing cpufreq policy //cpufreq_driver->suspend
 调用模块:
 执行流程:
            取得cpufreq_policy 类型的值的指针data,并增一data所指向结构的引用计数  //cpufreq_cpu_get
             获取写锁cpu_policy_rwsem //lock_policy_rwsem_write
             把当前cpufreq_policy的值复制到辅助变量中,
             使用user_policy成员的中数据更新辅助变量的相关域
             
             检查是否频率是否又被改变
              如果是,则call notifier chain and adjust_jiffies on frequency transition // cpufreq_out_of_sync
              如果没有改变,则
                          以辅助变量为参数调用 设置新的policy//__cpufreq_set_policy
           释放写锁cpu_policy_rwsem//unlock_policy_rwsem_write
          对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put   
16.
#define lock_policy_rwsem(mode, cpu)                    \
static int lock_policy_rwsem_##mode                 \
(int cpu)                               \
{                                   \
    int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);      \ //获得对应于cpu的cpufreq_policy_cpu
    BUG_ON(policy_cpu == -1);                   \
    down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu));        \ //获取cpu_policy_rwsem锁
    if (unlikely(!cpu_online(cpu))) {               \ //检查CPU是否处于online状态
        up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu));  \ //如果不是,则释放cpu_policy_rwsem锁
        return -1;                      \
    }                               \
                                    \
    return 0;                           \
}
lock_policy_rwsem(read, cpu); //获取读锁
lock_policy_rwsem(write, cpu); //获取写锁
 17.
   函数:static void unlock_policy_rwsem_read(int cpu)
  参数:
 返回值:
 功能:     释放读锁cpu_policy_rwsem
 调用模块:
 执行流程:
            获得与cpu号CPU对应的cpufreq_policy_cpu //per_cpu
             释放读锁cpu_policy_rwsem//up_read
 18.
  函数:static void unlock_policy_rwsem_write(int cpu)
  参数:
 返回值:
 功能:    释放写锁cpu_policy_rwsem
 调用模块:
 执行流程:   
              获得与cpu号CPU对应的cpufreq_policy_cpu //per_cpu
             释放写锁cpu_policy_rwsem//up_read           
 /*
 * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
 * all cpufreq/hotplug/workqueue/etc related lock issues.
 *
 * The rules for this semaphore:
 * - Any routine that wants to read from the policy structure will
 *   do a down_read on this semaphore.
 * - Any routine that will write to the policy structure and/or may take away
 *   the policy altogether (eg. CPU hotplug), will hold this lock in write
 *   mode before doing so.
 *
 * Additional rules:
 * - All holders of the lock should check to make sure that the CPU they
 *   are concerned with are online after they get the lock.
 * - Governor routines that can be called in cpufreq hotplug path should not
 *   take this sem as top level hotplug notifier handler takes this.
 * - Lock should not be held across
 *     __cpufreq_governor(data, CPUFREQ_GOV_STOP);
 */
static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
19.  **************时钟相关的
 static bool init_cpufreq_transition_notifier_list_called;
  函数:static int __init init_cpufreq_transition_notifier_list(void)
  参数:
 返回值:
 功能:     初始化cpufreq_transition_notifier_list
 调用模块:
 执行流程:
              Initialize an SRCU notifier head  //srcu_init_notifier_head
              init_cpufreq_transition_notifier_list_called置位
 /**
 * Two notifier lists: the "policy" list is involved in the
 * validation process for a new CPU frequency policy; the
 * "transition" list for kernel code that needs to handle
 * changes to devices when the CPU clock speed changes.
 * The mutex locks both lists.
 */
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
static struct srcu_notifier_head cpufreq_transition_notifier_list;
20. **************时钟相关的
  函数:
  /**
 *  cpufreq_register_notifier - register a driver with cpufreq
 *  @nb: notifier function to register
 *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
 *
 *  Add a driver to one of two lists: either a list of drivers that
 *      are notified about clock rate changes (once before and once after
 *      the transition), or a list of drivers that are notified about
 *      changes in cpufreq policy. //只能选择一个list
 *
 *  This function may sleep, and has the same return conditions as
 *  blocking_notifier_chain_register.
 */
int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
  参数:
 返回值:
 功能:     注册一个notifier到 cpufreq_transition_notifier_list或者blocking_notifier_chain_register
 调用模块:
 执行流程:
             list:CPUFREQ_TRANSITION_NOTIFIER 时
                          注册到cpufreq_transition_notifier_list//srcu_notifier_chain_register
             list:CPUFREQ_POLICY_NOTIFIER 时
                          注册到blocking_notifier_chain_register//cpufreq_policy_notifier_list        
 21.**************时钟相关的
   函数:
   /**
 *  cpufreq_unregister_notifier - unregister a driver with cpufreq
 *  @nb: notifier block to be unregistered
 *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
 *
 *  Remove a driver from the CPU frequency notifier list.
 *
 *  This function may sleep, and has the same return conditions as
 *  blocking_notifier_chain_unregister.
 */
int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
  参数:
 返回值:
 功能:      Remove a driver from the CPU frequency notifier list.
 调用模块:
 执行流程:
             ist:CPUFREQ_TRANSITION_NOTIFIER 时
                          从cpufreq_transition_notifier_list上删除//srcu_notifier_chain_unregister
             list:CPUFREQ_POLICY_NOTIFIER 时
                          注册到blocking_notifier_chain_register// blocking_notifier_chain_unregister

22.  **************时钟相关的
  函数:
  /**
 * cpufreq_notify_transition - call notifier chain and adjust_jiffies
 * on frequency transition.
 *
 * This function calls the transition notifiers and the "adjust_jiffies"
 * function. It is called twice on all CPU frequency changes that have
 * external effects.
 */
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
  参数:
 返回值:
 功能:     call notifier chain and adjust_jiffies on frequency transition
 调用模块:
 执行流程:
            若果中断被关闭,则打印BUG信息,然后调用PANIC函数,让系统panic //irqs_disabled,BUG_ON
            把cpufreq_driver->flags复制到freqs->flags
            得到全局cpufreq_policy结构的指针cpufreq_cpu_data //per_cpu
            如果处于 CPUFREQ_PRECHANGE阶段:
                       如果cpufreq_driver->flags没有设置CPUFREQ_CONST_LOOPS标志,
                                 则,   如果 policy中cur(当前的CPU频率)跟freqs->old不同时,使用cur更新freqs->old值
                       通知注册在cpufreq_transition_notifier_list上的监听者,CPU freq 发生改变//srcu_notifier_call_chain    
                      adjust the system "loops_per_jiffy" //adjust_jiffies    
           如果处于CPUFREQ_POSTCHANGE阶段:
                      adjust the system "loops_per_jiffy"  //   adjust_jiffies
                     //没有找到//trace_cpu_frequency //???????????????
                     通知注册在cpufreq_transition_notifier_list上的监听者,CPU freq 发生改变 //srcu_notifier_call_chain  
                      policy->cur = freqs->new;  
      =--------------------------=-      
#define CPUFREQ_PRECHANGE   (0) // <----------------------------------<<<<??????
#define CPUFREQ_POSTCHANGE  (1)
#define CPUFREQ_RESUMECHANGE    (8)
#define CPUFREQ_SUSPENDCHANGE   (9)

struct cpufreq_freqs {
    unsigned int cpu;   /* cpu nr */
    unsigned int old;  //
    unsigned int new; //新设置的CPU 频率
    u8 flags;       /* flags of cpufreq_driver, see below. *///CPUFREQ_CONST_LOOPS, CPUFREQ_STICKY,  CPUFREQ_PM_NO_WARN
};

23.
  函数:
  /**
 * adjust_jiffies - adjust the system "loops_per_jiffy"
 *
 * This function alters the system "loops_per_jiffy" for the clock
 * speed change. Note that loops_per_jiffy cannot be updated on SMP
 * systems as each CPU might be scaled differently. So, use the arch
 * per-CPU loops_per_jiffy value wherever possible.
 */
static unsigned long l_p_j_ref;
static unsigned int  l_p_j_ref_freq;                
static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci);
  参数:
                 ci->new: 要设置的频率
                 ci->old:原来的频率
 返回值:
 功能:     adjust the system "loops_per_jiffy"
 调用模块:
 执行流程:
              如果 cpufreq_freqs类型变量ci的flags设置了CPUFREQ_CONST_LOOPS标志,
                       则,直接返回
              ///  ?????????????????????????????? <--------------------------<<<<<<<这里的if语句中的条件没有看懂
              计算新值更新loops_per_jiffy值 //cpufreq_scale
             
24.
函数:
/**
 * cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch safe)
 * @old:   old value
 * @div:   divisor
 * @mult:  multiplier
 *    new = old * mult / div
 */         
static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mult);
  参数:
 返回值:
 功能:      "old * mult / div" calculation for large values (32-bit-arch safe)
 调用模块:
 执行流程:
         loops_per_jiffy计算原理:
              假设频率设置为ci->new后对应的loops_per_jiffy为X,则有
              
                    X                loops_per_jiffy
            ------------   =  --------------------
             ci->new              ci->old
             
25.
 函数:
 int __cpufreq_driver_target(struct cpufreq_policy *policy,
                unsigned int target_freq,
                unsigned int relation);
  参数:target_freq must be within policy->min and policy->max,
 返回值:
 功能:     执行  cpufreq_driver->target
 调用模块:
 执行流程:
             cpufreq_driver->target
 26.
   函数:   
int cpufreq_driver_target(struct cpufreq_policy *policy,
              unsigned int target_freq,
              unsigned int relation)
  参数: target_freq must be within policy->min and policy->max,
 返回值:
 功能:     执行  cpufreq_driver->target
 调用模块:
 执行流程:
               取得cpufreq_policy 类型的cpufreq_cpu_data的副本,对cpufreq_cpu_data引用计数增一 //cpufreq_cpu_get
               获得写锁//lock_policy_rwsem_write
               执行  cpufreq_driver->target//__cpufreq_driver_target
               释放写锁 //unlock_policy_rwsem_write
               对cpufreq_policy* 类型data所指向的结构的引用计数减一 //cpufreq_cpu_put   
 27.
  函数:int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
  参数:
 返回值:
 功能:     
 调用模块:
 执行流程:
               取得cpufreq_policy 类型的cpufreq_cpu_data的副本,对cpufreq_cpu_data引用计数增一 //cpufreq_cpu_get
               执行cpufreq_driver->getavg
               对cpufreq_policy* 类型data所指向的结构的引用计数减一 //cpufreq_cpu_put
 28.
  函数:static struct cpufreq_governor *__find_governor(const char *str_governor)
  参数:
 返回值:
 功能:     在cpufreq_governor_list上寻找名字为str_governor的governor
 NOTE:  在使用本函数前要先获得锁!!
 调用模块:
 执行流程:
               在cpufreq_governor_list上寻找名字为str_governor的governor //strnicmp,
               
static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX(cpufreq_governor_mutex);

29.
  函数:
  /**
 * cpufreq_parse_governor - parse a governor string
 */
static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
                struct cpufreq_governor **governor)
  参数:
 返回值:governor:str_governor对应的 cpufreq_governor结构
                    policy:如果governor是 performance,或者 powersave,则指示,在policy中返回
 功能:    parse a governor string
 调用模块:
 执行流程:
             如果str_governor是“performance”,那么policy是CPUFREQ_POLICY_PERFORMANCE
             如果str_governor是 "powersave", 那么policy是CPUFREQ_POLICY_POWERSAVE
             否则,
                       获得cpufreq_governor_list保护的锁cpufreq_governor_mutex //mutex_lock
                       在cpufreq_governor_list上寻找名字为str_governor的governor //__find_governor
                        如果没有找到,则
                                放弃cpufreq_governor_mutex锁//mutex_unlock
                                try to load a kernel module //cpufreq_##str_governor
                                获得cpufreq_governor_list保护的锁cpufreq_governor_mutex //mutex_lock
                                在cpufreq_governor_list上寻找名字为str_governor的governor //__find_governor
                                如果找到了,则保存在governor中
                                放弃cpufreq_governor_mutex锁//mutex_unlock
                                返回
  30.
   函数:
  /**
 * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware
 */
static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
                    char *buf)
  参数:
 返回值:
 功能:     
 调用模块:
 执行流程:
            获得cpu对应的CPU的实际运行频率 保存到 ret_freq,若实际运行频率和policy->cur
                   不一致则,依据实际频率调整 policy 的参数。 //__cpufreq_get
            显示CPU的实际运行频率
 
  31.
  函数:static unsigned int __cpufreq_get(unsigned int cpu)
  参数:
 返回值:
 功能:     获得cpu对应的CPU的实际运行频率 保存到 ret_freq,若实际运行频率和policy->cur
                   不一致则,依据实际频率调整 policy 的参数。
 调用模块:
 执行流程:
             获得cpufreq_policy类型cpufreq_cpu_data变量 //  
             获得cpu对应的CPU的实际运行频率 保存到 ret_freq //cpufreq_driver->get
              如果CPU的实际运行频率 ret_freq  和系统"认为的“运行频率policy->cur不一致
                则, call notifier chain and adjust_jiffies on frequency transition //cpufreq_out_of_sync
                          put work task ‘handle_update’ in global workqueue //schedule_work(&policy->update);
                           //handle_update 将会re-evaluate an existing cpufreq policy
            
32. ******** 时钟相关
 函数:
 /**
 *  cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble.
 *  @cpu: cpu number
 *  @old_freq: CPU frequency the kernel thinks the CPU runs at
 *  @new_freq: CPU frequency the CPU actually runs at
 *
 *  We adjust to current frequency first, and need to clean up later.
 *  So either call to cpufreq_update_policy() or schedule handle_update()).
 */
static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
                unsigned int new_freq);
 参数:
 返回值:
 功能:      call notifier chain and adjust_jiffies on frequency transition
 调用模块:
 执行流程:
                       call notifier chain and adjust_jiffies on frequency transition //cpufreq_notify_transition
                       
 33.
  函数:static void handle_update(struct work_struct *work) //
  参数:
 返回值:
 功能:     re-evaluate an existing cpufreq policy
 调用模块:
 执行流程:
                re-evaluate an existing cpufreq policy // cpufreq_update_policy   
                
                ----------
                
  INIT_WORK(&policy->update, handle_update); //初始化
     put work task ‘handle_update’ in global workqueue//schedule_work(&policy->update);
         //handle_update 将会re-evaluate an existing cpufreq policy
34.
  函数:
        /**
         * cpufreq_get - get the current CPU frequency (in kHz)
         * @cpu: CPU number
         *
         * Get the CPU current (static) CPU frequency
         */
        unsigned int cpufreq_get(unsigned int cpu);
  参数:
 返回值:
 功能:      get the current CPU frequency (in kHz)
 调用模块:
 执行流程:
             取得cpufreq_policy 类型的cpufreq_cpu_data的副本,对cpufreq_cpu_data引用计数增一 //cpufreq_cpu_get     
             获取读锁cpu_policy_rwsem//lock_policy_rwsem_read    
         
            获得cpu对应的CPU的实际运行频率 保存到 ret_freq,若实际运行频率和policy->cur
                   不一致则,依据实际频率调整 policy 的参数。  // __cpufreq_get
            释放读锁cpu_policy_rwsem//unlock_policy_rwsem_read     
            对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
 35.
  函数:
 /**
 * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
 * @cpu: CPU number
 *
 * This is the last known freq, without actually getting it from the driver.
 * Return value will be same as what is shown in scaling_cur_freq in sysfs.
 */
unsigned int cpufreq_quick_get(unsigned int cpu);
  参数:
 返回值:
 功能:     get the CPU frequency (in kHz) from policy->cur
                     //This is the last known freq getted  from the driver.
 调用模块:
 执行流程:
            取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
                      对cpufreq_cpu_data引用计数增一//cpufreq_cpu_get
             ret_freq = policy->cur
             对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
 
 36.
   函数:
  /**
 * show_scaling_governor - show the current policy for the specified CPU
 */
static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf);
  参数:
 返回值:
 功能:   show the current policy for the specified CPU  
 调用模块:
 执行流程:
 
 37.
  函数:
 /**
 * store_scaling_governor - store policy for the specified CPU
 */
static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
                    const char *buf, size_t count);
  参数:
 返回值:
 功能:     store policy for the specified CPU
 调用模块:
 执行流程:
               取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
                      对cpufreq_cpu_data引用计数增一//cpufreq_get_policy
               得到要设置的governor的名字 //sscanf
                parse a governor string  //cpufreq_parse_governor
                设置新的policy //__cpufreq_set_policy
                更新policy//policy->user_policy.policy = policy->policy;
                更新governor     //policy->user_policy.governor = policy->governor;        
 38.
         函数:
/**
 * show_scaling_driver - show the cpufreq driver currently loaded
 */
static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf);
 39.
         函数:    
 /**
 * show_scaling_available_governors - show the available CPUfreq governors
 */
static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
                        char *buf);
 40.
   函数:static ssize_t show_cpus(const struct cpumask *mask, char *buf)
   功能:
                  显示在mask中的CPU //for_each_cpu(cpu, mask)
41.
函数:
/**
 * show_related_cpus - show the CPUs affected by each transition even if
 * hw coordination is in use
 */
static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf);

42:
函数:
/**
 * show_affected_cpus - show the CPUs affected by each transition
 */
static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf);

43.
   函数:
static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
                    const char *buf, size_t count)       
  功能:      设置新的CPU运行频率//policy->governor->store_setspeed(policy, freq)

44.
函数:
static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
功能 : 显示CPU运行频率//policy->governor->show_setspeed(policy, buf);

45.
函数:
/**
 * show_scaling_driver - show the current cpufreq HW/BIOS limitation
 */
static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf);

46.
  函数:
/**
 * cpufreq_add_dev - add a CPU device
 *
 * Adds the cpufreq interface for a CPU device.
 *
 * The Oracle says: try running cpufreq registration/unregistration concurrently
 * with with cpu hotplugging and all hell will break loose. Tried to clean this
 * mess up, but more thorough testing is needed. - Mathieu
 */
static int cpufreq_add_dev(struct sys_device *sys_dev);
  参数:
 返回值:
 功能:     Adds the cpufreq interface for a CPU device.
 调用模块:
 执行流程:
                检查cpu号CPU是否可以调度(检查cpu是否在cpu_online_mask中)//cpu_is_offline
                 如果不能调度,则返回
                  
               取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
                             对cpufreq_cpu_data引用计数增一//cpufreq_cpu_get
                如果已经有其他CPU注册了该CPU设备,
                    则   对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
                            返回
                            
               如果cpufreq_driver->owner模块已经插入内核,则递增该模块引用计数;
                如果该模块还没有插入内核,则对try_module_get调用返回0//try_module_get
                
               allocate a struct cpumask ,并把policy->cpus指向该变量 //alloc_cpumask_var
               allocate a struct cpumask,结构清零,并把policy->related_cpus//zalloc_cpumask_var
               policy->cpu 初始化为sys_dev->id  // sys_dev->id
               初始化policy->cpus,仅仅设置和cpu相关的bit位 //cpumask_copy,cpumask_of
               暂时把当前cpu设置为policy cpu //    per_cpu(cpufreq_policy_cpu, cpu) = cpu;
                获取写锁cpu_policy_rwsem //lock_policy_rwsem_write, 该函数的参数为 policy cpu的号
               初始化 ** *//init_completion,INIT_WORK
               
               查找是否有其他CPU x 注册了cpu freq policy,而且当前cpu也在它的related_cpus中
               如果找到了,则 使用已经CPU x注册在policy中的 governor初始化本policy的governor域
               如果没有找到,则使用默认的governor
               
               调用driver的 init方法
               policy->user_policy.min = policy->min;
               policy->user_policy.max = policy->max;
               
               通告注册在cpufreq_policy_notifier_list上的所有监听者
                            CPUFREQ_START //blocking_notifier_call_chain ????表达的什么信息呢??policy改变吗??
                                                               //这要看接收到消息的监听者注册的函数了:
               
                 用policy的cpus域更新每个每个处在policy->cpus中的cpu对应的policy的cpus域,
                             并在sys_dev对应的文件夹(cpux????)下创建符号链接“cpufreq”
                                                                                                     // cpufreq_add_dev_policy  ????????????
                 在cpuX下,创建‘cpufreq’文件夹,在文件夹下创建跟driver相关的控制文件,
                   统一policy->cpus中的cpu的当前policy为 poliy,policy cpu 为policy->cpu
                  在cpu对应的文件‘cpuX' 下,创建 policy对应的文件'cpufreq'的符号链接  //cpufreq_add_dev_interface
                  
                  释放写锁cpu_policy_rwsem //unlock_policy_rwsem_write
                  向用户空间通知 cpufreq文件可用(policy->kobj)//kobject_uevent
                 cpufreq_driver->owner模块引用计数减一  //module_put
                 
 47.
  函数:
  /*
 * Returns:
 *   Negative: Failure
 *   0:        Success
 *   Positive: When we have a managed CPU and the sysfs got symlinked
 */
static int cpufreq_add_dev_policy(unsigned int cpu,
                  struct cpufreq_policy *policy,
                  struct sys_device *sys_dev);
  参数:
 返回值:
 功能:    用policy的cpus域更新每个每个处在policy->cpus中的cpu对应的policy的cpus域,
                   并在sys_dev对应的文件夹(cpux????)下创建符号链接“cpufreq” //???????????????
 调用模块:
 执行流程:
                找到cpufreq_governor_list上名为cpufreq_cpu_governor的governor
                                                             //cpufreq_cpu_governor ,__find_governor       
                 用找到的governor初始化policy->governor//这样会把cpufreq_add_dev中对该域的初始化值覆盖
                 
                 对于 policy->cpus中的除了自身外的每个cpu执行如下操作:
                          取得对应于cpu的cpufreq_policy 类型的cpufreq_cpu_data的副本,
                           即,该cpu的当前 cpufreq_policy , 并对cpufreq_cpu_data引用计数增一 //cpufreq_cpu_get     
                           
                           释放写锁cpu_policy_rwsem//unlock_policy_rwsem_write; lock_policy_rwsem_write在那里调用了????
                            对cpufreq_policy_cpu 赋值为 cpufreq_add_dev调用时,写入policy->cpu的值//
                            获得cpu_policy_rwsem写锁 //lock_policy_rwsem_write ********** 没有释放锁
                                   如果调用失败,则
                                         调用cpufreq_driver->exit(policy)//??????什么作用
                                         对cpufreq_policy* 类型 managed_policy所指向的结构的引用计数减一  //cpufreq_cpu_put
                           
                            获得cpufreq_driver_lock锁//spin_lock_irqsave
                            把 policy->cpus复制到managed_policy->cpus // ******************
                            把cpufreq_cpu_data赋值为 managed_policy//
                           释放cpufreq_driver_lock锁,并恢复中断标志 //spin_unlock_irqrestore
                           在sys_dev->kobj("cpuX????")下创建指向managed_policy->kobj(cpufreq)的
                                                                 符号链接文件cpufreq //sysfs_create_link *****************
                          对cpufreq_policy* 类型 managed_policy所指向的结构的引用计数减一 //cpufreq_cpu_put
                          cpufreq_driver->exit(policy)//??????? *************
                          
 48.
 函数:
 static int cpufreq_add_dev_interface(unsigned int cpu,
                     struct cpufreq_policy *policy,
                     struct sys_device *sys_dev);
 参数:
 返回值:
 功能:     在cpuX下,创建‘cpufreq’文件夹,在文件夹下创建跟driver相关的控制文件,
                     统一policy->cpus中的cpu的当前policy为 poliy,policy cpu 为policy->cpu
                     在cpu对应的文件‘cpuX' 下,创建 policy对应的文件'cpufreq'的符号链接
 调用模块:
 执行流程:
             在sys_dev下创建 cpufreq文件夹 //kobject_init_and_add
             在cpufreq下创建跟driver属性相关的控制文件//sysfs_create_file
             在cpufreq下创建跟driver成员函数相关的控制文件//sysfs_create_file
             
             得到锁cpufreq_driver_lock//spin_lock_irqsave
             对于每个处于policy->cpus中的cpu,执行如下操作:
                      如果cpu在线,则
                             更新它的cpufreq_cpu_data(每个cpu的当前policy结构的指针)
                             更新它的cpufreq_policy_cpu
                             
             释放锁cpufreq_driver_lock//spin_unlock_irqrestore
              在cpu对应的文件‘cpuX' 下,创建 policy对应的文件'cpufreq'的
                                           符号链接//cpufreq_add_dev_symlink
             将new_policy备份到policy中//memcpy
             设置新的policy  //__cpufreq_set_policy
               policy->user_policy.policy = policy->policy;
                policy->user_policy.governor = policy->governor;
 49.
 函数:
 /* symlink affected CPUs */
static int cpufreq_add_dev_symlink(unsigned int cpu,
                   struct cpufreq_policy *policy);
 参数:
 返回值:
 功能:     在cpu对应的文件‘cpuX' 下,创建 policy对应的文件'cpufreq'的符号链接
 调用模块:
 执行流程:
             对于 policy->cpus中的每个cpu执行如下操作:  //for_each_cpu
                           取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
                                     对cpufreq_cpu_data引用计数增一//cpufreq_cpu_get
                          获得cpu对应的sys_device //get_cpu_sysdev
                          在‘cpuX‘下创建'cpufreq'文件的符号链接//sysfs_create_link
 50
  函数:static int cpufreq_remove_dev(struct sys_device *sys_dev)
  参数:
 返回值:
 功能:     
 调用模块:
 执行流程:
                    得到写锁cpu_policy_rwsem//lock_policy_rwsem_write     
                    //__cpufreq_remove_dev
                    
51.
 函数:
/**
 * __cpufreq_remove_dev - remove a CPU device
 *
 * Removes the cpufreq interface for a CPU device.
 * Caller should already have policy_rwsem in write mode for this CPU.
 * This routine frees the rwsem before returning.
 */
static int __cpufreq_remove_dev(struct sys_device *sys_dev);        
  参数:
 返回值:
 功能:     remove   CPU device //可能被递归调用
 调用模块:
 执行流程:
              获得cpufreq_driver_lock锁 //spin_lock_irqsave
              获得cpufreq_cpu_data保存在data中,即当前policy结构的指针
              cpufreq_cpu_data置为空
               
               如果,当前cpu不是 data->cpu 那么,
                         将cpu 从data->cpus 中清除  //cpumask_clear_cpu
                         释放锁,并恢复中断标志 //spin_unlock_irqrestore
                         对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
                          释放写锁cpu_policy_rwsem//unlock_policy_rwsem_write
                          把cpuX下的cpufreq文件删除 //sysfs_remove_link
                   
               把删除的cpu的governor保存到cpufreq_cpu_governor     
               若还有其他cpu共用该policy //cpumask_weight   
                        那么,把每个相关的cpu的cpufreq_cpu_data置为空
                                                               //cpufreq_cpu_data每个cpu的当前policy结构的指针
                   释放cpufreq_driver_lock锁 //spin_unlock_irqrestore
               
               对于还有其他cpu共用该policy的情况,
                        把data->governor->name保存到每个cpu的cpufreq_cpu_governor
                        获得与cpu相关的cpu 设备的sys_device变量//get_cpu_sysdev
                        释放与cpu相关的写锁cpu_policy_rwsem//unlock_policy_rwsem_write
                        把cpuX下的cpufreq文件删除 //sysfs_remove_link
                        取得与cpu相关的写锁cpu_policy_rwsem//lock_policy_rwsem_write
                         对cpufreq_policy* 类型data所指向的结构的引用计数减一 //cpufreq_cpu_put
               
              使用policy处理event事件(CPUFREQ_GOV_STOP),卸载模块 //__cpufreq_governor
              //cmp = &data->kobj_unregister ???? what's this used for
              释放与cpu相关的写锁cpu_policy_rwsem//unlock_policy_rwsem_write
              释放policy对象//kobject_put
              
              调用data->kobj_unregister,并等待 //wait_for_completion
              调用cpufreq_driver->exit //?????????????,可以通过读实际的driver代码,看到底完成什么工作
              
              对于还有其他cpu共用该policy的情况,
                           when the CPU which is the parent of the kobj is hotplugged
                          offline, check for siblings, and create cpufreq sysfs interface
                          and symlinks //cpumask_clear_cpu, cpufreq_add_dev, get_cpu_sysdev, cpumask_first
                          取得与cpu相关的写锁cpu_policy_rwsem// lock_policy_rwsem_write
                          递归调用// __cpufreq_remove_dev

            释放policy相关的动态分配的内存//free_cpumask_var, free_cpumask_var, kfree   
              
---------相关的宏和用到的数据结构
 
  static struct notifier_block __refdata cpufreq_cpu_notifier = {
    .notifier_call = cpufreq_cpu_callback,
};
 
 
struct notifier_block {
    int (*notifier_call)(struct notifier_block *, unsigned long, void *);
    struct notifier_block __rcu *next;
    int priority;
};

  -----=-
 
  #define CPUFREQ_GOV_START  1 //This governor shall start its duty for the CPU     policy->cpu
#define CPUFREQ_GOV_STOP   2 //This governor shall end its duty for the CPU
#define CPUFREQ_GOV_LIMITS 3 //The limits for CPU policy->cpu have changed to  policy->min and policy->max

struct cpufreq_governor {
    char    name[CPUFREQ_NAME_LEN]; //
    int (*governor) (struct cpufreq_policy *policy, //在__cpufreq_governor中被调用。
    ssize_t (*show_setspeed)    (struct cpufreq_policy *policy,
                     char *buf); //用户空间显示CPU运行频率时调用
    int (*store_setspeed)   (struct cpufreq_policy *policy,
                     unsigned int freq); //用户空间设置频率时调用
    unsigned int max_transition_latency; /* HW must be able to switch to
            next freq faster than this value in nano secs or we
            will fallback to performance governor */
    struct list_head    governor_list;
    struct module       *owner;
};

 129 static LIST_HEAD(cpufreq_governor_list);
 130 static DEFINE_MUTEX(cpufreq_governor_mutex);

#define CPUFREQ_RELATION_L 0  /* lowest frequency at or above target */

#define CPUFREQ_RELATION_H 1  /* highest frequency below or at target */
 struct cpufreq_cpuinfo { //该结构内成员值,由driver负责填写
    unsigned int        max_freq; //the minimum and maximum frequency (in kHz) which is supported by this CPU
    unsigned int        min_freq;
    /* in 10^(-9) s = nanoseconds */
    unsigned int        transition_latency; //the time it takes on this CPU to switch between two frequencies innanoseconds
                                                                 // (if appropriate, else  specify CPUFREQ_ETERNAL)
};
struct cpufreq_policy {
    cpumask_var_t       cpus;   /* CPUs requiring sw coordination */ // CPUs affected by each transition
                                                  //在添加CPU设备时,在cpufreq_add_dev分配空间,并初始化
                                                  //List of CPUs that require software coordination of frequency.
    cpumask_var_t       related_cpus; /* CPUs with any coordination */ // the CPUs affected by each transition
                                                  // List of CPUs that need some sort of frequency
                                                  // coordination, whether software or hardware.
    unsigned int        shared_type; /* ANY or ALL affected CPUs
                        should set cpufreq */
    unsigned int        cpu;    /* cpu nr of registered CPU */ //在cpufreq_add_dev中被赋值为sys_dev->id
    struct cpufreq_cpuinfo  cpuinfo;/* see above */ 14

    unsigned int        min;    /* in kHz */ //由 driver负责填写
    unsigned int        max;    /* in kHz */ //由 driver负责填写
    unsigned int        cur;    /* in kHz, only needed if cpufreq //系统认为的,cpu的运行频率(但是有
         可能不是CPU真正的运行频率,CPU真正的运行频率,可调用cpufreq_driver结构的
                       get成员函数获得 ) //由 driver负责填写
                     * governors are used */
    unsigned int        policy; /* see above */                       // must contain the "default policy" for this CPU.
                                                           // CPUFREQ_POLICY_POWERSAVE, powersave policy
                                                           //CPUFREQ_POLICY_PERFORMANCE, performance
                                                           //other policy
                                                           //由 driver负责填写
                                                           
    struct cpufreq_governor *governor; /* see below */   //A few moments later, cpufreq_driver.verify and either
                                                                                             //cpufreq_driver.setpolicy or cpufreq_driver.target is called with
                                                                                              //these values.
                                                                                              //可以是CPUFREQ_DEFAULT_GOVERNOR
                                                                                              //由 driver负责填写
    struct work_struct  update; /* if update_policy() needs to be
                     * called, but you're in IRQ context */ //__cpufreq_get 调用了, 在 cpufreq_add_dev中初始化

    struct cpufreq_real_policy  user_policy; // 在cpufreq_update_policy用到,在store_scaling_governor中被设置
                                                                         //保存了用户设置的policy的相关参数??
    struct kobject      kobj;
    struct completion   kobj_unregister;//在 cpufreq_add_dev中初始化,                
                                                               //__cpufreq_remove_dev调用,确保在调用cpufreq_driver->exit前,
                                                               //没有对kobj的其他引用???
};
struct cpufreq_real_policy { //
    unsigned int        min;    /* in kHz */
    unsigned int        max;    /* in kHz */
    unsigned int        policy; /* see above */
    struct cpufreq_governor *governor; /* see below */
};


struct cpufreq_driver {
    struct module           *owner; //
    char            name[CPUFREQ_NAME_LEN];
    u8          flags; //CPUFREQ_CONST_LOOPS, CPUFREQ_STICKY,  CPUFREQ_PM_NO_WARN

    /* needed by all drivers */
    int (*init)     (struct cpufreq_policy *policy);//A pointer to the per-CPU initialization function.
    int (*verify)   (struct cpufreq_policy *policy); //A pointer to a "verification" function.

    /* define one out of two */
    int (*setpolicy)    (struct cpufreq_policy *policy);
    int (*target)   (struct cpufreq_policy *policy,
                 unsigned int target_freq,
                 unsigned int relation); //    如果target没有定义的话,那么只有performance powersave可用????

    /* should be defined, if possible */
    unsigned int    (*get)  (unsigned int cpu); //返回的值是当前号为cpu的CPU的真正频率
                                                                          //__cpufreq_get 中有调用
    /* optional */
    unsigned int (*getavg)  (struct cpufreq_policy *policy,
                 unsigned int cpu); ///?????????????
    int (*bios_limit)   (int cpu, unsigned int *limit);  // show the current cpufreq HW/BIOS limitation

    int (*exit)     (struct cpufreq_policy *policy); //A pointer to a per-CPU cleanup function
    int (*suspend)  (struct cpufreq_policy *policy);//  re-evaluate an existing cpufreq policy //cpufreq_update_policy中用到了
    int (*resume)   (struct cpufreq_policy *policy);//A pointer to a per-CPU resume function which is called with interrupts disabled
                 //and _before_ the pre-suspend frequency and/or policy is restored by a call to ->target or ->setpolicy                  
    struct freq_attr    **attr; //A pointer to a NULL-terminated list of "struct freq_attr" which allow to export values to sysfs.
};

 
  static struct cpufreq_driver *cpufreq_driver; //<-------------------------------------------<<<<<<<<<<<<<driver 的统一调用接口???
  static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); //存放了每个cpu的当前policy结构的指针
  static DEFINE_SPINLOCK(cpufreq_driver_lock); //用来保护cpufreq_driver结构
 
  /*
 * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
 * all cpufreq/hotplug/workqueue/etc related lock issues.
 *
 * The rules for this semaphore:
 * - Any routine that wants to read from the policy structure will
 *   do a down_read on this semaphore.
 * - Any routine that will write to the policy structure and/or may take away
 *   the policy altogether (eg. CPU hotplug), will hold this lock in write
 *   mode before doing so.
 *
 * Additional rules:
 * - All holders of the lock should check to make sure that the CPU they
 *   are concerned with are online after they get the lock.
 * - Governor routines that can be called in cpufreq hotplug path should not
 *   take this sem as top level hotplug notifier handler takes this.
 * - Lock should not be held across
 *     __cpufreq_governor(data, CPUFREQ_GOV_STOP);
 */
static DEFINE_PER_CPU(int, cpufreq_policy_cpu); // policy cpu, 设置policy时所在的cpu
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);

--------------------------------------------------------------------------------------------------------
  ------------------------------------------ 关于for_each_possible_cpu
      for_each_possible_cpu(cpu) {
        per_cpu(cpufreq_policy_cpu, cpu) = -1;//对cpufreq_policy_cpu赋值为-1
        init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));//初始化semaphore
    }

//添加一个 for头和一个struct cpumask类型的变量cpu_possible_mask,该变量用于?????
//
#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)

/**
 * for_each_cpu - iterate over every cpu in a mask
 * @cpu: the (optionally unsigned) integer iterator
 * @mask: the cpumask pointer
 *
 * After the loop, cpu is >= nr_cpu_ids.
 */
#define for_each_cpu(cpu, mask)             \
    for ((cpu) = -1;                \
        (cpu) = cpumask_next((cpu), (mask)),    \
        (cpu) < nr_cpu_ids;)

/**
 * cpumask_next - get the next cpu in a cpumask
 * @n: the cpu prior to the place to search (ie. return will be > @n)
 * @srcp: the cpumask pointer
 *
 * Returns >= nr_cpu_ids if no further cpus set.
 */
static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
{
    /* -1 is a legal arg here. */
    if (n != -1)
        cpumask_check(n);
    return find_next_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
}

/* verify cpu argument to cpumask_* operators */
static inline unsigned int cpumask_check(unsigned int cpu)
{
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    WARN_ON_ONCE(cpu >= nr_cpumask_bits);
#endif /* CONFIG_DEBUG_PER_CPU_MAPS */
    return cpu;
}
/*
 * Find the next set bit in a memory region.
 */
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
                unsigned long offset)
{
    const unsigned long *p = addr + BITOP_WORD(offset);
    unsigned long result = offset & ~(BITS_PER_LONG-1);
    unsigned long tmp;

    if (offset >= size)
        return size;
    size -= result;
    offset %= BITS_PER_LONG;
    if (offset) {
        tmp = *(p++);
        tmp &= (~0UL << offset);
        if (size < BITS_PER_LONG)
            goto found_first;
        if (tmp)
            goto found_middle;
        size -= BITS_PER_LONG;
        result += BITS_PER_LONG;
    }
    while (size & ~(BITS_PER_LONG-1)) {
        if ((tmp = *(p++)))
            goto found_middle;
        result += BITS_PER_LONG;
        size -= BITS_PER_LONG;
    }
    if (!size)
        return result;
    tmp = *p;

found_first:
    tmp &= (~0UL >> (BITS_PER_LONG - size));
    if (tmp == 0UL)     /* Are any bits set? */
        return result + size;   /* Nope. */
found_middle:
    return result + __ffs(tmp);
}

    
//创建一个能容纳CONFIG_NR_CPUS个bit位的long类型的数组,并转为为struct cpumask
//类型返回给cpu_possible_mask
//总之,就是得到cpu_possible_mask,它是一个struct cpumask类型
const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);


//to_cpumask 把数组bitmap转化为struct cpumask类型
#define to_cpumask(bitmap)                      \
    ((struct cpumask *)(1 ? (bitmap)                \
                : (void *)sizeof(__check_is_bitmap(bitmap))))
    
static inline int __check_is_bitmap(const unsigned long *bitmap)
{
    return 1;
}

typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;//结构体cpumask含有一个成员,
                                                                                  //该成员是一个能够容纳bits个bit位的名为name的long类型的数组

#define DECLARE_BITMAP(name,bits) \            //创建一个能够容纳bits个bit位的名为name的long类型的数组
    unsigned long name[BITS_TO_LONGS(bits)]
    --------------------------------------
   #define BITS_TO_LONGS(nr)   DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) //取得bit数除以long所占的bit数的向上取整

#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))

#define BITS_PER_BYTE 8
----  
 // cpu_possible_bits是一个long类型数组   
 #ifdef CONFIG_INIT_ALL_POSSIBLE
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly
    = CPU_BITS_ALL;
#else
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
#endif

----------per_cpu //取得per cpu变量 var在CPU号cpu上的副本
/*
 * A percpu variable may point to a discarded regions. The following are
 * established ways to produce a usable pointer from the percpu variable
 * offset.   
 */
#define per_cpu(var, cpu) \
    (*SHIFT_PERCPU_PTR(&(var), per_cpu_offset(cpu)))
/*
 * Add a offset to a pointer but keep the pointer as is.
 *
 * Only S390 provides its own means of moving the pointer.
 */
/* Weird cast keeps both GCC and sparse happy. */
#define SHIFT_PERCPU_PTR(__p, __offset) ({              \
    __verify_pcpu_ptr((__p));                   \
    RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)); \
})
/*
 * This macro obfuscates arithmetic on a variable address so that gcc
 * shouldn't recognize the original var, and make assumptions about it.
 *
 * This is needed because the C standard makes it undefined to do
 * pointer arithmetic on "objects" outside their boundaries and the
 * gcc optimizers assume this is the case. In particular they
 * assume such arithmetic does not wrap.
 *
 * A miscompilation has been observed because of this on PPC.
 * To work around it we hide the relationship of the pointer and the object
 * using this macro.
 *
 * Versions of the ppc64 compiler before 4.1 had a bug where use of
 * RELOC_HIDE could trash r30. The bug can be worked around by changing
 * the inline assembly constraint from =g to =r, in this particular
 * case either is valid.
 */                                              
#define RELOC_HIDE(ptr, off)     \  //
   ({ unsigned long __ptr;     \
     __asm__ ("" : "=r"(__ptr) : "0"(ptr));   \
     (typeof(ptr)) (__ptr + (off)); })
 
 
/*
 * per_cpu_offset() is the offset that has to be added to a <------------------<<<<< per_cpu_offset
 * percpu variable to get to the instance for a certain processor.
 *
 * Most arches use the __per_cpu_offset array for those offsets but
 * some arches have their own ways of determining the offset (x86_64, s390).
 */
extern unsigned long __per_cpu_offset[NR_CPUS];
#define per_cpu_offset(x) (__per_cpu_offset[x])
 
  /// x86_64
 
#include <asm/trap_block.h>

#define __per_cpu_offset(__cpu) \
    (trap_block[(__cpu)].__per_cpu_base)
#define per_cpu_offset(x) (__per_cpu_offset(x))
#define __my_cpu_offset __local_per_cpu_offset
 
 struct trap_per_cpu trap_block[NR_CPUS];
 ///end of x86_64
 --------------------------------- for_each_present_cpu     //添加一个 for头和一个struct cpumask类型的变量 cpu_present_mask,该变量用于?????
 #define for_each_present_cpu(cpu)  for_each_cpu((cpu), cpu_present_mask)
 
 //总之,就是得到cpu_present_mask,它是一个struct cpumask类型
 static DECLARE_BITMAP(cpu_present_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_present_mask = to_cpumask(cpu_present_bits);

----------------  cpu_online(cpu)   //检查cpu号CPU是否可以调度(检查cpu是否在cpu_online_mask中)

/*
 * The following particular system cpumasks and operations manage
 * possible, present, active and online cpus.
 *
 *     cpu_possible_mask- has bit 'cpu' set iff cpu is populatable
 *     cpu_present_mask - has bit 'cpu' set iff cpu is populated
 *     cpu_online_mask  - has bit 'cpu' set iff cpu available to scheduler
 *     cpu_active_mask  - has bit 'cpu' set iff cpu available to migration
 *
 *  If !CONFIG_HOTPLUG_CPU, present == possible, and active == online.
 *
 *  The cpu_possible_mask is fixed at boot time, as the set of CPU id's
 *  that it is possible might ever be plugged in at anytime during the
 *  life of that system boot.  The cpu_present_mask is dynamic(*),
 *  representing which CPUs are currently plugged in.  And
 *  cpu_online_mask is the dynamic subset of cpu_present_mask,
 *  indicating those CPUs available for scheduling.
 *
 *  If HOTPLUG is enabled, then cpu_possible_mask is forced to have
 *  all NR_CPUS bits set, otherwise it is just the set of CPUs that
 *  ACPI reports present at boot.
 *
 *  If HOTPLUG is enabled, then cpu_present_mask varies dynamically,
 *  depending on what ACPI reports as currently plugged in, otherwise
 *  cpu_present_mask is just a copy of cpu_possible_mask.
 *
 *  (*) Well, cpu_present_mask is dynamic in the hotplug case.  If not
 *      hotplug, it's a copy of cpu_possible_mask, hence fixed at boot.
 *
 * Subtleties:
 * 1) UP arch's (NR_CPUS == 1, CONFIG_SMP not defined) hardcode
 *    assumption that their single CPU is online.  The UP
 *    cpu_{online,possible,present}_masks are placebos.  Changing them
 *    will have no useful affect on the following num_*_cpus()
 *    and cpu_*() macros in the UP case.  This ugliness is a UP
 *    optimization - don't waste any instructions or memory references
 *    asking if you're online or how many CPUs there are if there is
 *    only one CPU.
 */



#define cpu_online(cpu)     cpumask_test_cpu((cpu), cpu_online_mask)//检查cpu是否在cpu_online_mask中
typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;//结构体cpumask含有一个成员,
                                                                                  //该成员是一个能够容纳bits个bit位的名为bits的long类型的数组

static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits);

/**
 * cpumask_test_cpu - test for a cpu in a cpumask //得到struct cpumask的bits域
 * @cpu: cpu number (< nr_cpu_ids)
 * @cpumask: the cpumask pointer
 *
 * No static inline type checking - see Subtlety (1) above.
 */
#define cpumask_test_cpu(cpu, cpumask) \
    test_bit(cpumask_check(cpu), cpumask_bits((cpumask)))//如果小于cpu值小于CPU个数,得到struct cpumask 的bits域

//确保cpu值是有效的,即小于CPU个数,返回值为cpu
/* verify cpu argument to cpumask_* operators */
static inline unsigned int cpumask_check(unsigned int cpu)
{
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    WARN_ON_ONCE(cpu >= nr_cpumask_bits); //确保cpu小于的CPU个数
#endif /* CONFIG_DEBUG_PER_CPU_MAPS */
    return cpu;
}    

/**
 * cpumask_bits - get the bits in a cpumask
 * @maskp: the struct cpumask *
 *
 * You should only assume nr_cpu_ids bits of this mask are valid.  This is
 * a macro so it's const-correct.
 */
#define cpumask_bits(maskp) ((maskp)->bits)


// 总之,nr_cpumask_bits 数值跟 NR_CPUS相同
#ifdef CONFIG_CPUMASK_OFFSTACK//Use dynamic allocation for cpumask_var_t, instead of putting them on the stack.
/* Assuming NR_CPUS is huge, a runtime limit is more efficient.  Also,
 * not all bits may be allocated. */
#define nr_cpumask_bits nr_cpu_ids //如果动态分配cpumask_var_t
#else
#define nr_cpumask_bits NR_CPUS //如果在栈上分配cpumask_var_t
#endif
------------------------test_bit
//如果addr的nr位为1,则返回1,否则,返回0
#define test_bit(nr,addr) \  
(__builtin_constant_p(nr) ? \   //如果是内建常量?????
 constant_test_bit((nr),(addr)) : \ //如果addr的nr位为1,则返回1,否则,返回0
 variable_test_bit((nr),(addr)))

//如果addr的nr位为1,则返回1,否则,返回0
static __always_inline int constant_test_bit(unsigned int nr, const volatile unsigned long *addr)
{   
    return ((1UL << (nr % BITS_PER_LONG)) &
        (addr[nr / BITS_PER_LONG])) != 0;
}

static inline int variable_test_bit(int nr, volatile const unsigned long *addr)
{
    int oldbit;
        
    asm volatile("bt %2,%1\n\t" //把 addr中指定的nr位的内容送到CF
             "sbb %0,%0" //带借位减法,CF - 0 => oldbit
             : "=r" (oldbit)
             : "m" (*(unsigned long *)addr), "Ir" (nr));
    
    return oldbit;
}


  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值