(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
s390/
sysconf.c
       1  /* Get system parameters, e.g. cache information.  S390/S390x version.
       2     Copyright (C) 2015-2023 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  
      23  static 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  
      35  static long
      36  get_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  
     108  long 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>