1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright IBM Corp. 1999, 2009 4 * 5 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 6 */ 7 8 #ifndef __ASM_FACILITY_H 9 #define __ASM_FACILITY_H 10 11 #include <asm/facility-defs.h> 12 #include <linux/string.h> 13 #include <linux/preempt.h> 14 #include <asm/lowcore.h> 15 16 #define MAX_FACILITY_BIT (sizeof(stfle_fac_list) * 8) 17 18 extern u64 stfle_fac_list[16]; 19 extern u64 alt_stfle_fac_list[16]; 20 21 static inline void __set_facility(unsigned long nr, void *facilities) 22 { 23 unsigned char *ptr = (unsigned char *) facilities; 24 25 if (nr >= MAX_FACILITY_BIT) 26 return; 27 ptr[nr >> 3] |= 0x80 >> (nr & 7); 28 } 29 30 static inline void __clear_facility(unsigned long nr, void *facilities) 31 { 32 unsigned char *ptr = (unsigned char *) facilities; 33 34 if (nr >= MAX_FACILITY_BIT) 35 return; 36 ptr[nr >> 3] &= ~(0x80 >> (nr & 7)); 37 } 38 39 static inline int __test_facility(unsigned long nr, void *facilities) 40 { 41 unsigned char *ptr; 42 43 if (nr >= MAX_FACILITY_BIT) 44 return 0; 45 ptr = (unsigned char *) facilities + (nr >> 3); 46 return (*ptr & (0x80 >> (nr & 7))) != 0; 47 } 48 49 /* 50 * The test_facility function uses the bit ordering where the MSB is bit 0. 51 * That makes it easier to query facility bits with the bit number as 52 * documented in the Principles of Operation. 53 */ 54 static inline int test_facility(unsigned long nr) 55 { 56 unsigned long facilities_als[] = { FACILITIES_ALS }; 57 58 if (__builtin_constant_p(nr) && nr < sizeof(facilities_als) * 8) { 59 if (__test_facility(nr, &facilities_als)) 60 return 1; 61 } 62 return __test_facility(nr, &stfle_fac_list); 63 } 64 65 static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size) 66 { 67 unsigned long reg0 = size - 1; 68 69 asm volatile( 70 " lgr 0,%[reg0]\n" 71 " .insn s,0xb2b00000,%[list]\n" /* stfle */ 72 " lgr %[reg0],0\n" 73 : [reg0] "+&d" (reg0), [list] "+Q" (*stfle_fac_list) 74 : 75 : "memory", "cc", "0"); 76 return reg0; 77 } 78 79 /** 80 * stfle - Store facility list extended 81 * @stfle_fac_list: array where facility list can be stored 82 * @size: size of passed in array in double words 83 */ 84 static inline void __stfle(u64 *stfle_fac_list, int size) 85 { 86 unsigned long nr; 87 u32 stfl_fac_list; 88 89 asm volatile( 90 " stfl 0(0)\n" 91 : "=m" (S390_lowcore.stfl_fac_list)); 92 stfl_fac_list = S390_lowcore.stfl_fac_list; 93 memcpy(stfle_fac_list, &stfl_fac_list, 4); 94 nr = 4; /* bytes stored by stfl */ 95 if (stfl_fac_list & 0x01000000) { 96 /* More facility bits available with stfle */ 97 nr = __stfle_asm(stfle_fac_list, size); 98 nr = min_t(unsigned long, (nr + 1) * 8, size * 8); 99 } 100 memset((char *) stfle_fac_list + nr, 0, size * 8 - nr); 101 } 102 103 static inline void stfle(u64 *stfle_fac_list, int size) 104 { 105 preempt_disable(); 106 __stfle(stfle_fac_list, size); 107 preempt_enable(); 108 } 109 110 #endif /* __ASM_FACILITY_H */ 111