esi.c 4.5 KB

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