我们看一个注册cpufreq_register_driver 的例子.先看makefile。只要定义了 CONFIG_X86_CPUFREQ_NFORCE2。就会build 出cpufreq-nforce2.o,我们就以它为例
42 obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
果然在init函数中调用cpufreq_register_driver
416 static int __init nforce2_init(void)
417 {
418 /* TODO: do we need to detect the processor? */
419
420 /* detect chipset */
421 if (nforce2_detect_chipset()) {
422 pr_info("No nForce2 chipset\n");
423 return -ENODEV;
424 }
425
426 return cpufreq_register_driver(&nforce2_driver);
427 }
我们来看看nforce2_driver
370 static struct cpufreq_driver nforce2_driver = {
371 .name = "nforce2",
372 .verify = nforce2_verify,
373 .target = nforce2_target,
374 .get = nforce2_get,
375 .init = nforce2_cpu_init,
376 .exit = nforce2_cpu_exit,
377 };
在使用中会调用__cpufreq_driver_target 来设定频率。这个函数target方法或者target_index 来将freq设定到cpu的寄存器中。对这点不明白可以参考前面的博文.
在本例中实现了target方法.
在调用target之前会调用init方法,init方法就给出了cpu 这里支持的最大和最小频率。如358行359所示.
309 static int nforce2_cpu_init(struct cpufreq_policy *policy)
310 {
356
357 /* cpuinfo and default policy values */
358 policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100;
359 policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100;
360 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
361
362 return 0;
363 }
其次看看target是如何设定freq的
252 static int nforce2_target(struct cpufreq_policy *policy,
253 unsigned int target_freq, unsigned int relation)
254 {
255 /* unsigned long flags; */
256 struct cpufreq_freqs freqs;
257 unsigned int target_fsb;
258
259 if ((target_freq > policy->max) || (target_freq < policy->min))
260 return -EINVAL;
261
262 target_fsb = target_freq / (fid * 100);
263
264 freqs.old = nforce2_get(policy->cpu);
265 freqs.new = target_fsb * fid * 100;
266
267 if (freqs.old == freqs.new)
268 return 0;
269
270 pr_debug("Old CPU frequency %d kHz, new %d kHz\n",
271 freqs.old, freqs.new);
272
273 cpufreq_freq_transition_begin(policy, &freqs);
274
275 /* Disable IRQs */
276 /* local_irq_save(flags); */
277
278 if (nforce2_set_fsb(target_fsb) < 0)
279 pr_err("Changing FSB to %d failed\n", target_fsb);
280 else
281 pr_debug("Changed FSB successfully to %d\n",
282 target_fsb);
283
284 /* Enable IRQs */
285 /* local_irq_restore(flags); */
286
287 cpufreq_freq_transition_end(policy, &freqs, 0);
288
289 return 0;
290 }
在262上所处 target_fsb = target_freq / (fid * 100);
可以看到是通过nforce2_set_fsb(target_fsb)来设定的频率的。
169 static int nforce2_set_fsb(unsigned int fsb)
170 {
171 u32 temp = 0;
172 unsigned int tfsb;
173 int diff;
174 int pll = 0;
175
176 if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) {
177 pr_err("FSB %d is out of range!\n", fsb);
178 return -EINVAL;
179 }
180
181 tfsb = nforce2_fsb_read(0);
182 if (!tfsb) {
183 pr_err("Error while reading the FSB\n");
184 return -EINVAL;
185 }
186
187 /* First write? Then set actual value */
188 pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
189 if (!temp) {
190 pll = nforce2_calc_pll(tfsb);
191
192 if (pll < 0)
193 return -EINVAL;
194
195 nforce2_write_pll(pll);
196 }
197
198 /* Enable write access */
199 temp = 0x01;
200 pci_write_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8)temp);
201
202 diff = tfsb - fsb;
203
204 if (!diff)
205 return 0;
206
207 while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) {
208 if (diff < 0)
209 tfsb++;
210 else
211 tfsb--;
212
213 /* Calculate the PLL reg. value */
214 pll = nforce2_calc_pll(tfsb);
215 if (pll == -1)
216 return -EINVAL;
217
218 nforce2_write_pll(pll);
219 #ifdef NFORCE2_DELAY
220 mdelay(NFORCE2_DELAY);
221 #endif
222 }
223
224 temp = 0x40;
225 pci_write_config_byte(nforce2_dev, NFORCE2_PLLADR, (u8)temp);
226
227 return 0;
228 }
229
从214行可以看出在这个例子中是将通过nforce2_calc_pll将freq转成成pll 通过调用nforce2_write_pll来设定到pll寄存器中的
116 static void nforce2_write_pll(int pll)
117 {
118 int temp;
119
120 /* Set the pll addr. to 0x00 */
121 pci_write_config_dword(nforce2_dev, NFORCE2_PLLADR, 0);
122
123 /* Now write the value in all 64 registers */
124 for (temp = 0; temp <= 0x3f; temp++)
125 pci_write_config_dword(nforce2_dev, NFORCE2_PLLREG, pll);
126
127 return;
128 }
哈哈,125行终于看见真的是在写寄存器了吧
42 obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
果然在init函数中调用cpufreq_register_driver
416 static int __init nforce2_init(void)
417 {
418 /* TODO: do we need to detect the processor? */
419
420 /* detect chipset */
421 if (nforce2_detect_chipset()) {
422 pr_info("No nForce2 chipset\n");
423 return -ENODEV;
424 }
425
426 return cpufreq_register_driver(&nforce2_driver);
427 }
我们来看看nforce2_driver
370 static struct cpufreq_driver nforce2_driver = {
371 .name = "nforce2",
372 .verify = nforce2_verify,
373 .target = nforce2_target,
374 .get = nforce2_get,
375 .init = nforce2_cpu_init,
376 .exit = nforce2_cpu_exit,
377 };
在使用中会调用__cpufreq_driver_target 来设定频率。这个函数target方法或者target_index 来将freq设定到cpu的寄存器中。对这点不明白可以参考前面的博文.
在本例中实现了target方法.
在调用target之前会调用init方法,init方法就给出了cpu 这里支持的最大和最小频率。如358行359所示.
309 static int nforce2_cpu_init(struct cpufreq_policy *policy)
310 {
356
357 /* cpuinfo and default policy values */
358 policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100;
359 policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100;
360 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
361
362 return 0;
363 }
其次看看target是如何设定freq的
252 static int nforce2_target(struct cpufreq_policy *policy,
253 unsigned int target_freq, unsigned int relation)
254 {
255 /* unsigned long flags; */
256 struct cpufreq_freqs freqs;
257 unsigned int target_fsb;
258
259 if ((target_freq > policy->max) || (target_freq < policy->min))
260 return -EINVAL;
261
262 target_fsb = target_freq / (fid * 100);
263
264 freqs.old = nforce2_get(policy->cpu);
265 freqs.new = target_fsb * fid * 100;
266
267 if (freqs.old == freqs.new)
268 return 0;
269
270 pr_debug("Old CPU frequency %d kHz, new %d kHz\n",
271 freqs.old, freqs.new);
272
273 cpufreq_freq_transition_begin(policy, &freqs);
274
275 /* Disable IRQs */
276 /* local_irq_save(flags); */
277
278 if (nforce2_set_fsb(target_fsb) < 0)
279 pr_err("Changing FSB to %d failed\n", target_fsb);
280 else
281 pr_debug("Changed FSB successfully to %d\n",
282 target_fsb);
283
284 /* Enable IRQs */
285 /* local_irq_restore(flags); */
286
287 cpufreq_freq_transition_end(policy, &freqs, 0);
288
289 return 0;
290 }
在262上所处 target_fsb = target_freq / (fid * 100);
可以看到是通过nforce2_set_fsb(target_fsb)来设定的频率的。
169 static int nforce2_set_fsb(unsigned int fsb)
170 {
171 u32 temp = 0;
172 unsigned int tfsb;
173 int diff;
174 int pll = 0;
175
176 if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) {
177 pr_err("FSB %d is out of range!\n", fsb);
178 return -EINVAL;
179 }
180
181 tfsb = nforce2_fsb_read(0);
182 if (!tfsb) {
183 pr_err("Error while reading the FSB\n");
184 return -EINVAL;
185 }
186
187 /* First write? Then set actual value */
188 pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
189 if (!temp) {
190 pll = nforce2_calc_pll(tfsb);
191
192 if (pll < 0)
193 return -EINVAL;
194
195 nforce2_write_pll(pll);
196 }
197
198 /* Enable write access */
199 temp = 0x01;
200 pci_write_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8)temp);
201
202 diff = tfsb - fsb;
203
204 if (!diff)
205 return 0;
206
207 while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) {
208 if (diff < 0)
209 tfsb++;
210 else
211 tfsb--;
212
213 /* Calculate the PLL reg. value */
214 pll = nforce2_calc_pll(tfsb);
215 if (pll == -1)
216 return -EINVAL;
217
218 nforce2_write_pll(pll);
219 #ifdef NFORCE2_DELAY
220 mdelay(NFORCE2_DELAY);
221 #endif
222 }
223
224 temp = 0x40;
225 pci_write_config_byte(nforce2_dev, NFORCE2_PLLADR, (u8)temp);
226
227 return 0;
228 }
229
从214行可以看出在这个例子中是将通过nforce2_calc_pll将freq转成成pll 通过调用nforce2_write_pll来设定到pll寄存器中的
116 static void nforce2_write_pll(int pll)
117 {
118 int temp;
119
120 /* Set the pll addr. to 0x00 */
121 pci_write_config_dword(nforce2_dev, NFORCE2_PLLADR, 0);
122
123 /* Now write the value in all 64 registers */
124 for (temp = 0; temp <= 0x3f; temp++)
125 pci_write_config_dword(nforce2_dev, NFORCE2_PLLREG, pll);
126
127 return;
128 }
哈哈,125行终于看见真的是在写寄存器了吧