linux/arch/s390/include/asm/facility.h
<<
>>
Prefs
   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
  18extern u64 stfle_fac_list[16];
  19extern u64 alt_stfle_fac_list[16];
  20
  21static 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
  30static 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
  39static 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 */
  54static 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
  65static 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 */
  84static 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
 103static 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