1 /* Copyright 2013-2014 IBM Corp.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 * implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <skiboot.h>
17 #include <fsp.h>
18 #include <opal.h>
19 #include <device.h>
20 #include <lock.h>
21 #include <processor.h>
22 #include <psi.h>
23 #include <opal-msg.h>
24 #include <fsp-sysparam.h>
25
26 struct sysparam_comp_data {
27 uint32_t param_len;
28 uint64_t async_token;
29 };
30
31 struct sysparam_req {
32 sysparam_compl_t completion;
33 void *comp_data;
34 void *ubuf;
35 uint32_t ulen;
36 struct fsp_msg msg;
37 struct fsp_msg resp;
38 bool done;
39 };
40
41 static struct sysparam_attr {
42 const char *name;
43 uint32_t id;
44 uint32_t length;
45 uint8_t perm;
46 } sysparam_attrs[] = {
47 #define _R OPAL_SYSPARAM_READ
48 #define _W OPAL_SYSPARAM_WRITE
49 #define _RW OPAL_SYSPARAM_RW
50 {"surveillance", SYS_PARAM_SURV, 4, _RW},
51 {"hmc-management", SYS_PARAM_HMC_MANAGED, 4, _R},
52 {"cupd-policy", SYS_PARAM_FLASH_POLICY, 4, _RW},
53 {"plat-hmc-managed", SYS_PARAM_NEED_HMC, 4, _RW},
54 {"fw-license-policy", SYS_PARAM_FW_LICENSE, 4, _RW},
55 {"world-wide-port-num", SYS_PARAM_WWPN, 12, _W},
56 {"default-boot-device", SYS_PARAM_DEF_BOOT_DEV, 1, _RW},
57 {"next-boot-device", SYS_PARAM_NEXT_BOOT_DEV,1, _RW},
58 {"console-select", SYS_PARAM_CONSOLE_SELECT,1, _RW},
59 {"boot-device-path", SYS_PARAM_BOOT_DEV_PATH,48, _RW}
60 #undef _R
61 #undef _W
62 #undef _RW
63 };
64
fsp_sysparam_process(struct sysparam_req * r)65 static int fsp_sysparam_process(struct sysparam_req *r)
66 {
67 u32 param_id, len;
68 int stlen = 0;
69 u8 fstat;
70 /* Snapshot completion before we set the "done" flag */
71 sysparam_compl_t comp = r->completion;
72 void *cdata = r->comp_data;
73
74 if (r->msg.state != fsp_msg_done) {
75 prerror("FSP: Request for sysparam 0x%x got FSP failure!\n",
76 r->msg.data.words[0]);
77 stlen = -1; /* XXX Find saner error codes */
78 goto complete;
79 }
80
81 param_id = r->resp.data.words[0];
82 len = r->resp.data.words[1] & 0xffff;
83
84 /* Check params validity */
85 if (param_id != r->msg.data.words[0]) {
86 prerror("FSP: Request for sysparam 0x%x got resp. for 0x%x!\n",
87 r->msg.data.words[0], param_id);
88 stlen = -2; /* XXX Sane error codes */
89 goto complete;
90 }
91 if (len > r->ulen) {
92 prerror("FSP: Request for sysparam 0x%x truncated!\n",
93 param_id);
94 len = r->ulen;
95 }
96
97 /* Decode the request status */
98 fstat = (r->msg.resp->word1 >> 8) & 0xff;
99 switch(fstat) {
100 case 0x00: /* XXX Is that even possible ? */
101 case 0x11: /* Data in request */
102 memcpy(r->ubuf, &r->resp.data.words[2], len);
103 /* fallthrough */
104 case 0x12: /* Data in TCE */
105 stlen = len;
106 break;
107 default:
108 stlen = -fstat;
109 }
110 complete:
111 /* Call completion if any */
112 if (comp)
113 comp(r->msg.data.words[0], stlen, cdata);
114
115 free(r);
116
117 return stlen;
118 }
119
fsp_sysparam_get_complete(struct fsp_msg * msg)120 static void fsp_sysparam_get_complete(struct fsp_msg *msg)
121 {
122 struct sysparam_req *r = container_of(msg, struct sysparam_req, msg);
123
124 /* If it's an asynchronous request, process it now */
125 if (r->completion) {
126 fsp_sysparam_process(r);
127 return;
128 }
129
130 /* Else just set the done flag */
131
132 /* Another CPU can be polling on the "done" flag without the
133 * lock held, so let's order the udpates to the structure
134 */
135 lwsync();
136 r->done = true;
137 }
138
fsp_get_sys_param(uint32_t param_id,void * buffer,uint32_t length,sysparam_compl_t async_complete,void * comp_data)139 int fsp_get_sys_param(uint32_t param_id, void *buffer, uint32_t length,
140 sysparam_compl_t async_complete, void *comp_data)
141 {
142 struct sysparam_req *r;
143 uint64_t baddr, tce_token;
144 int rc;
145
146 if (!fsp_present())
147 return -ENODEV;
148 /*
149 * XXX FIXME: We currently always allocate the sysparam_req here
150 * however, we want to avoid runtime allocations as much as
151 * possible, so if this is going to be used a lot at runtime,
152 * we probably want to pre-allocate a pool of these
153 */
154 if (length > 4096)
155 return -EINVAL;
156 r = zalloc(sizeof(struct sysparam_req));
157 if (!r)
158 return -ENOMEM;
159 r->completion = async_complete;
160 r->comp_data = comp_data;
161 r->done = false;
162 r->ubuf = buffer;
163 r->ulen = length;
164 r->msg.resp = &r->resp;
165
166 /* Map always 1 page ... easier that way and none of that
167 * is performance critical
168 */
169 baddr = (uint64_t)buffer;
170 fsp_tce_map(PSI_DMA_GET_SYSPARAM, (void *)(baddr & ~0xffful), 0x1000);
171 tce_token = PSI_DMA_GET_SYSPARAM | (baddr & 0xfff);
172 fsp_fillmsg(&r->msg, FSP_CMD_QUERY_SPARM, 3,
173 param_id, length, tce_token);
174 rc = fsp_queue_msg(&r->msg, fsp_sysparam_get_complete);
175
176 if (rc)
177 free(r);
178
179 /* Asynchronous operation or queueing failure, return */
180 if (rc || async_complete)
181 return rc;
182
183 /* Synchronous operation requested, spin and process */
184 while(!r->done)
185 opal_run_pollers();
186
187 /* Will free the request */
188 return fsp_sysparam_process(r);
189 }
190
fsp_opal_getparam_complete(uint32_t param_id __unused,int err_len,void * data)191 static void fsp_opal_getparam_complete(uint32_t param_id __unused, int err_len,
192 void *data)
193 {
194 struct sysparam_comp_data *comp_data = data;
195 int rc = OPAL_SUCCESS;
196
197 if (comp_data->param_len != err_len)
198 rc = OPAL_INTERNAL_ERROR;
199
200 opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL,
201 comp_data->async_token, rc);
202 free(comp_data);
203 }
204
fsp_opal_setparam_complete(struct fsp_msg * msg)205 static void fsp_opal_setparam_complete(struct fsp_msg *msg)
206 {
207 struct sysparam_comp_data *comp_data = msg->user_data;
208 u8 fstat;
209 uint32_t param_id;
210 int rc = OPAL_SUCCESS;
211
212 if (msg->state != fsp_msg_done) {
213 prerror("FSP: Request for set sysparam 0x%x got FSP failure!\n",
214 msg->data.words[0]);
215 rc = OPAL_INTERNAL_ERROR;
216 goto out;
217 }
218
219 param_id = msg->resp->data.words[0];
220 if (param_id != msg->data.words[0]) {
221 prerror("FSP: Request for set sysparam 0x%x got resp. for 0x%x!"
222 "\n", msg->data.words[0], param_id);
223 rc = OPAL_INTERNAL_ERROR;
224 goto out;
225 }
226
227 fstat = (msg->resp->word1 >> 8) & 0xff;
228 switch (fstat) {
229 case 0x00:
230 rc = OPAL_SUCCESS;
231 break;
232 case 0x22:
233 prerror("%s: Response status 0x%x, invalid data\n", __func__,
234 fstat);
235 rc = OPAL_INTERNAL_ERROR;
236 break;
237 case 0x24:
238 prerror("%s: Response status 0x%x, DMA error\n", __func__,
239 fstat);
240 rc = OPAL_INTERNAL_ERROR;
241 break;
242 default:
243 rc = OPAL_INTERNAL_ERROR;
244 break;
245 }
246
247 out:
248 opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL,
249 comp_data->async_token, rc);
250 free(comp_data);
251 fsp_freemsg(msg);
252 }
253
254 /* OPAL interface for PowerNV to read the system parameter from FSP */
fsp_opal_get_param(uint64_t async_token,uint32_t param_id,uint64_t buffer,uint64_t length)255 static int64_t fsp_opal_get_param(uint64_t async_token, uint32_t param_id,
256 uint64_t buffer, uint64_t length)
257 {
258 struct sysparam_comp_data *comp_data;
259 int count, rc, i;
260
261 if (!fsp_present())
262 return OPAL_HARDWARE;
263
264 count = ARRAY_SIZE(sysparam_attrs);
265 for (i = 0; i < count; i++)
266 if (sysparam_attrs[i].id == param_id)
267 break;
268 if (i == count)
269 return OPAL_PARAMETER;
270
271 if (length < sysparam_attrs[i].length)
272 return OPAL_PARAMETER;
273 if (!(sysparam_attrs[i].perm & OPAL_SYSPARAM_READ))
274 return OPAL_PERMISSION;
275
276 comp_data = zalloc(sizeof(struct sysparam_comp_data));
277 if (!comp_data)
278 return OPAL_NO_MEM;
279
280 comp_data->param_len = sysparam_attrs[i].length;
281 comp_data->async_token = async_token;
282 rc = fsp_get_sys_param(param_id, (void *)buffer,
283 sysparam_attrs[i].length, fsp_opal_getparam_complete,
284 comp_data);
285 if (rc) {
286 free(comp_data);
287 prerror("%s: Error %d queuing param request\n", __func__, rc);
288 return OPAL_INTERNAL_ERROR;
289 }
290
291 return OPAL_ASYNC_COMPLETION;
292 }
293
294 /* OPAL interface for PowerNV to update the system parameter to FSP */
fsp_opal_set_param(uint64_t async_token,uint32_t param_id,uint64_t buffer,uint64_t length)295 static int64_t fsp_opal_set_param(uint64_t async_token, uint32_t param_id,
296 uint64_t buffer, uint64_t length)
297 {
298 struct sysparam_comp_data *comp_data;
299 struct fsp_msg *msg;
300 uint64_t tce_token;
301 int count, rc, i;
302
303 if (!fsp_present())
304 return OPAL_HARDWARE;
305
306 count = ARRAY_SIZE(sysparam_attrs);
307 for (i = 0; i < count; i++)
308 if (sysparam_attrs[i].id == param_id)
309 break;
310 if (i == count)
311 return OPAL_PARAMETER;
312
313 if (length < sysparam_attrs[i].length)
314 return OPAL_PARAMETER;
315 if (!(sysparam_attrs[i].perm & OPAL_SYSPARAM_WRITE))
316 return OPAL_PERMISSION;
317
318 fsp_tce_map(PSI_DMA_SET_SYSPARAM, (void *)(buffer & ~0xffful), 0x1000);
319 tce_token = PSI_DMA_SET_SYSPARAM | (buffer & 0xfff);
320
321 msg = fsp_mkmsg(FSP_CMD_SET_SPARM_2, 4, param_id, length,
322 tce_token >> 32, tce_token);
323 if (!msg) {
324 prerror("%s: Failed to allocate the message\n", __func__);
325 return OPAL_INTERNAL_ERROR;
326 }
327
328 comp_data = zalloc(sizeof(struct sysparam_comp_data));
329 if (!comp_data) {
330 fsp_freemsg(msg);
331 return OPAL_NO_MEM;
332 }
333
334 comp_data->param_len = length;
335 comp_data->async_token = async_token;
336 msg->user_data = comp_data;
337
338 rc = fsp_queue_msg(msg, fsp_opal_setparam_complete);
339 if (rc) {
340 free(comp_data);
341 fsp_freemsg(msg);
342 prerror("%s: Failed to queue the message\n", __func__);
343 return OPAL_INTERNAL_ERROR;
344 }
345
346 return OPAL_ASYNC_COMPLETION;
347 }
348
349 struct sysparam_notify_entry {
350 struct list_node link;
351 sysparam_update_notify notify;
352 };
353
354 static LIST_HEAD(sysparam_update_notifiers);
355
356 /* Add client to notifier chain */
sysparam_add_update_notifier(sysparam_update_notify notify)357 void sysparam_add_update_notifier(sysparam_update_notify notify)
358 {
359 struct sysparam_notify_entry *entry;
360
361 entry = zalloc(sizeof(struct sysparam_notify_entry));
362 assert(entry);
363
364 entry->notify = notify;
365 list_add_tail(&sysparam_update_notifiers, &entry->link);
366 }
367
368 /* Remove client from notifier chain */
sysparam_del_update_notifier(sysparam_update_notify notify)369 void sysparam_del_update_notifier(sysparam_update_notify notify)
370 {
371 struct sysparam_notify_entry *entry;
372
373 list_for_each(&sysparam_update_notifiers, entry, link) {
374 if (entry->notify == notify) {
375 list_del(&entry->link);
376 free(entry);
377 return;
378 }
379 }
380 }
381
382 /* Update notification chain */
sysparam_run_update_notifier(struct fsp_msg * msg)383 static void sysparam_run_update_notifier(struct fsp_msg *msg)
384 {
385 bool ret;
386 struct sysparam_notify_entry *entry;
387
388 list_for_each(&sysparam_update_notifiers, entry, link) {
389 ret = entry->notify(msg);
390 if (ret == true)
391 break;
392 }
393 }
394
fsp_sysparam_msg(u32 cmd_sub_mod,struct fsp_msg * msg)395 static bool fsp_sysparam_msg(u32 cmd_sub_mod, struct fsp_msg *msg)
396 {
397 struct fsp_msg *rsp;
398 int rc = -ENOMEM;
399
400 switch(cmd_sub_mod) {
401 case FSP_CMD_SP_SPARM_UPD_0:
402 case FSP_CMD_SP_SPARM_UPD_1:
403 printf("FSP: Got sysparam update, param ID 0x%x\n",
404 msg->data.words[0]);
405
406 sysparam_run_update_notifier(msg);
407
408 rsp = fsp_mkmsg((cmd_sub_mod & 0xffff00) | 0x008000, 0);
409 if (rsp)
410 rc = fsp_queue_msg(rsp, fsp_freemsg);
411 if (rc) {
412 prerror("FSP: Error %d queuing sysparam reply\n", rc);
413 /* What to do here ? R/R ? */
414 fsp_freemsg(rsp);
415 }
416 return true;
417 }
418 return false;
419 }
420
421 static struct fsp_client fsp_sysparam_client = {
422 .message = fsp_sysparam_msg,
423 };
424
add_opal_sysparam_node(void)425 static void add_opal_sysparam_node(void)
426 {
427 struct dt_node *sysparams;
428 char *names, *s;
429 uint32_t *ids, *lens;
430 uint8_t *perms;
431 unsigned int i, count, size = 0;
432
433 if (!fsp_present())
434 return;
435
436 sysparams = dt_new(opal_node, "sysparams");
437 dt_add_property_string(sysparams, "compatible", "ibm,opal-sysparams");
438
439 count = ARRAY_SIZE(sysparam_attrs);
440 for (i = 0; i < count; i++)
441 size = size + strlen(sysparam_attrs[i].name) + 1;
442
443 names = zalloc(size);
444 if (!names) {
445 prerror("%s: Failed to allocate memory for parameter names\n",
446 __func__);
447 return;
448 }
449
450 ids = zalloc(count * sizeof(*ids));
451 if (!ids) {
452 prerror("%s: Failed to allocate memory for parameter ids\n",
453 __func__);
454 goto out_free_name;
455 }
456
457 lens = zalloc(count * sizeof(*lens));
458 if (!lens) {
459 prerror("%s: Failed to allocate memory for parameter length\n",
460 __func__);
461 goto out_free_id;
462 }
463
464 perms = zalloc(count * sizeof(*perms));
465 if (!perms) {
466 prerror("%s: Failed to allocate memory for parameter length\n",
467 __func__);
468 goto out_free_len;
469 }
470
471 s = names;
472 for (i = 0; i < count; i++) {
473 strcpy(s, sysparam_attrs[i].name);
474 s = s + strlen(sysparam_attrs[i].name) + 1;
475
476 ids[i] = sysparam_attrs[i].id;
477 lens[i] = sysparam_attrs[i].length;
478 perms[i] = sysparam_attrs[i].perm;
479 }
480
481 dt_add_property(sysparams, "param-name", names, size);
482 dt_add_property(sysparams, "param-id", ids, count * sizeof(*ids));
483 dt_add_property(sysparams, "param-len", lens, count * sizeof(*lens));
484 dt_add_property(sysparams, "param-perm", perms, count * sizeof(*perms));
485
486 free(perms);
487
488 out_free_len:
489 free(lens);
490 out_free_id:
491 free(ids);
492 out_free_name:
493 free(names);
494 }
495
fsp_sysparam_init(void)496 void fsp_sysparam_init(void)
497 {
498 if (!fsp_present())
499 return;
500
501 /* Register change notifications */
502 fsp_register_client(&fsp_sysparam_client, FSP_MCLASS_SERVICE);
503
504 /* Register OPAL interfaces */
505 opal_register(OPAL_GET_PARAM, fsp_opal_get_param, 4);
506 opal_register(OPAL_SET_PARAM, fsp_opal_set_param, 4);
507
508 /* Add device-tree nodes */
509 add_opal_sysparam_node();
510 }
511