1/* Get system parameters, e.g. cache information. S390/S390x version.
2 Copyright (C) 2015-2024 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#include <cpu-features.h>
22
23static long int linux_sysconf (int name);
24
25/* Possible arguments for get_cache_info.
26 The values are reflecting the level/attribute/type indications
27 of ecag-instruction (extract cpu attribute). */
28#define CACHE_LEVEL_MAX 8
29#define CACHE_ATTR_LINESIZE 1
30#define CACHE_ATTR_SIZE 2
31#define CACHE_ATTR_ASSOC 3
32#define CACHE_TYPE_DATA 0
33#define CACHE_TYPE_INSTRUCTION 1
34
35static long
36get_cache_info (int level, int attr, int type)
37{
38 unsigned long int val;
39 unsigned int cmd;
40 unsigned long int arg;
41
42 /* Check arguments. */
43 if (level < 1 || level > CACHE_LEVEL_MAX
44 || attr < CACHE_ATTR_LINESIZE || attr > CACHE_ATTR_ASSOC
45 || type < CACHE_TYPE_DATA || type > CACHE_TYPE_INSTRUCTION)
46 return 0L;
47
48 const struct cpu_features *features = &GLRO(dl_s390_cpu_features);
49
50 /* Check if ecag-instruction is available.
51 ecag - extract CPU attribute (only in zarch; arch >= z10; in as 2.24) */
52 if (!(features->hwcap & HWCAP_S390_STFLE)
53#if !defined __s390x__
54 || !(features->hwcap & HWCAP_S390_ZARCH)
55 || !(features->hwcap & HWCAP_S390_HIGH_GPRS)
56#endif /* !__s390x__ */
57 )
58 {
59 /* stfle (or zarch, high-gprs on s390-32) is not available.
60 We are on an old machine. Return 256byte for LINESIZE for L1 d/i-cache,
61 otherwise 0. */
62 if (level == 1 && attr == CACHE_ATTR_LINESIZE)
63 return 256L;
64 else
65 return 0L;
66 }
67
68 if (!S390_IS_Z10 (features->stfle_bits))
69 {
70 /* We are at least on a z9 machine.
71 Return 256byte for LINESIZE for L1 d/i-cache,
72 otherwise 0. */
73 if (level == 1 && attr == CACHE_ATTR_LINESIZE)
74 return 256L;
75 else
76 return 0L;
77 }
78
79 /* Check cache topology, if cache is available at this level. */
80 arg = (CACHE_LEVEL_MAX - level) * 8;
81 __asm__ __volatile__ (".machine push\n\t"
82 ".machine \"z10\"\n\t"
83 ".machinemode \"zarch_nohighgprs\"\n\t"
84 "ecag %0,%%r0,0\n\t" /* returns 64bit unsigned integer. */
85 "srlg %0,%0,0(%1)\n\t" /* right align 8bit cache info field. */
86 ".machine pop"
87 : "=&d" (val)
88 : "a" (arg)
89 );
90 val &= 0xCUL; /* Extract cache scope information from cache topology summary.
91 (bits 4-5 of 8bit-field; 00 means cache does not exist). */
92 if (val == 0)
93 return 0L;
94
95 /* Get cache information for level, attribute and type. */
96 cmd = (attr << 4) | ((level - 1) << 1) | type;
97 __asm__ __volatile__ (".machine push\n\t"
98 ".machine \"z10\"\n\t"
99 ".machinemode \"zarch_nohighgprs\"\n\t"
100 "ecag %0,%%r0,0(%1)\n\t"
101 ".machine pop"
102 : "=d" (val)
103 : "a" (cmd)
104 );
105 return val;
106}
107
108long int
109__sysconf (int name)
110{
111 if (name >= _SC_LEVEL1_ICACHE_SIZE && name <= _SC_LEVEL4_CACHE_LINESIZE)
112 {
113 int level;
114 int attr;
115 int type;
116
117 switch (name)
118 {
119 case _SC_LEVEL1_ICACHE_SIZE:
120 level = 1;
121 attr = CACHE_ATTR_SIZE;
122 type = CACHE_TYPE_INSTRUCTION;
123 break;
124 case _SC_LEVEL1_ICACHE_ASSOC:
125 level = 1;
126 attr = CACHE_ATTR_ASSOC;
127 type = CACHE_TYPE_INSTRUCTION;
128 break;
129 case _SC_LEVEL1_ICACHE_LINESIZE:
130 level = 1;
131 attr = CACHE_ATTR_LINESIZE;
132 type = CACHE_TYPE_INSTRUCTION;
133 break;
134
135 case _SC_LEVEL1_DCACHE_SIZE:
136 level = 1;
137 attr = CACHE_ATTR_SIZE;
138 type = CACHE_TYPE_DATA;
139 break;
140 case _SC_LEVEL1_DCACHE_ASSOC:
141 level = 1;
142 attr = CACHE_ATTR_ASSOC;
143 type = CACHE_TYPE_DATA;
144 break;
145 case _SC_LEVEL1_DCACHE_LINESIZE:
146 level = 1;
147 attr = CACHE_ATTR_LINESIZE;
148 type = CACHE_TYPE_DATA;
149 break;
150
151 case _SC_LEVEL2_CACHE_SIZE:
152 level = 2;
153 attr = CACHE_ATTR_SIZE;
154 type = CACHE_TYPE_DATA;
155 break;
156 case _SC_LEVEL2_CACHE_ASSOC:
157 level = 2;
158 attr = CACHE_ATTR_ASSOC;
159 type = CACHE_TYPE_DATA;
160 break;
161 case _SC_LEVEL2_CACHE_LINESIZE:
162 level = 2;
163 attr = CACHE_ATTR_LINESIZE;
164 type = CACHE_TYPE_DATA;
165 break;
166
167 case _SC_LEVEL3_CACHE_SIZE:
168 level = 3;
169 attr = CACHE_ATTR_SIZE;
170 type = CACHE_TYPE_DATA;
171 break;
172 case _SC_LEVEL3_CACHE_ASSOC:
173 level = 3;
174 attr = CACHE_ATTR_ASSOC;
175 type = CACHE_TYPE_DATA;
176 break;
177 case _SC_LEVEL3_CACHE_LINESIZE:
178 level = 3;
179 attr = CACHE_ATTR_LINESIZE;
180 type = CACHE_TYPE_DATA;
181 break;
182
183 case _SC_LEVEL4_CACHE_SIZE:
184 level = 4;
185 attr = CACHE_ATTR_SIZE;
186 type = CACHE_TYPE_DATA;
187 break;
188 case _SC_LEVEL4_CACHE_ASSOC:
189 level = 4;
190 attr = CACHE_ATTR_ASSOC;
191 type = CACHE_TYPE_DATA;
192 break;
193 case _SC_LEVEL4_CACHE_LINESIZE:
194 level = 4;
195 attr = CACHE_ATTR_LINESIZE;
196 type = CACHE_TYPE_DATA;
197 break;
198
199 default:
200 level = 0;
201 attr = 0;
202 type = 0;
203 break;
204 }
205
206 return get_cache_info (level, attr, type);
207 }
208
209 return linux_sysconf (name);
210}
211
212/* Now the generic Linux version. */
213#undef __sysconf
214#define __sysconf static linux_sysconf
215#include <sysdeps/unix/sysv/linux/sysconf.c>
216

source code of glibc/sysdeps/unix/sysv/linux/s390/sysconf.c