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