cregit-Linux how code gets into the kernel

Release 4.14 drivers/cpufreq/sparc-us2e-cpufreq.c

Directory: drivers/cpufreq
/* us2e_cpufreq.c: UltraSPARC-IIe cpu frequency support
 *
 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
 *
 * Many thanks to Dominik Brodowski for fixing up the cpufreq
 * infrastructure in order to make this driver easier to implement.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/cpufreq.h>
#include <linux/threads.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>

#include <asm/asi.h>
#include <asm/timer.h>


static struct cpufreq_driver *cpufreq_us2e_driver;


struct us2e_freq_percpu_info {
	
struct cpufreq_frequency_table table[6];
};

/* Indexed by cpu number. */

static struct us2e_freq_percpu_info *us2e_freq_table;


#define HBIRD_MEM_CNTL0_ADDR	0x1fe0000f010UL

#define HBIRD_ESTAR_MODE_ADDR	0x1fe0000f080UL

/* UltraSPARC-IIe has five dividers: 1, 2, 4, 6, and 8.  These are controlled
 * in the ESTAR mode control register.
 */

#define ESTAR_MODE_DIV_1	0x0000000000000000UL

#define ESTAR_MODE_DIV_2	0x0000000000000001UL

#define ESTAR_MODE_DIV_4	0x0000000000000003UL

#define ESTAR_MODE_DIV_6	0x0000000000000002UL

#define ESTAR_MODE_DIV_8	0x0000000000000004UL

#define ESTAR_MODE_DIV_MASK	0x0000000000000007UL


#define MCTRL0_SREFRESH_ENAB	0x0000000000010000UL

#define MCTRL0_REFR_COUNT_MASK	0x0000000000007f00UL

#define MCTRL0_REFR_COUNT_SHIFT	8

#define MCTRL0_REFR_INTERVAL	7800

#define MCTRL0_REFR_CLKS_P_CNT	64


static unsigned long read_hbreg(unsigned long addr) { unsigned long ret; __asm__ __volatile__("ldxa [%1] %2, %0" : "=&r" (ret) : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E)); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller21100.00%1100.00%
Total21100.00%1100.00%


static void write_hbreg(unsigned long addr, unsigned long val) { __asm__ __volatile__("stxa %0, [%1] %2\n\t" "membar #Sync" : /* no outputs */ : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E) : "memory"); if (addr == HBIRD_ESTAR_MODE_ADDR) { /* Need to wait 16 clock cycles for the PLL to lock. */ udelay(1); } }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller33100.00%1100.00%
Total33100.00%1100.00%


static void self_refresh_ctl(int enable) { unsigned long mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR); if (enable) mctrl |= MCTRL0_SREFRESH_ENAB; else mctrl &= ~MCTRL0_SREFRESH_ENAB; write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl); (void) read_hbreg(HBIRD_MEM_CNTL0_ADDR); }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller47100.00%1100.00%
Total47100.00%1100.00%


static void frob_mem_refresh(int cpu_slowing_down, unsigned long clock_tick, unsigned long old_divisor, unsigned long divisor) { unsigned long old_refr_count, refr_count, mctrl; refr_count = (clock_tick * MCTRL0_REFR_INTERVAL); refr_count /= (MCTRL0_REFR_CLKS_P_CNT * divisor * 1000000000UL); mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR); old_refr_count = (mctrl & MCTRL0_REFR_COUNT_MASK) >> MCTRL0_REFR_COUNT_SHIFT; mctrl &= ~MCTRL0_REFR_COUNT_MASK; mctrl |= refr_count << MCTRL0_REFR_COUNT_SHIFT; write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl); mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR); if (cpu_slowing_down && !(mctrl & MCTRL0_SREFRESH_ENAB)) { unsigned long usecs; /* We have to wait for both refresh counts (old * and new) to go to zero. */ usecs = (MCTRL0_REFR_CLKS_P_CNT * (refr_count + old_refr_count) * 1000000UL * old_divisor) / clock_tick; udelay(usecs + 1UL); } }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller132100.00%1100.00%
Total132100.00%1100.00%


static void us2e_transition(unsigned long estar, unsigned long new_bits, unsigned long clock_tick, unsigned long old_divisor, unsigned long divisor) { estar &= ~ESTAR_MODE_DIV_MASK; /* This is based upon the state transition diagram in the IIe manual. */ if (old_divisor == 2 && divisor == 1) { self_refresh_ctl(0); write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); frob_mem_refresh(0, clock_tick, old_divisor, divisor); } else if (old_divisor == 1 && divisor == 2) { frob_mem_refresh(1, clock_tick, old_divisor, divisor); write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); self_refresh_ctl(1); } else if (old_divisor == 1 && divisor > 2) { us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick, 1, 2); us2e_transition(estar, new_bits, clock_tick, 2, divisor); } else if (old_divisor > 2 && divisor == 1) { us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick, old_divisor, 2); us2e_transition(estar, new_bits, clock_tick, 2, divisor); } else if (old_divisor < divisor) { frob_mem_refresh(0, clock_tick, old_divisor, divisor); write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); } else if (old_divisor > divisor) { write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); frob_mem_refresh(1, clock_tick, old_divisor, divisor); } else { BUG(); } }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller249100.00%1100.00%
Total249100.00%1100.00%


static unsigned long index_to_estar_mode(unsigned int index) { switch (index) { case 0: return ESTAR_MODE_DIV_1; case 1: return ESTAR_MODE_DIV_2; case 2: return ESTAR_MODE_DIV_4; case 3: return ESTAR_MODE_DIV_6; case 4: return ESTAR_MODE_DIV_8; default: BUG(); } }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller51100.00%1100.00%
Total51100.00%1100.00%


static unsigned long index_to_divisor(unsigned int index) { switch (index) { case 0: return 1; case 1: return 2; case 2: return 4; case 3: return 6; case 4: return 8; default: BUG(); } }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller51100.00%1100.00%
Total51100.00%1100.00%


static unsigned long estar_to_divisor(unsigned long estar) { unsigned long ret; switch (estar & ESTAR_MODE_DIV_MASK) { case ESTAR_MODE_DIV_1: ret = 1; break; case ESTAR_MODE_DIV_2: ret = 2; break; case ESTAR_MODE_DIV_4: ret = 4; break; case ESTAR_MODE_DIV_6: ret = 6; break; case ESTAR_MODE_DIV_8: ret = 8; break; default: BUG(); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller70100.00%1100.00%
Total70100.00%1100.00%


static void __us2e_freq_get(void *arg) { unsigned long *estar = arg; *estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR); }

Contributors

PersonTokensPropCommitsCommitProp
Thomas Gleixner25100.00%1100.00%
Total25100.00%1100.00%


static unsigned int us2e_freq_get(unsigned int cpu) { unsigned long clock_tick, estar; clock_tick = sparc64_get_clock_tick(cpu) / 1000; if (smp_call_function_single(cpu, __us2e_freq_get, &estar, 1)) return 0; return clock_tick / estar_to_divisor(estar); }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller3772.55%133.33%
Thomas Gleixner1325.49%133.33%
Julia Lawall11.96%133.33%
Total51100.00%3100.00%


static void __us2e_freq_target(void *arg) { unsigned int cpu = smp_processor_id(); unsigned int *index = arg; unsigned long new_bits, new_freq; unsigned long clock_tick, divisor, old_divisor, estar; new_freq = clock_tick = sparc64_get_clock_tick(cpu) / 1000; new_bits = index_to_estar_mode(*index); divisor = index_to_divisor(*index); new_freq /= divisor; estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR); old_divisor = estar_to_divisor(estar); if (old_divisor != divisor) { us2e_transition(estar, new_bits, clock_tick * 1000, old_divisor, divisor); } }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller8477.78%360.00%
Thomas Gleixner1816.67%120.00%
Viresh Kumar65.56%120.00%
Total108100.00%5100.00%


static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index) { unsigned int cpu = policy->cpu; return smp_call_function_single(cpu, __us2e_freq_target, &index, 1); }

Contributors

PersonTokensPropCommitsCommitProp
Thomas Gleixner3083.33%133.33%
David S. Miller513.89%133.33%
Julia Lawall12.78%133.33%
Total36100.00%3100.00%


static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy) { unsigned int cpu = policy->cpu; unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000; struct cpufreq_frequency_table *table = &us2e_freq_table[cpu].table[0]; table[0].driver_data = 0; table[0].frequency = clock_tick / 1; table[1].driver_data = 1; table[1].frequency = clock_tick / 2; table[2].driver_data = 2; table[2].frequency = clock_tick / 4; table[2].driver_data = 3; table[2].frequency = clock_tick / 6; table[2].driver_data = 4; table[2].frequency = clock_tick / 8; table[2].driver_data = 5; table[3].frequency = CPUFREQ_TABLE_END; policy->cpuinfo.transition_latency = 0; policy->cur = clock_tick; return cpufreq_table_validate_and_show(policy, table); }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller17995.72%250.00%
Viresh Kumar84.28%250.00%
Total187100.00%4100.00%


static int us2e_freq_cpu_exit(struct cpufreq_policy *policy) { if (cpufreq_us2e_driver) us2e_freq_target(policy, 0); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller2496.00%150.00%
Viresh Kumar14.00%150.00%
Total25100.00%2100.00%


static int __init us2e_freq_init(void) { unsigned long manuf, impl, ver; int ret; if (tlb_type != spitfire) return -ENODEV; __asm__("rdpr %%ver, %0" : "=r" (ver)); manuf = ((ver >> 48) & 0xffff); impl = ((ver >> 32) & 0xffff); if (manuf == 0x17 && impl == 0x13) { struct cpufreq_driver *driver; ret = -ENOMEM; driver = kzalloc(sizeof(*driver), GFP_KERNEL); if (!driver) goto err_out; us2e_freq_table = kzalloc((NR_CPUS * sizeof(*us2e_freq_table)), GFP_KERNEL); if (!us2e_freq_table) goto err_out; driver->init = us2e_freq_cpu_init; driver->verify = cpufreq_generic_frequency_table_verify; driver->target_index = us2e_freq_target; driver->get = us2e_freq_get; driver->exit = us2e_freq_cpu_exit; strcpy(driver->name, "UltraSPARC-IIe"); cpufreq_us2e_driver = driver; ret = cpufreq_register_driver(driver); if (ret) goto err_out; return 0; err_out: if (driver) { kfree(driver); cpufreq_us2e_driver = NULL; } kfree(us2e_freq_table); us2e_freq_table = NULL; return ret; } return -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller20896.30%342.86%
Viresh Kumar62.78%342.86%
Eric Sesterhenn / Snakebyte20.93%114.29%
Total216100.00%7100.00%


static void __exit us2e_freq_exit(void) { if (cpufreq_us2e_driver) { cpufreq_unregister_driver(cpufreq_us2e_driver); kfree(cpufreq_us2e_driver); cpufreq_us2e_driver = NULL; kfree(us2e_freq_table); us2e_freq_table = NULL; } }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller38100.00%1100.00%
Total38100.00%1100.00%

MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-IIe"); MODULE_LICENSE("GPL"); module_init(us2e_freq_init); module_exit(us2e_freq_exit);

Overall Contributors

PersonTokensPropCommitsCommitProp
David S. Miller136692.48%430.77%
Thomas Gleixner865.82%17.69%
Viresh Kumar211.42%646.15%
Julia Lawall20.14%17.69%
Eric Sesterhenn / Snakebyte20.14%17.69%
Total1477100.00%13100.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.