Merge branch 'pcmcia-next' of git://git.kernel.org/pub/scm/linux/kernel/git/brodo...
[linux-2.6-microblaze.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 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... */