root/arch/s390/include/asm/machine.h
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright IBM Corp. 2024
 */

#ifndef __ASM_S390_MACHINE_H
#define __ASM_S390_MACHINE_H

#include <linux/const.h>

#define MFEATURE_LOWCORE        0
#define MFEATURE_PCI_MIO        1
#define MFEATURE_SCC            2
#define MFEATURE_TLB_GUEST      3
#define MFEATURE_TX             4
#define MFEATURE_ESOP           5
#define MFEATURE_DIAG9C         6
#define MFEATURE_VM             7
#define MFEATURE_KVM            8
#define MFEATURE_LPAR           9
#define MFEATURE_DIAG288        10

#ifndef __ASSEMBLER__

#include <linux/bitops.h>
#include <asm/alternative.h>

extern unsigned long machine_features[1];

#define MAX_MFEATURE_BIT (sizeof(machine_features) * BITS_PER_BYTE)

static inline void __set_machine_feature(unsigned int nr, unsigned long *mfeatures)
{
        if (nr >= MAX_MFEATURE_BIT)
                return;
        __set_bit(nr, mfeatures);
}

static inline void set_machine_feature(unsigned int nr)
{
        __set_machine_feature(nr, machine_features);
}

static inline void __clear_machine_feature(unsigned int nr, unsigned long *mfeatures)
{
        if (nr >= MAX_MFEATURE_BIT)
                return;
        __clear_bit(nr, mfeatures);
}

static inline void clear_machine_feature(unsigned int nr)
{
        __clear_machine_feature(nr, machine_features);
}

static bool __test_machine_feature(unsigned int nr, unsigned long *mfeatures)
{
        if (nr >= MAX_MFEATURE_BIT)
                return false;
        return test_bit(nr, mfeatures);
}

static bool test_machine_feature(unsigned int nr)
{
        return __test_machine_feature(nr, machine_features);
}

static __always_inline bool __test_machine_feature_constant(unsigned int nr)
{
        asm goto(
                ALTERNATIVE("brcl 15,%l[l_no]", "brcl 0,0", ALT_FEATURE(%[nr]))
                :
                : [nr] "i" (nr)
                :
                : l_no);
        return true;
l_no:
        return false;
}

#define DEFINE_MACHINE_HAS_FEATURE(name, feature)                               \
static __always_inline bool machine_has_##name(void)                            \
{                                                                               \
        if (!__is_defined(__DECOMPRESSOR) && __builtin_constant_p(feature))     \
                return __test_machine_feature_constant(feature);                \
        return test_machine_feature(feature);                                   \
}

DEFINE_MACHINE_HAS_FEATURE(relocated_lowcore, MFEATURE_LOWCORE)
DEFINE_MACHINE_HAS_FEATURE(scc, MFEATURE_SCC)
DEFINE_MACHINE_HAS_FEATURE(tlb_guest, MFEATURE_TLB_GUEST)
DEFINE_MACHINE_HAS_FEATURE(tx, MFEATURE_TX)
DEFINE_MACHINE_HAS_FEATURE(esop, MFEATURE_ESOP)
DEFINE_MACHINE_HAS_FEATURE(diag9c, MFEATURE_DIAG9C)
DEFINE_MACHINE_HAS_FEATURE(vm, MFEATURE_VM)
DEFINE_MACHINE_HAS_FEATURE(kvm, MFEATURE_KVM)
DEFINE_MACHINE_HAS_FEATURE(lpar, MFEATURE_LPAR)

#define machine_is_vm   machine_has_vm
#define machine_is_kvm  machine_has_kvm
#define machine_is_lpar machine_has_lpar

#endif /* __ASSEMBLER__ */
#endif /* __ASM_S390_MACHINE_H */