cregit-Linux how code gets into the kernel

Release 4.14 drivers/cpufreq/cpufreq-nforce2.c

Directory: drivers/cpufreq
/*
 * (C) 2004-2006  Sebastian Witt <se.witt@gmx.net>
 *
 *  Licensed under the terms of the GNU GPL License version 2.
 *  Based upon reverse engineered information
 *
 *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/pci.h>
#include <linux/delay.h>


#define NFORCE2_XTAL 25

#define NFORCE2_BOOTFSB 0x48

#define NFORCE2_PLLENABLE 0xa8

#define NFORCE2_PLLREG 0xa4

#define NFORCE2_PLLADR 0xa0

#define NFORCE2_PLL(mul, div) (0x100000 | (mul << 8) | div)


#define NFORCE2_MIN_FSB 50

#define NFORCE2_SAFE_DISTANCE 50

/* Delay in ms between FSB changes */
/* #define NFORCE2_DELAY 10 */

/*
 * nforce2_chipset:
 * FSB is changed using the chipset
 */

static struct pci_dev *nforce2_dev;

/* fid:
 * multiplier * 10
 */

static int fid;

/* min_fsb, max_fsb:
 * minimum and maximum FSB (= FSB at boot time)
 */

static int min_fsb;

static int max_fsb;

MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
MODULE_DESCRIPTION("nForce2 FSB changing cpufreq driver");
MODULE_LICENSE("GPL");

module_param(fid, int, 0444);
module_param(min_fsb, int, 0444);

MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
MODULE_PARM_DESC(min_fsb,
		"Minimum FSB to use, if not defined: current FSB - 50");

/**
 * nforce2_calc_fsb - calculate FSB
 * @pll: PLL value
 *
 *   Calculates FSB from PLL value
 */

static int nforce2_calc_fsb(int pll) { unsigned char mul, div; mul = (pll >> 8) & 0xff; div = pll & 0xff; if (div > 0) return NFORCE2_XTAL * mul / div; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones47100.00%1100.00%
Total47100.00%1100.00%

/** * nforce2_calc_pll - calculate PLL value * @fsb: FSB * * Calculate PLL value for given FSB */
static int nforce2_calc_pll(unsigned int fsb) { unsigned char xmul, xdiv; unsigned char mul = 0, div = 0; int tried = 0; /* Try to calculate multiplier and divider up to 4 times */ while (((mul == 0) || (div == 0)) && (tried <= 3)) { for (xdiv = 2; xdiv <= 0x80; xdiv++) for (xmul = 1; xmul <= 0xfe; xmul++) if (nforce2_calc_fsb(NFORCE2_PLL(xmul, xdiv)) == fsb + tried) { mul = xmul; div = xdiv; } tried++; } if ((mul == 0) || (div == 0)) return -1; return NFORCE2_PLL(mul, div); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones137100.00%2100.00%
Total137100.00%2100.00%

/** * nforce2_write_pll - write PLL value to chipset * @pll: PLL value * * Writes new FSB PLL value to chipset */
static void nforce2_write_pll(int pll) { int temp; /* Set the pll addr. to 0x00 */ pci_write_config_dword(nforce2_dev, NFORCE2_PLLADR, 0); /* Now write the value in all 64 registers */ for (temp = 0; temp <= 0x3f; temp++) pci_write_config_dword(nforce2_dev, NFORCE2_PLLREG, pll); return; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones46100.00%3100.00%
Total46100.00%3100.00%

/** * nforce2_fsb_read - Read FSB * * Read FSB from chipset * If bootfsb != 0, return FSB at boot-time */
static unsigned int nforce2_fsb_read(int bootfsb) { struct pci_dev *nforce2_sub5; u32 fsb, temp = 0; /* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */ nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, 0x01EF, PCI_ANY_ID, PCI_ANY_ID, NULL); if (!nforce2_sub5) return 0; pci_read_config_dword(nforce2_sub5, NFORCE2_BOOTFSB, &fsb); fsb /= 1000000; /* Check if PLL register is already set */ pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp); if (bootfsb || !temp) return fsb; /* Use PLL register FSB value */ pci_read_config_dword(nforce2_dev, NFORCE2_PLLREG, &temp); fsb = nforce2_calc_fsb(temp); return fsb; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones106100.00%2100.00%
Total106100.00%2100.00%

/** * nforce2_set_fsb - set new FSB * @fsb: New FSB * * Sets new FSB */
static int nforce2_set_fsb(unsigned int fsb) { u32 temp = 0; unsigned int tfsb; int diff; int pll = 0; if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) { pr_err("FSB %d is out of range!\n", fsb); return -EINVAL; } tfsb = nforce2_fsb_read(0); if (!tfsb) { pr_err("Error while reading the FSB\n"); return -EINVAL; } /* First write? Then set actual value */ pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp); if (!temp) { pll = nforce2_calc_pll(tfsb); if (pll < 0) return -EINVAL; nforce2_write_pll(pll); } /* Enable write access */ temp = 0x01; pci_write_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8)temp); diff = tfsb - fsb; if (!diff) return 0; while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) { if (diff < 0) tfsb++; else tfsb--; /* Calculate the PLL reg. value */ pll = nforce2_calc_pll(tfsb); if (pll == -1) return -EINVAL; nforce2_write_pll(pll); #ifdef NFORCE2_DELAY mdelay(NFORCE2_DELAY); #endif } temp = 0x40; pci_write_config_byte(nforce2_dev, NFORCE2_PLLADR, (u8)temp); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones22694.17%350.00%
Joe Perches52.08%116.67%
Gabriel A. Devenyi52.08%116.67%
Paolo Ciarrocchi41.67%116.67%
Total240100.00%6100.00%

/** * nforce2_get - get the CPU frequency * @cpu: CPU number * * Returns the CPU frequency */
static unsigned int nforce2_get(unsigned int cpu) { if (cpu) return 0; return nforce2_fsb_read(0) * fid * 100; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones28100.00%1100.00%
Total28100.00%1100.00%

/** * nforce2_target - set a new CPUFreq policy * @policy: new policy * @target_freq: the target frequency * @relation: how that frequency relates to achieved frequency * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) * * Sets a new CPUFreq policy. */
static int nforce2_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { /* unsigned long flags; */ struct cpufreq_freqs freqs; unsigned int target_fsb; if ((target_freq > policy->max) || (target_freq < policy->min)) return -EINVAL; target_fsb = target_freq / (fid * 100); freqs.old = nforce2_get(policy->cpu); freqs.new = target_fsb * fid * 100; if (freqs.old == freqs.new) return 0; pr_debug("Old CPU frequency %d kHz, new %d kHz\n", freqs.old, freqs.new); cpufreq_freq_transition_begin(policy, &freqs); /* Disable IRQs */ /* local_irq_save(flags); */ if (nforce2_set_fsb(target_fsb) < 0) pr_err("Changing FSB to %d failed\n", target_fsb); else pr_debug("Changed FSB successfully to %d\n", target_fsb); /* Enable IRQs */ /* local_irq_restore(flags); */ cpufreq_freq_transition_end(policy, &freqs, 0); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones13989.10%225.00%
Viresh Kumar74.49%225.00%
Joe Perches31.92%112.50%
Paolo Ciarrocchi31.92%112.50%
Jan Beulich21.28%112.50%
Dominik Brodowski21.28%112.50%
Total156100.00%8100.00%

/** * nforce2_verify - verifies a new CPUFreq policy * @policy: new policy */
static int nforce2_verify(struct cpufreq_policy *policy) { unsigned int fsb_pol_max; fsb_pol_max = policy->max / (fid * 100); if (policy->min < (fsb_pol_max * fid * 100)) policy->max = (fsb_pol_max + 1) * fid * 100; cpufreq_verify_within_cpu_limits(policy); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones6298.41%150.00%
Viresh Kumar11.59%150.00%
Total63100.00%2100.00%


static int nforce2_cpu_init(struct cpufreq_policy *policy) { unsigned int fsb; unsigned int rfid; /* capability check */ if (policy->cpu != 0) return -ENODEV; /* Get current FSB */ fsb = nforce2_fsb_read(0); if (!fsb) return -EIO; /* FIX: Get FID from CPU */ if (!fid) { if (!cpu_khz) { pr_warn("cpu_khz not set, can't calculate multiplier!\n"); return -ENODEV; } fid = cpu_khz / (fsb * 100); rfid = fid % 5; if (rfid) { if (rfid > 2) fid += 5 - rfid; else fid -= rfid; } } pr_info("FSB currently at %i MHz, FID %d.%d\n", fsb, fid / 10, fid % 10); /* Set maximum FSB to FSB at boot time */ max_fsb = nforce2_fsb_read(1); if (!max_fsb) return -EIO; if (!min_fsb) min_fsb = max_fsb - NFORCE2_SAFE_DISTANCE; if (min_fsb < NFORCE2_MIN_FSB) min_fsb = NFORCE2_MIN_FSB; /* cpuinfo and default policy values */ policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100; policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones18491.54%250.00%
Joe Perches94.48%125.00%
Viresh Kumar83.98%125.00%
Total201100.00%4100.00%


static int nforce2_cpu_exit(struct cpufreq_policy *policy) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones14100.00%1100.00%
Total14100.00%1100.00%

static struct cpufreq_driver nforce2_driver = { .name = "nforce2", .flags = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING, .verify = nforce2_verify, .target = nforce2_target, .get = nforce2_get, .init = nforce2_cpu_init, .exit = nforce2_cpu_exit, }; #ifdef MODULE static const struct pci_device_id nforce2_ids[] = { { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2 }, {} }; MODULE_DEVICE_TABLE(pci, nforce2_ids); #endif /** * nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic * * Detects nForce2 A2 and C1 stepping * */
static int nforce2_detect_chipset(void) { nforce2_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, PCI_ANY_ID, PCI_ANY_ID, NULL); if (nforce2_dev == NULL) return -ENODEV; pr_info("Detected nForce2 chipset revision %X\n", nforce2_dev->revision); pr_info("FSB changing is maybe unstable and can lead to crashes and data loss\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones4284.00%375.00%
Joe Perches816.00%125.00%
Total50100.00%4100.00%

/** * nforce2_init - initializes the nForce2 CPUFreq driver * * Initializes the nForce2 FSB support. Returns -ENODEV on unsupported * devices, -EINVAL on problems during initialization, and zero on * success. */
static int __init nforce2_init(void) { /* TODO: do we need to detect the processor? */ /* detect chipset */ if (nforce2_detect_chipset()) { pr_info("No nForce2 chipset\n"); return -ENODEV; } return cpufreq_register_driver(&nforce2_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones3191.18%150.00%
Joe Perches38.82%150.00%
Total34100.00%2100.00%

/** * nforce2_exit - unregisters cpufreq module * * Unregisters nForce2 FSB change support. */
static void __exit nforce2_exit(void) { cpufreq_unregister_driver(&nforce2_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones15100.00%1100.00%
Total15100.00%1100.00%

module_init(nforce2_init); module_exit(nforce2_exit);

Overall Contributors

PersonTokensPropCommitsCommitProp
Dave Jones126192.38%630.00%
Joe Perches352.56%210.00%
Andi Kleen231.68%15.00%
Viresh Kumar211.54%525.00%
Paolo Ciarrocchi90.66%15.00%
Jingoo Han60.44%15.00%
Gabriel A. Devenyi50.37%15.00%
Jan Beulich20.15%15.00%
Dominik Brodowski20.15%15.00%
Shailendra Verma10.07%15.00%
Total1365100.00%20100.00%
Directory: drivers/cpufreq
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.