Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/cavium-octeon/csrc-octeon.c
10818 views
1
/*
2
* This file is subject to the terms and conditions of the GNU General Public
3
* License. See the file "COPYING" in the main directory of this archive
4
* for more details.
5
*
6
* Copyright (C) 2007 by Ralf Baechle
7
* Copyright (C) 2009, 2010 Cavium Networks, Inc.
8
*/
9
#include <linux/clocksource.h>
10
#include <linux/init.h>
11
#include <linux/smp.h>
12
13
#include <asm/cpu-info.h>
14
#include <asm/time.h>
15
16
#include <asm/octeon/octeon.h>
17
#include <asm/octeon/cvmx-ipd-defs.h>
18
#include <asm/octeon/cvmx-mio-defs.h>
19
20
/*
21
* Set the current core's cvmcount counter to the value of the
22
* IPD_CLK_COUNT. We do this on all cores as they are brought
23
* on-line. This allows for a read from a local cpu register to
24
* access a synchronized counter.
25
*
26
* On CPU_CAVIUM_OCTEON2 the IPD_CLK_COUNT is scaled by rdiv/sdiv.
27
*/
28
void octeon_init_cvmcount(void)
29
{
30
unsigned long flags;
31
unsigned loops = 2;
32
u64 f = 0;
33
u64 rdiv = 0;
34
u64 sdiv = 0;
35
if (current_cpu_type() == CPU_CAVIUM_OCTEON2) {
36
union cvmx_mio_rst_boot rst_boot;
37
rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
38
rdiv = rst_boot.s.c_mul; /* CPU clock */
39
sdiv = rst_boot.s.pnr_mul; /* I/O clock */
40
f = (0x8000000000000000ull / sdiv) * 2;
41
}
42
43
44
/* Clobber loops so GCC will not unroll the following while loop. */
45
asm("" : "+r" (loops));
46
47
local_irq_save(flags);
48
/*
49
* Loop several times so we are executing from the cache,
50
* which should give more deterministic timing.
51
*/
52
while (loops--) {
53
u64 ipd_clk_count = cvmx_read_csr(CVMX_IPD_CLK_COUNT);
54
if (rdiv != 0) {
55
ipd_clk_count *= rdiv;
56
if (f != 0) {
57
asm("dmultu\t%[cnt],%[f]\n\t"
58
"mfhi\t%[cnt]"
59
: [cnt] "+r" (ipd_clk_count),
60
[f] "=r" (f)
61
: : "hi", "lo");
62
}
63
}
64
write_c0_cvmcount(ipd_clk_count);
65
}
66
local_irq_restore(flags);
67
}
68
69
static cycle_t octeon_cvmcount_read(struct clocksource *cs)
70
{
71
return read_c0_cvmcount();
72
}
73
74
static struct clocksource clocksource_mips = {
75
.name = "OCTEON_CVMCOUNT",
76
.read = octeon_cvmcount_read,
77
.mask = CLOCKSOURCE_MASK(64),
78
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
79
};
80
81
unsigned long long notrace sched_clock(void)
82
{
83
/* 64-bit arithmatic can overflow, so use 128-bit. */
84
u64 t1, t2, t3;
85
unsigned long long rv;
86
u64 mult = clocksource_mips.mult;
87
u64 shift = clocksource_mips.shift;
88
u64 cnt = read_c0_cvmcount();
89
90
asm (
91
"dmultu\t%[cnt],%[mult]\n\t"
92
"nor\t%[t1],$0,%[shift]\n\t"
93
"mfhi\t%[t2]\n\t"
94
"mflo\t%[t3]\n\t"
95
"dsll\t%[t2],%[t2],1\n\t"
96
"dsrlv\t%[rv],%[t3],%[shift]\n\t"
97
"dsllv\t%[t1],%[t2],%[t1]\n\t"
98
"or\t%[rv],%[t1],%[rv]\n\t"
99
: [rv] "=&r" (rv), [t1] "=&r" (t1), [t2] "=&r" (t2), [t3] "=&r" (t3)
100
: [cnt] "r" (cnt), [mult] "r" (mult), [shift] "r" (shift)
101
: "hi", "lo");
102
return rv;
103
}
104
105
void __init plat_time_init(void)
106
{
107
clocksource_mips.rating = 300;
108
clocksource_register_hz(&clocksource_mips, octeon_get_clock_rate());
109
}
110
111
static u64 octeon_udelay_factor;
112
static u64 octeon_ndelay_factor;
113
114
void __init octeon_setup_delays(void)
115
{
116
octeon_udelay_factor = octeon_get_clock_rate() / 1000000;
117
/*
118
* For __ndelay we divide by 2^16, so the factor is multiplied
119
* by the same amount.
120
*/
121
octeon_ndelay_factor = (octeon_udelay_factor * 0x10000ull) / 1000ull;
122
123
preset_lpj = octeon_get_clock_rate() / HZ;
124
}
125
126
void __udelay(unsigned long us)
127
{
128
u64 cur, end, inc;
129
130
cur = read_c0_cvmcount();
131
132
inc = us * octeon_udelay_factor;
133
end = cur + inc;
134
135
while (end > cur)
136
cur = read_c0_cvmcount();
137
}
138
EXPORT_SYMBOL(__udelay);
139
140
void __ndelay(unsigned long ns)
141
{
142
u64 cur, end, inc;
143
144
cur = read_c0_cvmcount();
145
146
inc = ((ns * octeon_ndelay_factor) >> 16);
147
end = cur + inc;
148
149
while (end > cur)
150
cur = read_c0_cvmcount();
151
}
152
EXPORT_SYMBOL(__ndelay);
153
154
void __delay(unsigned long loops)
155
{
156
u64 cur, end;
157
158
cur = read_c0_cvmcount();
159
end = cur + loops;
160
161
while (end > cur)
162
cur = read_c0_cvmcount();
163
}
164
EXPORT_SYMBOL(__delay);
165
166