facility.h 2.7 KB

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