xref: /openbmc/linux/arch/ia64/kernel/esi.c (revision f20c7d91)
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... */
194