Merge tag 'trace-v5.2-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[sfrench/cifs-2.6.git] / arch / ia64 / kernel / esi.c
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... */