From patchwork Fri Apr 17 13:31:34 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Liebler X-Patchwork-Id: 6299 Received: (qmail 44791 invoked by alias); 17 Apr 2015 13:31:54 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 44779 invoked by uid 89); 17 Apr 2015 13:31:53 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.5 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_HELO_PASS, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: plane.gmane.org To: libc-alpha@sourceware.org From: Stefan Liebler Subject: [PATCH] S390: Get cache information via sysconf. Date: Fri, 17 Apr 2015 15:31:34 +0200 Lines: 270 Message-ID: Mime-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.6.0 Hi, this patch adds support to query cache information on s390 via sysconf() function - e.g. with _SC_LEVEL1_ICACHE_SIZE. The attributes size, linesize and assoc can be queried for cache level 1 - 4 via "extract cpu attribute" instruction, which was first available with z10. Tested on s390/s390x. Ok to commit? Bye Stefan --- 2015-04-17 Stefan Liebler * sysdeps/unix/sysv/linux/s390/sysconf.c: New File. diff --git a/sysdeps/unix/sysv/linux/s390/sysconf.c b/sysdeps/unix/sysv/linux/s390/sysconf.c new file mode 100644 index 0000000..ac9ddb1 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/sysconf.c @@ -0,0 +1,230 @@ +/* Get system parameters, e.g. cache information. S390/S390x version. + Copyright (C) 2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#include +#include + +static long int __linux_sysconf (int name); + +/* Possible arguments for __getCacheInfo. + The values are reflecting the level/attribute/type indications + of ecag-instruction (extract cpu attribue). */ +#define CACHE_LEVEL_MAX 8 +#define CACHE_ATTR_LINESIZE 1 +#define CACHE_ATTR_SIZE 2 +#define CACHE_ATTR_ASSOC 3 +#define CACHE_TYPE_DATA 0 +#define CACHE_TYPE_INSTRUCTION 1 + +static long +__getCacheInfo (int level, int attr, int type) +{ + unsigned long int val; + unsigned int cmd; + unsigned long int arg; + + /* check arguments. */ + if ((level < 1 || level > CACHE_LEVEL_MAX) + || (attr < CACHE_ATTR_LINESIZE || attr > CACHE_ATTR_ASSOC) + || (type < CACHE_TYPE_DATA || type > CACHE_TYPE_INSTRUCTION)) + return 0L; + + /* check if ecag-instruction is available. */ + /* ecag - extract CPU attribute (only in zarch; arch >= z10; in as 2.24) */ + if (((GLRO (dl_hwcap) & HWCAP_S390_STFLE) == 0) +#if !defined __s390x__ + || ((GLRO (dl_hwcap) & HWCAP_S390_ZARCH) == 0) + || ((GLRO (dl_hwcap) & HWCAP_S390_HIGH_GPRS) == 0) +#endif + ) + { + /* stfle (or zarch, high-gprs on s390-32) is not available. + We are on an old machine. Return 256byte for LINESIZE for L1 d/i-cache, + otherwise 0. */ + if (level == 1 && attr == CACHE_ATTR_LINESIZE) + return 256L; + else + return 0L; + } + + /* store facility list and check for z10. + (see ifunc-resolver for details) */ + register unsigned long reg0 asm("0") = 0; +#ifdef __s390x__ + unsigned long stfle_bits; +# define STFLE_Z10_MASK (1UL << (63 - 34)) +#else + unsigned long long stfle_bits; +# define STFLE_Z10_MASK (1ULL << (63 - 34)) +#endif + asm volatile(".machine push" "\n\t" + ".machinemode \"zarch_nohighgprs\"\n\t" + ".machine \"z9-109\"" "\n\t" + "stfle %0" "\n\t" + ".machine pop" "\n" + : "=QS" (stfle_bits), "+d" (reg0) + : : "cc"); + + if ((stfle_bits & STFLE_Z10_MASK) == 0) + { + /* We are at least on a z9 machine. + Return 256byte for LINESIZE for L1 d/i-cache, + otherwise 0. */ + if (level == 1 && attr == CACHE_ATTR_LINESIZE) + return 256L; + else + return 0L; + } + + /* check cache topology, if cache is available at this level. */ + arg = (CACHE_LEVEL_MAX - level) * 8; + asm volatile (".machine push\n\t" + ".machine \"z10\"\n\t" + ".machinemode \"zarch_nohighgprs\"\n\t" + "ecag %0,%%r0,0\n\t" /* returns 64bit unsigned integer. */ + "srlg %0,%0,0(%1)\n\t" /* right align 8bit cache info field. */ + ".machine pop" + : "=&d" (val) + : "a" (arg) + ); + val &= 0xCUL; /* extract cache scope information from cache topology summary. + (bits 4-5 of 8bit-field; 00 means cache does not exist). */ + if (val == 0) + return 0L; + + /* get cache information for level, attribute and type. */ + cmd = (attr << 4) | ((level - 1) << 1) | type; + asm volatile (".machine push\n\t" + ".machine \"z10\"\n\t" + ".machinemode \"zarch_nohighgprs\"\n\t" + "ecag %0,%%r0,0(%1)\n\t" + ".machine pop" + : "=d" (val) + : "a" (cmd) + ); + return val; +} + +long int +__sysconf (int name) +{ + if (name >= _SC_LEVEL1_ICACHE_SIZE && name <= _SC_LEVEL4_CACHE_LINESIZE) + { + int level; + int attr; + int type; + + switch (name) + { + case _SC_LEVEL1_ICACHE_SIZE: + level = 1; + attr = CACHE_ATTR_SIZE; + type = CACHE_TYPE_INSTRUCTION; + break; + case _SC_LEVEL1_ICACHE_ASSOC: + level = 1; + attr = CACHE_ATTR_ASSOC; + type = CACHE_TYPE_INSTRUCTION; + break; + case _SC_LEVEL1_ICACHE_LINESIZE: + level = 1; + attr = CACHE_ATTR_LINESIZE; + type = CACHE_TYPE_INSTRUCTION; + break; + + case _SC_LEVEL1_DCACHE_SIZE: + level = 1; + attr = CACHE_ATTR_SIZE; + type = CACHE_TYPE_DATA; + break; + case _SC_LEVEL1_DCACHE_ASSOC: + level = 1; + attr = CACHE_ATTR_ASSOC; + type = CACHE_TYPE_DATA; + break; + case _SC_LEVEL1_DCACHE_LINESIZE: + level = 1; + attr = CACHE_ATTR_LINESIZE; + type = CACHE_TYPE_DATA; + break; + + case _SC_LEVEL2_CACHE_SIZE: + level = 2; + attr = CACHE_ATTR_SIZE; + type = CACHE_TYPE_DATA; + break; + case _SC_LEVEL2_CACHE_ASSOC: + level = 2; + attr = CACHE_ATTR_ASSOC; + type = CACHE_TYPE_DATA; + break; + case _SC_LEVEL2_CACHE_LINESIZE: + level = 2; + attr = CACHE_ATTR_LINESIZE; + type = CACHE_TYPE_DATA; + break; + + case _SC_LEVEL3_CACHE_SIZE: + level = 3; + attr = CACHE_ATTR_SIZE; + type = CACHE_TYPE_DATA; + break; + case _SC_LEVEL3_CACHE_ASSOC: + level = 3; + attr = CACHE_ATTR_ASSOC; + type = CACHE_TYPE_DATA; + break; + case _SC_LEVEL3_CACHE_LINESIZE: + level = 3; + attr = CACHE_ATTR_LINESIZE; + type = CACHE_TYPE_DATA; + break; + + case _SC_LEVEL4_CACHE_SIZE: + level = 4; + attr = CACHE_ATTR_SIZE; + type = CACHE_TYPE_DATA; + break; + case _SC_LEVEL4_CACHE_ASSOC: + level = 4; + attr = CACHE_ATTR_ASSOC; + type = CACHE_TYPE_DATA; + break; + case _SC_LEVEL4_CACHE_LINESIZE: + level = 4; + attr = CACHE_ATTR_LINESIZE; + type = CACHE_TYPE_DATA; + break; + + default: + level = 0; + attr = 0; + type = 0; + break; + } + + return __getCacheInfo (level, attr, type); + } + + return __linux_sysconf (name); +} + +/* Now the generic Linux version. */ +#undef __sysconf +#define __sysconf static __linux_sysconf +#include