Loading...
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
16MODULE_AUTHOR("Alex Williamson <alex.williamson@hp.com>");
17MODULE_DESCRIPTION("Extensible SAL Interface (ESI) support");
18MODULE_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
26enum 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
36typedef 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
44struct pdesc {
45 void *addr;
46 void *gp;
47};
48
49static struct ia64_sal_systab *esi_systab;
50
51static 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
101int 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}
151EXPORT_SYMBOL_GPL(ia64_esi_call);
152
153int 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}
199EXPORT_SYMBOL_GPL(ia64_esi_call_phys);
200
201static void __exit esi_exit (void)
202{
203}
204
205module_init(esi_init);
206module_exit(esi_exit); /* makes module removable... */
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
15MODULE_AUTHOR("Alex Williamson <alex.williamson@hp.com>");
16MODULE_DESCRIPTION("Extensible SAL Interface (ESI) support");
17MODULE_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
25enum 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
35typedef 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
43struct pdesc {
44 void *addr;
45 void *gp;
46};
47
48static struct ia64_sal_systab *esi_systab;
49
50static 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
100int 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}
150EXPORT_SYMBOL_GPL(ia64_esi_call);
151
152int 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}
198EXPORT_SYMBOL_GPL(ia64_esi_call_phys);
199
200static void __exit esi_exit (void)
201{
202}
203
204module_init(esi_init);
205module_exit(esi_exit); /* makes module removable... */