aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-07-12 18:55:55 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-16 07:04:36 -0400
commitb3e13fbeb9ac1eb8e7b0791bf56e1775c692972b (patch)
tree06539dfe2332c98c4d8b83450fe1e6055680ddc0 /arch
parent83292e0a9c3f1c326b28fbf8cb70a8ce81a98163 (diff)
[SPARC64]: Fix setting of variables in LDOM guest.
There is a special domain services capability for setting variables in the OBP options node. Guests don't have permanent store for the OBP variables like a normal system, so they are instead maintained in the LDOM control node or in the SC. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r--arch/sparc64/kernel/ds.c187
-rw-r--r--arch/sparc64/prom/misc.c5
-rw-r--r--arch/sparc64/prom/tree.c13
3 files changed, 190 insertions, 15 deletions
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c
index 9c8839d1cffd..4e20ef232c51 100644
--- a/arch/sparc64/kernel/ds.c
+++ b/arch/sparc64/kernel/ds.c
@@ -11,6 +11,7 @@
11#include <linux/slab.h> 11#include <linux/slab.h>
12#include <linux/sched.h> 12#include <linux/sched.h>
13#include <linux/delay.h> 13#include <linux/delay.h>
14#include <linux/mutex.h>
14 15
15#include <asm/ldc.h> 16#include <asm/ldc.h>
16#include <asm/vio.h> 17#include <asm/vio.h>
@@ -171,7 +172,7 @@ static void md_update_data(struct ldc_channel *lp,
171 172
172 rp = (struct ds_md_update_req *) (dpkt + 1); 173 rp = (struct ds_md_update_req *) (dpkt + 1);
173 174
174 printk(KERN_ERR PFX "Machine description update.\n"); 175 printk(KERN_INFO PFX "Machine description update.\n");
175 176
176 memset(&pkt, 0, sizeof(pkt)); 177 memset(&pkt, 0, sizeof(pkt));
177 pkt.data.tag.type = DS_DATA; 178 pkt.data.tag.type = DS_DATA;
@@ -248,8 +249,8 @@ static void domain_panic_data(struct ldc_channel *lp,
248 249
249 rp = (struct ds_panic_req *) (dpkt + 1); 250 rp = (struct ds_panic_req *) (dpkt + 1);
250 251
251 printk(KERN_ERR PFX "Panic REQ [%lx], len=%d\n", 252 printk(KERN_ALERT PFX "Panic request from "
252 rp->req_num, len); 253 "LDOM manager received.\n");
253 254
254 memset(&pkt, 0, sizeof(pkt)); 255 memset(&pkt, 0, sizeof(pkt));
255 pkt.data.tag.type = DS_DATA; 256 pkt.data.tag.type = DS_DATA;
@@ -313,10 +314,60 @@ static void ds_pri_data(struct ldc_channel *lp,
313 314
314 rp = (struct ds_pri_msg *) (dpkt + 1); 315 rp = (struct ds_pri_msg *) (dpkt + 1);
315 316
316 printk(KERN_ERR PFX "PRI REQ [%lx:%lx], len=%d\n", 317 printk(KERN_INFO PFX "PRI REQ [%lx:%lx], len=%d\n",
317 rp->req_num, rp->type, len); 318 rp->req_num, rp->type, len);
318} 319}
319 320
321struct ds_var_hdr {
322 __u32 type;
323#define DS_VAR_SET_REQ 0x00
324#define DS_VAR_DELETE_REQ 0x01
325#define DS_VAR_SET_RESP 0x02
326#define DS_VAR_DELETE_RESP 0x03
327};
328
329struct ds_var_set_msg {
330 struct ds_var_hdr hdr;
331 char name_and_value[0];
332};
333
334struct ds_var_delete_msg {
335 struct ds_var_hdr hdr;
336 char name[0];
337};
338
339struct ds_var_resp {
340 struct ds_var_hdr hdr;
341 __u32 result;
342#define DS_VAR_SUCCESS 0x00
343#define DS_VAR_NO_SPACE 0x01
344#define DS_VAR_INVALID_VAR 0x02
345#define DS_VAR_INVALID_VAL 0x03
346#define DS_VAR_NOT_PRESENT 0x04
347};
348
349static DEFINE_MUTEX(ds_var_mutex);
350static int ds_var_doorbell;
351static int ds_var_response;
352
353static void ds_var_data(struct ldc_channel *lp,
354 struct ds_cap_state *dp,
355 void *buf, int len)
356{
357 struct ds_data *dpkt = buf;
358 struct ds_var_resp *rp;
359
360 rp = (struct ds_var_resp *) (dpkt + 1);
361
362 if (rp->hdr.type != DS_VAR_SET_RESP &&
363 rp->hdr.type != DS_VAR_DELETE_RESP)
364 return;
365
366 ds_var_response = rp->result;
367 wmb();
368 ds_var_doorbell = 1;
369}
370
320struct ds_cap_state ds_states[] = { 371struct ds_cap_state ds_states[] = {
321 { 372 {
322 .service_id = "md-update", 373 .service_id = "md-update",
@@ -338,17 +389,16 @@ struct ds_cap_state ds_states[] = {
338 .service_id = "pri", 389 .service_id = "pri",
339 .data = ds_pri_data, 390 .data = ds_pri_data,
340 }, 391 },
392 {
393 .service_id = "var-config",
394 .data = ds_var_data,
395 },
396 {
397 .service_id = "var-config-backup",
398 .data = ds_var_data,
399 },
341}; 400};
342 401
343static struct ds_cap_state *find_cap(u64 handle)
344{
345 unsigned int index = handle >> 32;
346
347 if (index >= ARRAY_SIZE(ds_states))
348 return NULL;
349 return &ds_states[index];
350}
351
352static DEFINE_SPINLOCK(ds_lock); 402static DEFINE_SPINLOCK(ds_lock);
353 403
354struct ds_info { 404struct ds_info {
@@ -361,6 +411,115 @@ struct ds_info {
361 int rcv_buf_len; 411 int rcv_buf_len;
362}; 412};
363 413
414static struct ds_info *ds_info;
415
416static struct ds_cap_state *find_cap(u64 handle)
417{
418 unsigned int index = handle >> 32;
419
420 if (index >= ARRAY_SIZE(ds_states))
421 return NULL;
422 return &ds_states[index];
423}
424
425static struct ds_cap_state *find_cap_by_string(const char *name)
426{
427 int i;
428
429 for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
430 if (strcmp(ds_states[i].service_id, name))
431 continue;
432
433 return &ds_states[i];
434 }
435 return NULL;
436}
437
438void ldom_set_var(const char *var, const char *value)
439{
440 struct ds_info *dp = ds_info;
441 struct ds_cap_state *cp;
442
443 cp = find_cap_by_string("var-config");
444 if (cp->state != CAP_STATE_REGISTERED)
445 cp = find_cap_by_string("var-config-backup");
446
447 if (cp->state == CAP_STATE_REGISTERED) {
448 union {
449 struct {
450 struct ds_data data;
451 struct ds_var_set_msg msg;
452 } header;
453 char all[512];
454 } pkt;
455 unsigned long flags;
456 char *base, *p;
457 int msg_len, loops;
458
459 memset(&pkt, 0, sizeof(pkt));
460 pkt.header.data.tag.type = DS_DATA;
461 pkt.header.data.handle = cp->handle;
462 pkt.header.msg.hdr.type = DS_VAR_SET_REQ;
463 base = p = &pkt.header.msg.name_and_value[0];
464 strcpy(p, var);
465 p += strlen(var) + 1;
466 strcpy(p, value);
467 p += strlen(value) + 1;
468
469 msg_len = (sizeof(struct ds_data) +
470 sizeof(struct ds_var_set_msg) +
471 (p - base));
472 msg_len = (msg_len + 3) & ~3;
473 pkt.header.data.tag.len = msg_len - sizeof(struct ds_msg_tag);
474
475 mutex_lock(&ds_var_mutex);
476
477 spin_lock_irqsave(&ds_lock, flags);
478 ds_var_doorbell = 0;
479 ds_var_response = -1;
480
481 ds_send(dp->lp, &pkt, msg_len);
482 spin_unlock_irqrestore(&ds_lock, flags);
483
484 loops = 1000;
485 while (ds_var_doorbell == 0) {
486 if (loops-- < 0)
487 break;
488 barrier();
489 udelay(100);
490 }
491
492 mutex_unlock(&ds_var_mutex);
493
494 if (ds_var_doorbell == 0 ||
495 ds_var_response != DS_VAR_SUCCESS)
496 printk(KERN_ERR PFX "var-config [%s:%s] "
497 "failed, response(%d).\n",
498 var, value,
499 ds_var_response);
500 } else {
501 printk(KERN_ERR PFX "var-config not registered so "
502 "could not set (%s) variable to (%s).\n",
503 var, value);
504 }
505}
506
507void ldom_reboot(const char *boot_command)
508{
509 /* Don't bother with any of this if the boot_command
510 * is empty.
511 */
512 if (boot_command && strlen(boot_command)) {
513 char full_boot_str[256];
514
515 strcpy(full_boot_str, "boot ");
516 strcpy(full_boot_str + strlen("boot "), boot_command);
517
518 ldom_set_var("reboot-command", full_boot_str);
519 }
520 sun4v_mach_sir();
521}
522
364static void ds_conn_reset(struct ds_info *dp) 523static void ds_conn_reset(struct ds_info *dp)
365{ 524{
366 printk(KERN_ERR PFX "ds_conn_reset() from %p\n", 525 printk(KERN_ERR PFX "ds_conn_reset() from %p\n",
@@ -594,6 +753,8 @@ static int __devinit ds_probe(struct vio_dev *vdev,
594 if (err) 753 if (err)
595 goto out_free_ldc; 754 goto out_free_ldc;
596 755
756 ds_info = dp;
757
597 start_powerd(); 758 start_powerd();
598 759
599 return err; 760 return err;
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index f3e0c14e9eef..72d272c9de6b 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -14,6 +14,7 @@
14#include <asm/openprom.h> 14#include <asm/openprom.h>
15#include <asm/oplib.h> 15#include <asm/oplib.h>
16#include <asm/system.h> 16#include <asm/system.h>
17#include <asm/ldc.h>
17 18
18int prom_service_exists(const char *service_name) 19int prom_service_exists(const char *service_name)
19{ 20{
@@ -37,6 +38,10 @@ void prom_sun4v_guest_soft_state(void)
37/* Reset and reboot the machine with the command 'bcommand'. */ 38/* Reset and reboot the machine with the command 'bcommand'. */
38void prom_reboot(const char *bcommand) 39void prom_reboot(const char *bcommand)
39{ 40{
41#ifdef CONFIG_SUN_LDOMS
42 if (ldom_domaining_enabled)
43 ldom_reboot(bcommand);
44#endif
40 p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) | 45 p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) |
41 P1275_INOUT(1, 0), bcommand); 46 P1275_INOUT(1, 0), bcommand);
42} 47}
diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c
index 500f05e2cfcb..17b7ecfe7ca9 100644
--- a/arch/sparc64/prom/tree.c
+++ b/arch/sparc64/prom/tree.c
@@ -13,6 +13,7 @@
13 13
14#include <asm/openprom.h> 14#include <asm/openprom.h>
15#include <asm/oplib.h> 15#include <asm/oplib.h>
16#include <asm/ldc.h>
16 17
17/* Return the child of node 'node' or zero if no this node has no 18/* Return the child of node 'node' or zero if no this node has no
18 * direct descendent. 19 * direct descendent.
@@ -261,9 +262,17 @@ int prom_node_has_property(int node, const char *prop)
261int 262int
262prom_setprop(int node, const char *pname, char *value, int size) 263prom_setprop(int node, const char *pname, char *value, int size)
263{ 264{
264 if(size == 0) return 0; 265 if (size == 0)
265 if((pname == 0) || (value == 0)) return 0; 266 return 0;
267 if ((pname == 0) || (value == 0))
268 return 0;
266 269
270#ifdef CONFIG_SUN_LDOMS
271 if (ldom_domaining_enabled) {
272 ldom_set_var(pname, value);
273 return 0;
274 }
275#endif
267 return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)| 276 return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
268 P1275_ARG(2,P1275_ARG_IN_BUF)| 277 P1275_ARG(2,P1275_ARG_IN_BUF)|
269 P1275_INOUT(4, 1), 278 P1275_INOUT(4, 1),