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