1 /* Get system parameters, e.g. cache information. S390/S390x version.
2 Copyright (C) 2015-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library. If not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #include <unistd.h>
20 #include <dl-procinfo.h>
21
22 static long int linux_sysconf (int name);
23
24 /* Possible arguments for get_cache_info.
25 The values are reflecting the level/attribute/type indications
26 of ecag-instruction (extract cpu attribue). */
27 #define CACHE_LEVEL_MAX 8
28 #define CACHE_ATTR_LINESIZE 1
29 #define CACHE_ATTR_SIZE 2
30 #define CACHE_ATTR_ASSOC 3
31 #define CACHE_TYPE_DATA 0
32 #define CACHE_TYPE_INSTRUCTION 1
33
34 static long
get_cache_info(int level,int attr,int type)35 get_cache_info (int level, int attr, int type)
36 {
37 unsigned long int val;
38 unsigned int cmd;
39 unsigned long int arg;
40
41 /* Check arguments. */
42 if (level < 1 || level > CACHE_LEVEL_MAX
43 || attr < CACHE_ATTR_LINESIZE || attr > CACHE_ATTR_ASSOC
44 || type < CACHE_TYPE_DATA || type > CACHE_TYPE_INSTRUCTION)
45 return 0L;
46
47 /* Check if ecag-instruction is available.
48 ecag - extract CPU attribute (only in zarch; arch >= z10; in as 2.24) */
49 if (!(GLRO (dl_hwcap) & HWCAP_S390_STFLE)
50 #if !defined __s390x__
51 || !(GLRO (dl_hwcap) & HWCAP_S390_ZARCH)
52 || !(GLRO (dl_hwcap) & HWCAP_S390_HIGH_GPRS)
53 #endif /* !__s390x__ */
54 )
55 {
56 /* stfle (or zarch, high-gprs on s390-32) is not available.
57 We are on an old machine. Return 256byte for LINESIZE for L1 d/i-cache,
58 otherwise 0. */
59 if (level == 1 && attr == CACHE_ATTR_LINESIZE)
60 return 256L;
61 else
62 return 0L;
63 }
64
65 /* Store facility list and check for z10.
66 (see ifunc-resolver for details) */
67 register unsigned long reg0 __asm__("0") = 0;
68 #ifdef __s390x__
69 unsigned long stfle_bits;
70 # define STFLE_Z10_MASK (1UL << (63 - 34))
71 #else
72 unsigned long long stfle_bits;
73 # define STFLE_Z10_MASK (1ULL << (63 - 34))
74 #endif /* !__s390x__ */
75 __asm__ __volatile__(".machine push" "\n\t"
76 ".machinemode \"zarch_nohighgprs\"\n\t"
77 ".machine \"z9-109\"" "\n\t"
78 "stfle %0" "\n\t"
79 ".machine pop" "\n"
80 : "=QS" (stfle_bits), "+d" (reg0)
81 : : "cc");
82
83 if (!(stfle_bits & STFLE_Z10_MASK))
84 {
85 /* We are at least on a z9 machine.
86 Return 256byte for LINESIZE for L1 d/i-cache,
87 otherwise 0. */
88 if (level == 1 && attr == CACHE_ATTR_LINESIZE)
89 return 256L;
90 else
91 return 0L;
92 }
93
94 /* Check cache topology, if cache is available at this level. */
95 arg = (CACHE_LEVEL_MAX - level) * 8;
96 __asm__ __volatile__ (".machine push\n\t"
97 ".machine \"z10\"\n\t"
98 ".machinemode \"zarch_nohighgprs\"\n\t"
99 "ecag %0,%%r0,0\n\t" /* returns 64bit unsigned integer. */
100 "srlg %0,%0,0(%1)\n\t" /* right align 8bit cache info field. */
101 ".machine pop"
102 : "=&d" (val)
103 : "a" (arg)
104 );
105 val &= 0xCUL; /* Extract cache scope information from cache topology summary.
106 (bits 4-5 of 8bit-field; 00 means cache does not exist). */
107 if (val == 0)
108 return 0L;
109
110 /* Get cache information for level, attribute and type. */
111 cmd = (attr << 4) | ((level - 1) << 1) | type;
112 __asm__ __volatile__ (".machine push\n\t"
113 ".machine \"z10\"\n\t"
114 ".machinemode \"zarch_nohighgprs\"\n\t"
115 "ecag %0,%%r0,0(%1)\n\t"
116 ".machine pop"
117 : "=d" (val)
118 : "a" (cmd)
119 );
120 return val;
121 }
122
123 long int
__sysconf(int name)124 __sysconf (int name)
125 {
126 if (name >= _SC_LEVEL1_ICACHE_SIZE && name <= _SC_LEVEL4_CACHE_LINESIZE)
127 {
128 int level;
129 int attr;
130 int type;
131
132 switch (name)
133 {
134 case _SC_LEVEL1_ICACHE_SIZE:
135 level = 1;
136 attr = CACHE_ATTR_SIZE;
137 type = CACHE_TYPE_INSTRUCTION;
138 break;
139 case _SC_LEVEL1_ICACHE_ASSOC:
140 level = 1;
141 attr = CACHE_ATTR_ASSOC;
142 type = CACHE_TYPE_INSTRUCTION;
143 break;
144 case _SC_LEVEL1_ICACHE_LINESIZE:
145 level = 1;
146 attr = CACHE_ATTR_LINESIZE;
147 type = CACHE_TYPE_INSTRUCTION;
148 break;
149
150 case _SC_LEVEL1_DCACHE_SIZE:
151 level = 1;
152 attr = CACHE_ATTR_SIZE;
153 type = CACHE_TYPE_DATA;
154 break;
155 case _SC_LEVEL1_DCACHE_ASSOC:
156 level = 1;
157 attr = CACHE_ATTR_ASSOC;
158 type = CACHE_TYPE_DATA;
159 break;
160 case _SC_LEVEL1_DCACHE_LINESIZE:
161 level = 1;
162 attr = CACHE_ATTR_LINESIZE;
163 type = CACHE_TYPE_DATA;
164 break;
165
166 case _SC_LEVEL2_CACHE_SIZE:
167 level = 2;
168 attr = CACHE_ATTR_SIZE;
169 type = CACHE_TYPE_DATA;
170 break;
171 case _SC_LEVEL2_CACHE_ASSOC:
172 level = 2;
173 attr = CACHE_ATTR_ASSOC;
174 type = CACHE_TYPE_DATA;
175 break;
176 case _SC_LEVEL2_CACHE_LINESIZE:
177 level = 2;
178 attr = CACHE_ATTR_LINESIZE;
179 type = CACHE_TYPE_DATA;
180 break;
181
182 case _SC_LEVEL3_CACHE_SIZE:
183 level = 3;
184 attr = CACHE_ATTR_SIZE;
185 type = CACHE_TYPE_DATA;
186 break;
187 case _SC_LEVEL3_CACHE_ASSOC:
188 level = 3;
189 attr = CACHE_ATTR_ASSOC;
190 type = CACHE_TYPE_DATA;
191 break;
192 case _SC_LEVEL3_CACHE_LINESIZE:
193 level = 3;
194 attr = CACHE_ATTR_LINESIZE;
195 type = CACHE_TYPE_DATA;
196 break;
197
198 case _SC_LEVEL4_CACHE_SIZE:
199 level = 4;
200 attr = CACHE_ATTR_SIZE;
201 type = CACHE_TYPE_DATA;
202 break;
203 case _SC_LEVEL4_CACHE_ASSOC:
204 level = 4;
205 attr = CACHE_ATTR_ASSOC;
206 type = CACHE_TYPE_DATA;
207 break;
208 case _SC_LEVEL4_CACHE_LINESIZE:
209 level = 4;
210 attr = CACHE_ATTR_LINESIZE;
211 type = CACHE_TYPE_DATA;
212 break;
213
214 default:
215 level = 0;
216 attr = 0;
217 type = 0;
218 break;
219 }
220
221 return get_cache_info (level, attr, type);
222 }
223
224 return linux_sysconf (name);
225 }
226
227 /* Now the generic Linux version. */
228 #undef __sysconf
229 #define __sysconf static linux_sysconf
230 #include <sysdeps/unix/sysv/linux/sysconf.c>
231