speedstep-ich.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /*
  2. * (C) 2001 Dave Jones, Arjan van de ven.
  3. * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
  4. *
  5. * Licensed under the terms of the GNU GPL License version 2.
  6. * Based upon reverse engineered information, and on Intel documentation
  7. * for chipsets ICH2-M and ICH3-M.
  8. *
  9. * Many thanks to Ducrot Bruno for finding and fixing the last
  10. * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler
  11. * for extensive testing.
  12. *
  13. * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
  14. */
  15. /*********************************************************************
  16. * SPEEDSTEP - DEFINITIONS *
  17. *********************************************************************/
  18. #include <linux/kernel.h>
  19. #include <linux/module.h>
  20. #include <linux/init.h>
  21. #include <linux/cpufreq.h>
  22. #include <linux/pci.h>
  23. #include <linux/slab.h>
  24. #include "speedstep-lib.h"
  25. /* speedstep_chipset:
  26. * It is necessary to know which chipset is used. As accesses to
  27. * this device occur at various places in this module, we need a
  28. * static struct pci_dev * pointing to that device.
  29. */
  30. static struct pci_dev *speedstep_chipset_dev;
  31. /* speedstep_processor
  32. */
  33. static unsigned int speedstep_processor = 0;
  34. /*
  35. * There are only two frequency states for each processor. Values
  36. * are in kHz for the time being.
  37. */
  38. static struct cpufreq_frequency_table speedstep_freqs[] = {
  39. {SPEEDSTEP_HIGH, 0},
  40. {SPEEDSTEP_LOW, 0},
  41. {0, CPUFREQ_TABLE_END},
  42. };
  43. #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-ich", msg)
  44. /**
  45. * speedstep_set_state - set the SpeedStep state
  46. * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
  47. *
  48. * Tries to change the SpeedStep state.
  49. */
  50. static void speedstep_set_state (unsigned int state)
  51. {
  52. u32 pmbase;
  53. u8 pm2_blk;
  54. u8 value;
  55. unsigned long flags;
  56. if (!speedstep_chipset_dev || (state > 0x1))
  57. return;
  58. /* get PMBASE */
  59. pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
  60. if (!(pmbase & 0x01)) {
  61. printk(KERN_ERR "speedstep-ich: could not find speedstep register\n");
  62. return;
  63. }
  64. pmbase &= 0xFFFFFFFE;
  65. if (!pmbase) {
  66. printk(KERN_ERR "speedstep-ich: could not find speedstep register\n");
  67. return;
  68. }
  69. /* Disable IRQs */
  70. local_irq_save(flags);
  71. /* read state */
  72. value = inb(pmbase + 0x50);
  73. dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
  74. /* write new state */
  75. value &= 0xFE;
  76. value |= state;
  77. dprintk("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
  78. /* Disable bus master arbitration */
  79. pm2_blk = inb(pmbase + 0x20);
  80. pm2_blk |= 0x01;
  81. outb(pm2_blk, (pmbase + 0x20));
  82. /* Actual transition */
  83. outb(value, (pmbase + 0x50));
  84. /* Restore bus master arbitration */
  85. pm2_blk &= 0xfe;
  86. outb(pm2_blk, (pmbase + 0x20));
  87. /* check if transition was successful */
  88. value = inb(pmbase + 0x50);
  89. /* Enable IRQs */
  90. local_irq_restore(flags);
  91. dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
  92. if (state == (value & 0x1)) {
  93. dprintk("change to %u MHz succeeded\n", (speedstep_get_processor_frequency(speedstep_processor) / 1000));
  94. } else {
  95. printk (KERN_ERR "cpufreq: change failed - I/O error\n");
  96. }
  97. return;
  98. }
  99. /**
  100. * speedstep_activate - activate SpeedStep control in the chipset
  101. *
  102. * Tries to activate the SpeedStep status and control registers.
  103. * Returns -EINVAL on an unsupported chipset, and zero on success.
  104. */
  105. static int speedstep_activate (void)
  106. {
  107. u16 value = 0;
  108. if (!speedstep_chipset_dev)
  109. return -EINVAL;
  110. pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value);
  111. if (!(value & 0x08)) {
  112. value |= 0x08;
  113. dprintk("activating SpeedStep (TM) registers\n");
  114. pci_write_config_word(speedstep_chipset_dev, 0x00A0, value);
  115. }
  116. return 0;
  117. }
  118. /**
  119. * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic
  120. *
  121. * Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to
  122. * the LPC bridge / PM module which contains all power-management
  123. * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
  124. * chipset, or zero on failure.
  125. */
  126. static unsigned int speedstep_detect_chipset (void)
  127. {
  128. speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
  129. PCI_DEVICE_ID_INTEL_82801DB_12,
  130. PCI_ANY_ID,
  131. PCI_ANY_ID,
  132. NULL);
  133. if (speedstep_chipset_dev)
  134. return 4; /* 4-M */
  135. speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
  136. PCI_DEVICE_ID_INTEL_82801CA_12,
  137. PCI_ANY_ID,
  138. PCI_ANY_ID,
  139. NULL);
  140. if (speedstep_chipset_dev)
  141. return 3; /* 3-M */
  142. speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
  143. PCI_DEVICE_ID_INTEL_82801BA_10,
  144. PCI_ANY_ID,
  145. PCI_ANY_ID,
  146. NULL);
  147. if (speedstep_chipset_dev) {
  148. /* speedstep.c causes lockups on Dell Inspirons 8000 and
  149. * 8100 which use a pretty old revision of the 82815
  150. * host brige. Abort on these systems.
  151. */
  152. static struct pci_dev *hostbridge;
  153. u8 rev = 0;
  154. hostbridge = pci_get_subsys(PCI_VENDOR_ID_INTEL,
  155. PCI_DEVICE_ID_INTEL_82815_MC,
  156. PCI_ANY_ID,
  157. PCI_ANY_ID,
  158. NULL);
  159. if (!hostbridge)
  160. return 2; /* 2-M */
  161. pci_read_config_byte(hostbridge, PCI_REVISION_ID, &rev);
  162. if (rev < 5) {
  163. dprintk("hostbridge does not support speedstep\n");
  164. speedstep_chipset_dev = NULL;
  165. pci_dev_put(hostbridge);
  166. return 0;
  167. }
  168. pci_dev_put(hostbridge);
  169. return 2; /* 2-M */
  170. }
  171. return 0;
  172. }
  173. static unsigned int _speedstep_get(cpumask_t cpus)
  174. {
  175. unsigned int speed;
  176. cpumask_t cpus_allowed;
  177. cpus_allowed = current->cpus_allowed;
  178. set_cpus_allowed(current, cpus);
  179. speed = speedstep_get_processor_frequency(speedstep_processor);
  180. set_cpus_allowed(current, cpus_allowed);
  181. dprintk("detected %u kHz as current frequency\n", speed);
  182. return speed;
  183. }
  184. static unsigned int speedstep_get(unsigned int cpu)
  185. {
  186. return _speedstep_get(cpumask_of_cpu(cpu));
  187. }
  188. /**
  189. * speedstep_target - set a new CPUFreq policy
  190. * @policy: new policy
  191. * @target_freq: the target frequency
  192. * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
  193. *
  194. * Sets a new CPUFreq policy.
  195. */
  196. static int speedstep_target (struct cpufreq_policy *policy,
  197. unsigned int target_freq,
  198. unsigned int relation)
  199. {
  200. unsigned int newstate = 0;
  201. struct cpufreq_freqs freqs;
  202. cpumask_t cpus_allowed;
  203. int i;
  204. if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
  205. return -EINVAL;
  206. freqs.old = _speedstep_get(policy->cpus);
  207. freqs.new = speedstep_freqs[newstate].frequency;
  208. freqs.cpu = policy->cpu;
  209. dprintk("transiting from %u to %u kHz\n", freqs.old, freqs.new);
  210. /* no transition necessary */
  211. if (freqs.old == freqs.new)
  212. return 0;
  213. cpus_allowed = current->cpus_allowed;
  214. for_each_cpu_mask(i, policy->cpus) {
  215. freqs.cpu = i;
  216. cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
  217. }
  218. /* switch to physical CPU where state is to be changed */
  219. set_cpus_allowed(current, policy->cpus);
  220. speedstep_set_state(newstate);
  221. /* allow to be run on all CPUs */
  222. set_cpus_allowed(current, cpus_allowed);
  223. for_each_cpu_mask(i, policy->cpus) {
  224. freqs.cpu = i;
  225. cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
  226. }
  227. return 0;
  228. }
  229. /**
  230. * speedstep_verify - verifies a new CPUFreq policy
  231. * @policy: new policy
  232. *
  233. * Limit must be within speedstep_low_freq and speedstep_high_freq, with
  234. * at least one border included.
  235. */
  236. static int speedstep_verify (struct cpufreq_policy *policy)
  237. {
  238. return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
  239. }
  240. static int speedstep_cpu_init(struct cpufreq_policy *policy)
  241. {
  242. int result = 0;
  243. unsigned int speed;
  244. cpumask_t cpus_allowed;
  245. /* only run on CPU to be set, or on its sibling */
  246. #ifdef CONFIG_SMP
  247. policy->cpus = cpu_sibling_map[policy->cpu];
  248. #endif
  249. cpus_allowed = current->cpus_allowed;
  250. set_cpus_allowed(current, policy->cpus);
  251. /* detect low and high frequency */
  252. result = speedstep_get_freqs(speedstep_processor,
  253. &speedstep_freqs[SPEEDSTEP_LOW].frequency,
  254. &speedstep_freqs[SPEEDSTEP_HIGH].frequency,
  255. &speedstep_set_state);
  256. set_cpus_allowed(current, cpus_allowed);
  257. if (result)
  258. return result;
  259. /* get current speed setting */
  260. speed = _speedstep_get(policy->cpus);
  261. if (!speed)
  262. return -EIO;
  263. dprintk("currently at %s speed setting - %i MHz\n",
  264. (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high",
  265. (speed / 1000));
  266. /* cpuinfo and default policy values */
  267. policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
  268. policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
  269. policy->cur = speed;
  270. result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
  271. if (result)
  272. return (result);
  273. cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
  274. return 0;
  275. }
  276. static int speedstep_cpu_exit(struct cpufreq_policy *policy)
  277. {
  278. cpufreq_frequency_table_put_attr(policy->cpu);
  279. return 0;
  280. }
  281. static struct freq_attr* speedstep_attr[] = {
  282. &cpufreq_freq_attr_scaling_available_freqs,
  283. NULL,
  284. };
  285. static struct cpufreq_driver speedstep_driver = {
  286. .name = "speedstep-ich",
  287. .verify = speedstep_verify,
  288. .target = speedstep_target,
  289. .init = speedstep_cpu_init,
  290. .exit = speedstep_cpu_exit,
  291. .get = speedstep_get,
  292. .owner = THIS_MODULE,
  293. .attr = speedstep_attr,
  294. };
  295. /**
  296. * speedstep_init - initializes the SpeedStep CPUFreq driver
  297. *
  298. * Initializes the SpeedStep support. Returns -ENODEV on unsupported
  299. * devices, -EINVAL on problems during initiatization, and zero on
  300. * success.
  301. */
  302. static int __init speedstep_init(void)
  303. {
  304. /* detect processor */
  305. speedstep_processor = speedstep_detect_processor();
  306. if (!speedstep_processor) {
  307. dprintk("Intel(R) SpeedStep(TM) capable processor not found\n");
  308. return -ENODEV;
  309. }
  310. /* detect chipset */
  311. if (!speedstep_detect_chipset()) {
  312. dprintk("Intel(R) SpeedStep(TM) for this chipset not (yet) available.\n");
  313. return -ENODEV;
  314. }
  315. /* activate speedstep support */
  316. if (speedstep_activate()) {
  317. pci_dev_put(speedstep_chipset_dev);
  318. return -EINVAL;
  319. }
  320. return cpufreq_register_driver(&speedstep_driver);
  321. }
  322. /**
  323. * speedstep_exit - unregisters SpeedStep support
  324. *
  325. * Unregisters SpeedStep support.
  326. */
  327. static void __exit speedstep_exit(void)
  328. {
  329. pci_dev_put(speedstep_chipset_dev);
  330. cpufreq_unregister_driver(&speedstep_driver);
  331. }
  332. MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>, Dominik Brodowski <linux@brodo.de>");
  333. MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors on chipsets with ICH-M southbridges.");
  334. MODULE_LICENSE ("GPL");
  335. module_init(speedstep_init);
  336. module_exit(speedstep_exit);