esi.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Extensible SAL Interface (ESI) support routines.
  4. *
  5. * Copyright (C) 2006 Hewlett-Packard Co
  6. * Alex Williamson <[email protected]>
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/init.h>
  10. #include <linux/module.h>
  11. #include <linux/string.h>
  12. #include <asm/esi.h>
  13. #include <asm/sal.h>
  14. MODULE_AUTHOR("Alex Williamson <[email protected]>");
  15. MODULE_DESCRIPTION("Extensible SAL Interface (ESI) support");
  16. MODULE_LICENSE("GPL");
  17. #define MODULE_NAME "esi"
  18. enum esi_systab_entry_type {
  19. ESI_DESC_ENTRY_POINT = 0
  20. };
  21. /*
  22. * Entry type: Size:
  23. * 0 48
  24. */
  25. #define ESI_DESC_SIZE(type) "\060"[(unsigned) (type)]
  26. typedef struct ia64_esi_desc_entry_point {
  27. u8 type;
  28. u8 reserved1[15];
  29. u64 esi_proc;
  30. u64 gp;
  31. efi_guid_t guid;
  32. } ia64_esi_desc_entry_point_t;
  33. struct pdesc {
  34. void *addr;
  35. void *gp;
  36. };
  37. static struct ia64_sal_systab *esi_systab;
  38. extern unsigned long esi_phys;
  39. static int __init esi_init (void)
  40. {
  41. struct ia64_sal_systab *systab;
  42. char *p;
  43. int i;
  44. if (esi_phys == EFI_INVALID_TABLE_ADDR)
  45. return -ENODEV;
  46. systab = __va(esi_phys);
  47. if (strncmp(systab->signature, "ESIT", 4) != 0) {
  48. printk(KERN_ERR "bad signature in ESI system table!");
  49. return -ENODEV;
  50. }
  51. p = (char *) (systab + 1);
  52. for (i = 0; i < systab->entry_count; i++) {
  53. /*
  54. * The first byte of each entry type contains the type
  55. * descriptor.
  56. */
  57. switch (*p) {
  58. case ESI_DESC_ENTRY_POINT:
  59. break;
  60. default:
  61. printk(KERN_WARNING "Unknown table type %d found in "
  62. "ESI table, ignoring rest of table\n", *p);
  63. return -ENODEV;
  64. }
  65. p += ESI_DESC_SIZE(*p);
  66. }
  67. esi_systab = systab;
  68. return 0;
  69. }
  70. int ia64_esi_call (efi_guid_t guid, struct ia64_sal_retval *isrvp,
  71. enum esi_proc_type proc_type, u64 func,
  72. u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6,
  73. u64 arg7)
  74. {
  75. struct ia64_fpreg fr[6];
  76. unsigned long flags = 0;
  77. int i;
  78. char *p;
  79. if (!esi_systab)
  80. return -1;
  81. p = (char *) (esi_systab + 1);
  82. for (i = 0; i < esi_systab->entry_count; i++) {
  83. if (*p == ESI_DESC_ENTRY_POINT) {
  84. ia64_esi_desc_entry_point_t *esi = (void *)p;
  85. if (!efi_guidcmp(guid, esi->guid)) {
  86. ia64_sal_handler esi_proc;
  87. struct pdesc pdesc;
  88. pdesc.addr = __va(esi->esi_proc);
  89. pdesc.gp = __va(esi->gp);
  90. esi_proc = (ia64_sal_handler) &pdesc;
  91. ia64_save_scratch_fpregs(fr);
  92. if (proc_type == ESI_PROC_SERIALIZED)
  93. spin_lock_irqsave(&sal_lock, flags);
  94. else if (proc_type == ESI_PROC_MP_SAFE)
  95. local_irq_save(flags);
  96. else
  97. preempt_disable();
  98. *isrvp = (*esi_proc)(func, arg1, arg2, arg3,
  99. arg4, arg5, arg6, arg7);
  100. if (proc_type == ESI_PROC_SERIALIZED)
  101. spin_unlock_irqrestore(&sal_lock,
  102. flags);
  103. else if (proc_type == ESI_PROC_MP_SAFE)
  104. local_irq_restore(flags);
  105. else
  106. preempt_enable();
  107. ia64_load_scratch_fpregs(fr);
  108. return 0;
  109. }
  110. }
  111. p += ESI_DESC_SIZE(*p);
  112. }
  113. return -1;
  114. }
  115. EXPORT_SYMBOL_GPL(ia64_esi_call);
  116. int ia64_esi_call_phys (efi_guid_t guid, struct ia64_sal_retval *isrvp,
  117. u64 func, u64 arg1, u64 arg2, u64 arg3, u64 arg4,
  118. u64 arg5, u64 arg6, u64 arg7)
  119. {
  120. struct ia64_fpreg fr[6];
  121. unsigned long flags;
  122. u64 esi_params[8];
  123. char *p;
  124. int i;
  125. if (!esi_systab)
  126. return -1;
  127. p = (char *) (esi_systab + 1);
  128. for (i = 0; i < esi_systab->entry_count; i++) {
  129. if (*p == ESI_DESC_ENTRY_POINT) {
  130. ia64_esi_desc_entry_point_t *esi = (void *)p;
  131. if (!efi_guidcmp(guid, esi->guid)) {
  132. ia64_sal_handler esi_proc;
  133. struct pdesc pdesc;
  134. pdesc.addr = (void *)esi->esi_proc;
  135. pdesc.gp = (void *)esi->gp;
  136. esi_proc = (ia64_sal_handler) &pdesc;
  137. esi_params[0] = func;
  138. esi_params[1] = arg1;
  139. esi_params[2] = arg2;
  140. esi_params[3] = arg3;
  141. esi_params[4] = arg4;
  142. esi_params[5] = arg5;
  143. esi_params[6] = arg6;
  144. esi_params[7] = arg7;
  145. ia64_save_scratch_fpregs(fr);
  146. spin_lock_irqsave(&sal_lock, flags);
  147. *isrvp = esi_call_phys(esi_proc, esi_params);
  148. spin_unlock_irqrestore(&sal_lock, flags);
  149. ia64_load_scratch_fpregs(fr);
  150. return 0;
  151. }
  152. }
  153. p += ESI_DESC_SIZE(*p);
  154. }
  155. return -1;
  156. }
  157. EXPORT_SYMBOL_GPL(ia64_esi_call_phys);
  158. static void __exit esi_exit (void)
  159. {
  160. }
  161. module_init(esi_init);
  162. module_exit(esi_exit); /* makes module removable... */