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