0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/thread_info.h>
0011
0012 #include <asm/apic.h>
0013 #include <asm/cpu_device_id.h>
0014 #include <asm/intel-family.h>
0015 #include <asm/msr.h>
0016 #include <asm/param.h>
0017 #include <asm/tsc.h>
0018
0019 #define MAX_NUM_FREQS 16
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #define TSC_REFERENCE_KHZ 100000
0037
0038 struct muldiv {
0039 u32 multiplier;
0040 u32 divider;
0041 };
0042
0043
0044
0045
0046
0047
0048
0049
0050 struct freq_desc {
0051 bool use_msr_plat;
0052 struct muldiv muldiv[MAX_NUM_FREQS];
0053
0054
0055
0056
0057 u32 freqs[MAX_NUM_FREQS];
0058 u32 mask;
0059 };
0060
0061
0062
0063
0064
0065
0066 static const struct freq_desc freq_desc_pnw = {
0067 .use_msr_plat = false,
0068 .freqs = { 0, 0, 0, 0, 0, 99840, 0, 83200 },
0069 .mask = 0x07,
0070 };
0071
0072 static const struct freq_desc freq_desc_clv = {
0073 .use_msr_plat = false,
0074 .freqs = { 0, 133200, 0, 0, 0, 99840, 0, 83200 },
0075 .mask = 0x07,
0076 };
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 static const struct freq_desc freq_desc_byt = {
0087 .use_msr_plat = true,
0088 .muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 7, 6 },
0089 { 4, 5 } },
0090 .mask = 0x07,
0091 };
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 static const struct freq_desc freq_desc_cht = {
0106 .use_msr_plat = true,
0107 .muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 7, 6 },
0108 { 4, 5 }, { 14, 15 }, { 9, 10 }, { 8, 9 },
0109 { 7, 8 } },
0110 .mask = 0x0f,
0111 };
0112
0113
0114
0115
0116
0117
0118 static const struct freq_desc freq_desc_tng = {
0119 .use_msr_plat = true,
0120 .muldiv = { { 0, 0 }, { 1, 1 }, { 4, 3 } },
0121 .mask = 0x07,
0122 };
0123
0124
0125
0126
0127
0128
0129
0130
0131 static const struct freq_desc freq_desc_ann = {
0132 .use_msr_plat = true,
0133 .muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 1, 1 } },
0134 .mask = 0x0f,
0135 };
0136
0137
0138
0139
0140
0141
0142 static const struct freq_desc freq_desc_lgm = {
0143 .use_msr_plat = true,
0144 .freqs = { 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000,
0145 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000 },
0146 .mask = 0x0f,
0147 };
0148
0149 static const struct x86_cpu_id tsc_msr_cpu_ids[] = {
0150 X86_MATCH_INTEL_FAM6_MODEL(ATOM_SALTWELL_MID, &freq_desc_pnw),
0151 X86_MATCH_INTEL_FAM6_MODEL(ATOM_SALTWELL_TABLET,&freq_desc_clv),
0152 X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, &freq_desc_byt),
0153 X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &freq_desc_tng),
0154 X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, &freq_desc_cht),
0155 X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT_MID, &freq_desc_ann),
0156 X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT_NP, &freq_desc_lgm),
0157 {}
0158 };
0159
0160
0161
0162
0163
0164
0165
0166 unsigned long cpu_khz_from_msr(void)
0167 {
0168 u32 lo, hi, ratio, freq, tscref;
0169 const struct freq_desc *freq_desc;
0170 const struct x86_cpu_id *id;
0171 const struct muldiv *md;
0172 unsigned long res;
0173 int index;
0174
0175 id = x86_match_cpu(tsc_msr_cpu_ids);
0176 if (!id)
0177 return 0;
0178
0179 freq_desc = (struct freq_desc *)id->driver_data;
0180 if (freq_desc->use_msr_plat) {
0181 rdmsr(MSR_PLATFORM_INFO, lo, hi);
0182 ratio = (lo >> 8) & 0xff;
0183 } else {
0184 rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
0185 ratio = (hi >> 8) & 0x1f;
0186 }
0187
0188
0189 rdmsr(MSR_FSB_FREQ, lo, hi);
0190 index = lo & freq_desc->mask;
0191 md = &freq_desc->muldiv[index];
0192
0193
0194
0195
0196
0197 if (md->divider) {
0198 tscref = TSC_REFERENCE_KHZ * md->multiplier;
0199 freq = DIV_ROUND_CLOSEST(tscref, md->divider);
0200
0201
0202
0203
0204 res = DIV_ROUND_CLOSEST(tscref * ratio, md->divider);
0205 } else {
0206 freq = freq_desc->freqs[index];
0207 res = freq * ratio;
0208 }
0209
0210 if (freq == 0)
0211 pr_err("Error MSR_FSB_FREQ index %d is unknown\n", index);
0212
0213 #ifdef CONFIG_X86_LOCAL_APIC
0214 lapic_timer_period = (freq * 1000) / HZ;
0215 #endif
0216
0217
0218
0219
0220
0221
0222
0223 setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233 setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
0234
0235 return res;
0236 }