~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/loongson64/cpucfg-emul.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 
  3 #include <linux/smp.h>
  4 #include <linux/types.h>
  5 #include <asm/cpu.h>
  6 #include <asm/cpu-info.h>
  7 #include <asm/elf.h>
  8 
  9 #include <loongson_regs.h>
 10 #include <cpucfg-emul.h>
 11 
 12 static bool is_loongson(struct cpuinfo_mips *c)
 13 {
 14         switch (c->processor_id & PRID_COMP_MASK) {
 15         case PRID_COMP_LEGACY:
 16                 return ((c->processor_id & PRID_IMP_MASK) ==
 17                         PRID_IMP_LOONGSON_64C);
 18 
 19         case PRID_COMP_LOONGSON:
 20                 return true;
 21 
 22         default:
 23                 return false;
 24         }
 25 }
 26 
 27 static u32 get_loongson_fprev(struct cpuinfo_mips *c)
 28 {
 29         return c->fpu_id & LOONGSON_FPREV_MASK;
 30 }
 31 
 32 static bool cpu_has_uca(void)
 33 {
 34         u32 diag = read_c0_diag();
 35         u32 new_diag;
 36 
 37         if (diag & LOONGSON_DIAG_UCAC)
 38                 /* UCA is already enabled. */
 39                 return true;
 40 
 41         /* See if UCAC bit can be flipped on. This should be safe. */
 42         new_diag = diag | LOONGSON_DIAG_UCAC;
 43         write_c0_diag(new_diag);
 44         new_diag = read_c0_diag();
 45         write_c0_diag(diag);
 46 
 47         return (new_diag & LOONGSON_DIAG_UCAC) != 0;
 48 }
 49 
 50 static void probe_uca(struct cpuinfo_mips *c)
 51 {
 52         if (cpu_has_uca())
 53                 c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_LSUCA;
 54 }
 55 
 56 static void decode_loongson_config6(struct cpuinfo_mips *c)
 57 {
 58         u32 config6 = read_c0_config6();
 59 
 60         if (config6 & LOONGSON_CONF6_SFBEN)
 61                 c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_SFBP;
 62         if (config6 & LOONGSON_CONF6_LLEXC)
 63                 c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_LLEXC;
 64         if (config6 & LOONGSON_CONF6_SCRAND)
 65                 c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_SCRAND;
 66 }
 67 
 68 static void patch_cpucfg_sel1(struct cpuinfo_mips *c)
 69 {
 70         u64 ases = c->ases;
 71         u64 options = c->options;
 72         u32 data = c->loongson3_cpucfg_data[0];
 73 
 74         if (options & MIPS_CPU_FPU) {
 75                 data |= LOONGSON_CFG1_FP;
 76                 data |= get_loongson_fprev(c) << LOONGSON_CFG1_FPREV_OFFSET;
 77         }
 78         if (ases & MIPS_ASE_LOONGSON_MMI)
 79                 data |= LOONGSON_CFG1_MMI;
 80         if (ases & MIPS_ASE_MSA)
 81                 data |= LOONGSON_CFG1_MSA1;
 82 
 83         c->loongson3_cpucfg_data[0] = data;
 84 }
 85 
 86 static void patch_cpucfg_sel2(struct cpuinfo_mips *c)
 87 {
 88         u64 ases = c->ases;
 89         u64 options = c->options;
 90         u32 data = c->loongson3_cpucfg_data[1];
 91 
 92         if (ases & MIPS_ASE_LOONGSON_EXT)
 93                 data |= LOONGSON_CFG2_LEXT1;
 94         if (ases & MIPS_ASE_LOONGSON_EXT2)
 95                 data |= LOONGSON_CFG2_LEXT2;
 96         if (options & MIPS_CPU_LDPTE)
 97                 data |= LOONGSON_CFG2_LSPW;
 98 
 99         if (ases & MIPS_ASE_VZ)
100                 data |= LOONGSON_CFG2_LVZP;
101         else
102                 data &= ~LOONGSON_CFG2_LVZREV;
103 
104         c->loongson3_cpucfg_data[1] = data;
105 }
106 
107 static void patch_cpucfg_sel3(struct cpuinfo_mips *c)
108 {
109         u64 ases = c->ases;
110         u32 data = c->loongson3_cpucfg_data[2];
111 
112         if (ases & MIPS_ASE_LOONGSON_CAM) {
113                 data |= LOONGSON_CFG3_LCAMP;
114         } else {
115                 data &= ~LOONGSON_CFG3_LCAMREV;
116                 data &= ~LOONGSON_CFG3_LCAMNUM;
117                 data &= ~LOONGSON_CFG3_LCAMKW;
118                 data &= ~LOONGSON_CFG3_LCAMVW;
119         }
120 
121         c->loongson3_cpucfg_data[2] = data;
122 }
123 
124 void loongson3_cpucfg_synthesize_data(struct cpuinfo_mips *c)
125 {
126         /* Only engage the logic on Loongson processors. */
127         if (!is_loongson(c))
128                 return;
129 
130         /* CPUs with CPUCFG support don't need to synthesize anything. */
131         if (cpu_has_cfg())
132                 goto have_cpucfg_now;
133 
134         c->loongson3_cpucfg_data[0] = 0;
135         c->loongson3_cpucfg_data[1] = 0;
136         c->loongson3_cpucfg_data[2] = 0;
137 
138         /* Add CPUCFG features non-discoverable otherwise. */
139         switch (c->processor_id & (PRID_IMP_MASK | PRID_REV_MASK)) {
140         case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_0:
141         case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_1:
142         case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_2:
143         case PRID_IMP_LOONGSON_64R | PRID_REV_LOONGSON2K_R1_3:
144                 decode_loongson_config6(c);
145                 probe_uca(c);
146 
147                 c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_LSLDR0 |
148                         LOONGSON_CFG1_LSSYNCI | LOONGSON_CFG1_LLSYNC |
149                         LOONGSON_CFG1_TGTSYNC);
150                 c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
151                         LOONGSON_CFG2_LBT2 | LOONGSON_CFG2_LPMP |
152                         LOONGSON_CFG2_LPM_REV2);
153                 c->loongson3_cpucfg_data[2] = 0;
154                 break;
155 
156         case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R1:
157                 c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_LSLDR0 |
158                         LOONGSON_CFG1_LSSYNCI | LOONGSON_CFG1_LSUCA |
159                         LOONGSON_CFG1_LLSYNC | LOONGSON_CFG1_TGTSYNC);
160                 c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
161                         LOONGSON_CFG2_LPMP | LOONGSON_CFG2_LPM_REV1);
162                 c->loongson3_cpucfg_data[2] |= (
163                         LOONGSON_CFG3_LCAM_REV1 |
164                         LOONGSON_CFG3_LCAMNUM_REV1 |
165                         LOONGSON_CFG3_LCAMKW_REV1 |
166                         LOONGSON_CFG3_LCAMVW_REV1);
167                 break;
168 
169         case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3B_R1:
170         case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3B_R2:
171                 c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_LSLDR0 |
172                         LOONGSON_CFG1_LSSYNCI | LOONGSON_CFG1_LSUCA |
173                         LOONGSON_CFG1_LLSYNC | LOONGSON_CFG1_TGTSYNC);
174                 c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
175                         LOONGSON_CFG2_LPMP | LOONGSON_CFG2_LPM_REV1);
176                 c->loongson3_cpucfg_data[2] |= (
177                         LOONGSON_CFG3_LCAM_REV1 |
178                         LOONGSON_CFG3_LCAMNUM_REV1 |
179                         LOONGSON_CFG3_LCAMKW_REV1 |
180                         LOONGSON_CFG3_LCAMVW_REV1);
181                 break;
182 
183         case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0:
184         case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_1:
185         case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R3_0:
186         case PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R3_1:
187                 decode_loongson_config6(c);
188                 probe_uca(c);
189 
190                 c->loongson3_cpucfg_data[0] |= (LOONGSON_CFG1_CNT64 |
191                         LOONGSON_CFG1_LSLDR0 | LOONGSON_CFG1_LSPREF |
192                         LOONGSON_CFG1_LSPREFX | LOONGSON_CFG1_LSSYNCI |
193                         LOONGSON_CFG1_LLSYNC | LOONGSON_CFG1_TGTSYNC);
194                 c->loongson3_cpucfg_data[1] |= (LOONGSON_CFG2_LBT1 |
195                         LOONGSON_CFG2_LBT2 | LOONGSON_CFG2_LBTMMU |
196                         LOONGSON_CFG2_LPMP | LOONGSON_CFG2_LPM_REV1 |
197                         LOONGSON_CFG2_LVZ_REV1);
198                 c->loongson3_cpucfg_data[2] |= (LOONGSON_CFG3_LCAM_REV1 |
199                         LOONGSON_CFG3_LCAMNUM_REV1 |
200                         LOONGSON_CFG3_LCAMKW_REV1 |
201                         LOONGSON_CFG3_LCAMVW_REV1);
202                 break;
203 
204         default:
205                 /* It is possible that some future Loongson cores still do
206                  * not have CPUCFG, so do not emulate anything for these
207                  * cores.
208                  */
209                 return;
210         }
211 
212         /* This feature is set by firmware, but all known Loongson-64 systems
213          * are configured this way.
214          */
215         c->loongson3_cpucfg_data[0] |= LOONGSON_CFG1_CDMAP;
216 
217         /* Patch in dynamically probed bits. */
218         patch_cpucfg_sel1(c);
219         patch_cpucfg_sel2(c);
220         patch_cpucfg_sel3(c);
221 
222 have_cpucfg_now:
223         /* We have usable CPUCFG now, emulated or not.
224          * Announce CPUCFG availability to userspace via hwcap.
225          */
226         elf_hwcap |= HWCAP_LOONGSON_CPUCFG;
227 }
228 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php