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