diff options
author | James Hogan <james.hogan@imgtec.com> | 2016-05-11 10:50:30 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2016-05-13 09:30:25 -0400 |
commit | 6ad816e77ed77538fe729050cf6631328c6113f7 (patch) | |
tree | f04c89b18b8a90d9abc9be6e181cb247c1335d63 /arch/mips/kernel/cpu-probe.c | |
parent | 7eb91118227d71132ca2da06a9b376ba656171d9 (diff) |
MIPS: Add probing & defs for VZ & guest features
Add a few new cpu-features.h definitions for VZ sub-features, namely the
existence of the CP0_GuestCtl0Ext, CP0_GuestCtl1, and CP0_GuestCtl2
registers, and support for GuestID to dialias TLB entries belonging to
different guests.
Also add certain features present in the guest, with the naming scheme
cpu_guest_has_*. These are added separately to the main options bitfield
since they generally parallel similar features in the root context. A
few of these (FPU, MSA, watchpoints, perf counters, CP0_[X]ContextConfig
registers, MAAR registers, and probably others in future) can be
dynamically configured in the guest context, for which the
cpu_guest_has_dyn_* macros are added.
[ralf@linux-mips.org: Resolve merge conflict.]
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/13231/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/cpu-probe.c')
-rw-r--r-- | arch/mips/kernel/cpu-probe.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 31c27576a931..5ac5c3e23460 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c | |||
@@ -915,6 +915,235 @@ static void decode_configs(struct cpuinfo_mips *c) | |||
915 | #endif | 915 | #endif |
916 | } | 916 | } |
917 | 917 | ||
918 | /* | ||
919 | * Probe for certain guest capabilities by writing config bits and reading back. | ||
920 | * Finally write back the original value. | ||
921 | */ | ||
922 | #define probe_gc0_config(name, maxconf, bits) \ | ||
923 | do { \ | ||
924 | unsigned int tmp; \ | ||
925 | tmp = read_gc0_##name(); \ | ||
926 | write_gc0_##name(tmp | (bits)); \ | ||
927 | back_to_back_c0_hazard(); \ | ||
928 | maxconf = read_gc0_##name(); \ | ||
929 | write_gc0_##name(tmp); \ | ||
930 | } while (0) | ||
931 | |||
932 | /* | ||
933 | * Probe for dynamic guest capabilities by changing certain config bits and | ||
934 | * reading back to see if they change. Finally write back the original value. | ||
935 | */ | ||
936 | #define probe_gc0_config_dyn(name, maxconf, dynconf, bits) \ | ||
937 | do { \ | ||
938 | maxconf = read_gc0_##name(); \ | ||
939 | write_gc0_##name(maxconf ^ (bits)); \ | ||
940 | back_to_back_c0_hazard(); \ | ||
941 | dynconf = maxconf ^ read_gc0_##name(); \ | ||
942 | write_gc0_##name(maxconf); \ | ||
943 | maxconf |= dynconf; \ | ||
944 | } while (0) | ||
945 | |||
946 | static inline unsigned int decode_guest_config0(struct cpuinfo_mips *c) | ||
947 | { | ||
948 | unsigned int config0; | ||
949 | |||
950 | probe_gc0_config(config, config0, MIPS_CONF_M); | ||
951 | |||
952 | if (config0 & MIPS_CONF_M) | ||
953 | c->guest.conf |= BIT(1); | ||
954 | return config0 & MIPS_CONF_M; | ||
955 | } | ||
956 | |||
957 | static inline unsigned int decode_guest_config1(struct cpuinfo_mips *c) | ||
958 | { | ||
959 | unsigned int config1, config1_dyn; | ||
960 | |||
961 | probe_gc0_config_dyn(config1, config1, config1_dyn, | ||
962 | MIPS_CONF_M | MIPS_CONF1_PC | MIPS_CONF1_WR | | ||
963 | MIPS_CONF1_FP); | ||
964 | |||
965 | if (config1 & MIPS_CONF1_FP) | ||
966 | c->guest.options |= MIPS_CPU_FPU; | ||
967 | if (config1_dyn & MIPS_CONF1_FP) | ||
968 | c->guest.options_dyn |= MIPS_CPU_FPU; | ||
969 | |||
970 | if (config1 & MIPS_CONF1_WR) | ||
971 | c->guest.options |= MIPS_CPU_WATCH; | ||
972 | if (config1_dyn & MIPS_CONF1_WR) | ||
973 | c->guest.options_dyn |= MIPS_CPU_WATCH; | ||
974 | |||
975 | if (config1 & MIPS_CONF1_PC) | ||
976 | c->guest.options |= MIPS_CPU_PERF; | ||
977 | if (config1_dyn & MIPS_CONF1_PC) | ||
978 | c->guest.options_dyn |= MIPS_CPU_PERF; | ||
979 | |||
980 | if (config1 & MIPS_CONF_M) | ||
981 | c->guest.conf |= BIT(2); | ||
982 | return config1 & MIPS_CONF_M; | ||
983 | } | ||
984 | |||
985 | static inline unsigned int decode_guest_config2(struct cpuinfo_mips *c) | ||
986 | { | ||
987 | unsigned int config2; | ||
988 | |||
989 | probe_gc0_config(config2, config2, MIPS_CONF_M); | ||
990 | |||
991 | if (config2 & MIPS_CONF_M) | ||
992 | c->guest.conf |= BIT(3); | ||
993 | return config2 & MIPS_CONF_M; | ||
994 | } | ||
995 | |||
996 | static inline unsigned int decode_guest_config3(struct cpuinfo_mips *c) | ||
997 | { | ||
998 | unsigned int config3, config3_dyn; | ||
999 | |||
1000 | probe_gc0_config_dyn(config3, config3, config3_dyn, | ||
1001 | MIPS_CONF_M | MIPS_CONF3_MSA | MIPS_CONF3_CTXTC); | ||
1002 | |||
1003 | if (config3 & MIPS_CONF3_CTXTC) | ||
1004 | c->guest.options |= MIPS_CPU_CTXTC; | ||
1005 | if (config3_dyn & MIPS_CONF3_CTXTC) | ||
1006 | c->guest.options_dyn |= MIPS_CPU_CTXTC; | ||
1007 | |||
1008 | if (config3 & MIPS_CONF3_PW) | ||
1009 | c->guest.options |= MIPS_CPU_HTW; | ||
1010 | |||
1011 | if (config3 & MIPS_CONF3_SC) | ||
1012 | c->guest.options |= MIPS_CPU_SEGMENTS; | ||
1013 | |||
1014 | if (config3 & MIPS_CONF3_BI) | ||
1015 | c->guest.options |= MIPS_CPU_BADINSTR; | ||
1016 | if (config3 & MIPS_CONF3_BP) | ||
1017 | c->guest.options |= MIPS_CPU_BADINSTRP; | ||
1018 | |||
1019 | if (config3 & MIPS_CONF3_MSA) | ||
1020 | c->guest.ases |= MIPS_ASE_MSA; | ||
1021 | if (config3_dyn & MIPS_CONF3_MSA) | ||
1022 | c->guest.ases_dyn |= MIPS_ASE_MSA; | ||
1023 | |||
1024 | if (config3 & MIPS_CONF_M) | ||
1025 | c->guest.conf |= BIT(4); | ||
1026 | return config3 & MIPS_CONF_M; | ||
1027 | } | ||
1028 | |||
1029 | static inline unsigned int decode_guest_config4(struct cpuinfo_mips *c) | ||
1030 | { | ||
1031 | unsigned int config4; | ||
1032 | |||
1033 | probe_gc0_config(config4, config4, | ||
1034 | MIPS_CONF_M | MIPS_CONF4_KSCREXIST); | ||
1035 | |||
1036 | c->guest.kscratch_mask = (config4 & MIPS_CONF4_KSCREXIST) | ||
1037 | >> MIPS_CONF4_KSCREXIST_SHIFT; | ||
1038 | |||
1039 | if (config4 & MIPS_CONF_M) | ||
1040 | c->guest.conf |= BIT(5); | ||
1041 | return config4 & MIPS_CONF_M; | ||
1042 | } | ||
1043 | |||
1044 | static inline unsigned int decode_guest_config5(struct cpuinfo_mips *c) | ||
1045 | { | ||
1046 | unsigned int config5, config5_dyn; | ||
1047 | |||
1048 | probe_gc0_config_dyn(config5, config5, config5_dyn, | ||
1049 | MIPS_CONF_M | MIPS_CONF5_MRP); | ||
1050 | |||
1051 | if (config5 & MIPS_CONF5_MRP) | ||
1052 | c->guest.options |= MIPS_CPU_MAAR; | ||
1053 | if (config5_dyn & MIPS_CONF5_MRP) | ||
1054 | c->guest.options_dyn |= MIPS_CPU_MAAR; | ||
1055 | |||
1056 | if (config5 & MIPS_CONF5_LLB) | ||
1057 | c->guest.options |= MIPS_CPU_RW_LLB; | ||
1058 | |||
1059 | if (config5 & MIPS_CONF_M) | ||
1060 | c->guest.conf |= BIT(6); | ||
1061 | return config5 & MIPS_CONF_M; | ||
1062 | } | ||
1063 | |||
1064 | static inline void decode_guest_configs(struct cpuinfo_mips *c) | ||
1065 | { | ||
1066 | unsigned int ok; | ||
1067 | |||
1068 | ok = decode_guest_config0(c); | ||
1069 | if (ok) | ||
1070 | ok = decode_guest_config1(c); | ||
1071 | if (ok) | ||
1072 | ok = decode_guest_config2(c); | ||
1073 | if (ok) | ||
1074 | ok = decode_guest_config3(c); | ||
1075 | if (ok) | ||
1076 | ok = decode_guest_config4(c); | ||
1077 | if (ok) | ||
1078 | decode_guest_config5(c); | ||
1079 | } | ||
1080 | |||
1081 | static inline void cpu_probe_guestctl0(struct cpuinfo_mips *c) | ||
1082 | { | ||
1083 | unsigned int guestctl0, temp; | ||
1084 | |||
1085 | guestctl0 = read_c0_guestctl0(); | ||
1086 | |||
1087 | if (guestctl0 & MIPS_GCTL0_G0E) | ||
1088 | c->options |= MIPS_CPU_GUESTCTL0EXT; | ||
1089 | if (guestctl0 & MIPS_GCTL0_G1) | ||
1090 | c->options |= MIPS_CPU_GUESTCTL1; | ||
1091 | if (guestctl0 & MIPS_GCTL0_G2) | ||
1092 | c->options |= MIPS_CPU_GUESTCTL2; | ||
1093 | if (!(guestctl0 & MIPS_GCTL0_RAD)) { | ||
1094 | c->options |= MIPS_CPU_GUESTID; | ||
1095 | |||
1096 | /* | ||
1097 | * Probe for Direct Root to Guest (DRG). Set GuestCtl1.RID = 0 | ||
1098 | * first, otherwise all data accesses will be fully virtualised | ||
1099 | * as if they were performed by guest mode. | ||
1100 | */ | ||
1101 | write_c0_guestctl1(0); | ||
1102 | tlbw_use_hazard(); | ||
1103 | |||
1104 | write_c0_guestctl0(guestctl0 | MIPS_GCTL0_DRG); | ||
1105 | back_to_back_c0_hazard(); | ||
1106 | temp = read_c0_guestctl0(); | ||
1107 | |||
1108 | if (temp & MIPS_GCTL0_DRG) { | ||
1109 | write_c0_guestctl0(guestctl0); | ||
1110 | c->options |= MIPS_CPU_DRG; | ||
1111 | } | ||
1112 | } | ||
1113 | } | ||
1114 | |||
1115 | static inline void cpu_probe_guestctl1(struct cpuinfo_mips *c) | ||
1116 | { | ||
1117 | if (cpu_has_guestid) { | ||
1118 | /* determine the number of bits of GuestID available */ | ||
1119 | write_c0_guestctl1(MIPS_GCTL1_ID); | ||
1120 | back_to_back_c0_hazard(); | ||
1121 | c->guestid_mask = (read_c0_guestctl1() & MIPS_GCTL1_ID) | ||
1122 | >> MIPS_GCTL1_ID_SHIFT; | ||
1123 | write_c0_guestctl1(0); | ||
1124 | } | ||
1125 | } | ||
1126 | |||
1127 | static inline void cpu_probe_gtoffset(struct cpuinfo_mips *c) | ||
1128 | { | ||
1129 | /* determine the number of bits of GTOffset available */ | ||
1130 | write_c0_gtoffset(0xffffffff); | ||
1131 | back_to_back_c0_hazard(); | ||
1132 | c->gtoffset_mask = read_c0_gtoffset(); | ||
1133 | write_c0_gtoffset(0); | ||
1134 | } | ||
1135 | |||
1136 | static inline void cpu_probe_vz(struct cpuinfo_mips *c) | ||
1137 | { | ||
1138 | cpu_probe_guestctl0(c); | ||
1139 | if (cpu_has_guestctl1) | ||
1140 | cpu_probe_guestctl1(c); | ||
1141 | |||
1142 | cpu_probe_gtoffset(c); | ||
1143 | |||
1144 | decode_guest_configs(c); | ||
1145 | } | ||
1146 | |||
918 | #define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \ | 1147 | #define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \ |
919 | | MIPS_CPU_COUNTER) | 1148 | | MIPS_CPU_COUNTER) |
920 | 1149 | ||
@@ -1817,6 +2046,9 @@ void cpu_probe(void) | |||
1817 | elf_hwcap |= HWCAP_MIPS_MSA; | 2046 | elf_hwcap |= HWCAP_MIPS_MSA; |
1818 | } | 2047 | } |
1819 | 2048 | ||
2049 | if (cpu_has_vz) | ||
2050 | cpu_probe_vz(c); | ||
2051 | |||
1820 | cpu_probe_vmbits(c); | 2052 | cpu_probe_vmbits(c); |
1821 | 2053 | ||
1822 | #ifdef CONFIG_64BIT | 2054 | #ifdef CONFIG_64BIT |