aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/ds.c
diff options
context:
space:
mode:
authorSam Ravnborg <sam@ravnborg.org>2008-12-03 06:11:52 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-04 12:17:21 -0500
commita88b5ba8bd8ac18aad65ee6c6a254e2e74876db3 (patch)
treeeb3d0ffaf53c3f7ec6083752c2097cecd1cb892a /arch/sparc/kernel/ds.c
parentd670bd4f803c8b646acd20f3ba21e65458293faf (diff)
sparc,sparc64: unify kernel/
o Move all files from sparc64/kernel/ to sparc/kernel - rename as appropriate o Update sparc/Makefile to the changes o Update sparc/kernel/Makefile to include the sparc64 files NOTE: This commit changes link order on sparc64! Link order had to change for either of sparc32 and sparc64. And assuming sparc64 see more testing than sparc32 change link order on sparc64 where issues will be caught faster. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/ds.c')
-rw-r--r--arch/sparc/kernel/ds.c1244
1 files changed, 1244 insertions, 0 deletions
diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c
new file mode 100644
index 00000000000..f52e0534d91
--- /dev/null
+++ b/arch/sparc/kernel/ds.c
@@ -0,0 +1,1244 @@
1/* ds.c: Domain Services driver for Logical Domains
2 *
3 * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
4 */
5
6#include <linux/kernel.h>
7#include <linux/module.h>
8#include <linux/types.h>
9#include <linux/string.h>
10#include <linux/slab.h>
11#include <linux/sched.h>
12#include <linux/delay.h>
13#include <linux/mutex.h>
14#include <linux/kthread.h>
15#include <linux/reboot.h>
16#include <linux/cpu.h>
17
18#include <asm/ldc.h>
19#include <asm/vio.h>
20#include <asm/mdesc.h>
21#include <asm/head.h>
22#include <asm/irq.h>
23
24#define DRV_MODULE_NAME "ds"
25#define PFX DRV_MODULE_NAME ": "
26#define DRV_MODULE_VERSION "1.0"
27#define DRV_MODULE_RELDATE "Jul 11, 2007"
28
29static char version[] __devinitdata =
30 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
31MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
32MODULE_DESCRIPTION("Sun LDOM domain services driver");
33MODULE_LICENSE("GPL");
34MODULE_VERSION(DRV_MODULE_VERSION);
35
36struct ds_msg_tag {
37 __u32 type;
38#define DS_INIT_REQ 0x00
39#define DS_INIT_ACK 0x01
40#define DS_INIT_NACK 0x02
41#define DS_REG_REQ 0x03
42#define DS_REG_ACK 0x04
43#define DS_REG_NACK 0x05
44#define DS_UNREG_REQ 0x06
45#define DS_UNREG_ACK 0x07
46#define DS_UNREG_NACK 0x08
47#define DS_DATA 0x09
48#define DS_NACK 0x0a
49
50 __u32 len;
51};
52
53/* Result codes */
54#define DS_OK 0x00
55#define DS_REG_VER_NACK 0x01
56#define DS_REG_DUP 0x02
57#define DS_INV_HDL 0x03
58#define DS_TYPE_UNKNOWN 0x04
59
60struct ds_version {
61 __u16 major;
62 __u16 minor;
63};
64
65struct ds_ver_req {
66 struct ds_msg_tag tag;
67 struct ds_version ver;
68};
69
70struct ds_ver_ack {
71 struct ds_msg_tag tag;
72 __u16 minor;
73};
74
75struct ds_ver_nack {
76 struct ds_msg_tag tag;
77 __u16 major;
78};
79
80struct ds_reg_req {
81 struct ds_msg_tag tag;
82 __u64 handle;
83 __u16 major;
84 __u16 minor;
85 char svc_id[0];
86};
87
88struct ds_reg_ack {
89 struct ds_msg_tag tag;
90 __u64 handle;
91 __u16 minor;
92};
93
94struct ds_reg_nack {
95 struct ds_msg_tag tag;
96 __u64 handle;
97 __u16 major;
98};
99
100struct ds_unreg_req {
101 struct ds_msg_tag tag;
102 __u64 handle;
103};
104
105struct ds_unreg_ack {
106 struct ds_msg_tag tag;
107 __u64 handle;
108};
109
110struct ds_unreg_nack {
111 struct ds_msg_tag tag;
112 __u64 handle;
113};
114
115struct ds_data {
116 struct ds_msg_tag tag;
117 __u64 handle;
118};
119
120struct ds_data_nack {
121 struct ds_msg_tag tag;
122 __u64 handle;
123 __u64 result;
124};
125
126struct ds_info;
127struct ds_cap_state {
128 __u64 handle;
129
130 void (*data)(struct ds_info *dp,
131 struct ds_cap_state *cp,
132 void *buf, int len);
133
134 const char *service_id;
135
136 u8 state;
137#define CAP_STATE_UNKNOWN 0x00
138#define CAP_STATE_REG_SENT 0x01
139#define CAP_STATE_REGISTERED 0x02
140};
141
142static void md_update_data(struct ds_info *dp, struct ds_cap_state *cp,
143 void *buf, int len);
144static void domain_shutdown_data(struct ds_info *dp,
145 struct ds_cap_state *cp,
146 void *buf, int len);
147static void domain_panic_data(struct ds_info *dp,
148 struct ds_cap_state *cp,
149 void *buf, int len);
150#ifdef CONFIG_HOTPLUG_CPU
151static void dr_cpu_data(struct ds_info *dp,
152 struct ds_cap_state *cp,
153 void *buf, int len);
154#endif
155static void ds_pri_data(struct ds_info *dp,
156 struct ds_cap_state *cp,
157 void *buf, int len);
158static void ds_var_data(struct ds_info *dp,
159 struct ds_cap_state *cp,
160 void *buf, int len);
161
162static struct ds_cap_state ds_states_template[] = {
163 {
164 .service_id = "md-update",
165 .data = md_update_data,
166 },
167 {
168 .service_id = "domain-shutdown",
169 .data = domain_shutdown_data,
170 },
171 {
172 .service_id = "domain-panic",
173 .data = domain_panic_data,
174 },
175#ifdef CONFIG_HOTPLUG_CPU
176 {
177 .service_id = "dr-cpu",
178 .data = dr_cpu_data,
179 },
180#endif
181 {
182 .service_id = "pri",
183 .data = ds_pri_data,
184 },
185 {
186 .service_id = "var-config",
187 .data = ds_var_data,
188 },
189 {
190 .service_id = "var-config-backup",
191 .data = ds_var_data,
192 },
193};
194
195static DEFINE_SPINLOCK(ds_lock);
196
197struct ds_info {
198 struct ldc_channel *lp;
199 u8 hs_state;
200#define DS_HS_START 0x01
201#define DS_HS_DONE 0x02
202
203 u64 id;
204
205 void *rcv_buf;
206 int rcv_buf_len;
207
208 struct ds_cap_state *ds_states;
209 int num_ds_states;
210
211 struct ds_info *next;
212};
213
214static struct ds_info *ds_info_list;
215
216static struct ds_cap_state *find_cap(struct ds_info *dp, u64 handle)
217{
218 unsigned int index = handle >> 32;
219
220 if (index >= dp->num_ds_states)
221 return NULL;
222 return &dp->ds_states[index];
223}
224
225static struct ds_cap_state *find_cap_by_string(struct ds_info *dp,
226 const char *name)
227{
228 int i;
229
230 for (i = 0; i < dp->num_ds_states; i++) {
231 if (strcmp(dp->ds_states[i].service_id, name))
232 continue;
233
234 return &dp->ds_states[i];
235 }
236 return NULL;
237}
238
239static int __ds_send(struct ldc_channel *lp, void *data, int len)
240{
241 int err, limit = 1000;
242
243 err = -EINVAL;
244 while (limit-- > 0) {
245 err = ldc_write(lp, data, len);
246 if (!err || (err != -EAGAIN))
247 break;
248 udelay(1);
249 }
250
251 return err;
252}
253
254static int ds_send(struct ldc_channel *lp, void *data, int len)
255{
256 unsigned long flags;
257 int err;
258
259 spin_lock_irqsave(&ds_lock, flags);
260 err = __ds_send(lp, data, len);
261 spin_unlock_irqrestore(&ds_lock, flags);
262
263 return err;
264}
265
266struct ds_md_update_req {
267 __u64 req_num;
268};
269
270struct ds_md_update_res {
271 __u64 req_num;
272 __u32 result;
273};
274
275static void md_update_data(struct ds_info *dp,
276 struct ds_cap_state *cp,
277 void *buf, int len)
278{
279 struct ldc_channel *lp = dp->lp;
280 struct ds_data *dpkt = buf;
281 struct ds_md_update_req *rp;
282 struct {
283 struct ds_data data;
284 struct ds_md_update_res res;
285 } pkt;
286
287 rp = (struct ds_md_update_req *) (dpkt + 1);
288
289 printk(KERN_INFO "ds-%lu: Machine description update.\n", dp->id);
290
291 mdesc_update();
292
293 memset(&pkt, 0, sizeof(pkt));
294 pkt.data.tag.type = DS_DATA;
295 pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
296 pkt.data.handle = cp->handle;
297 pkt.res.req_num = rp->req_num;
298 pkt.res.result = DS_OK;
299
300 ds_send(lp, &pkt, sizeof(pkt));
301}
302
303struct ds_shutdown_req {
304 __u64 req_num;
305 __u32 ms_delay;
306};
307
308struct ds_shutdown_res {
309 __u64 req_num;
310 __u32 result;
311 char reason[1];
312};
313
314static void domain_shutdown_data(struct ds_info *dp,
315 struct ds_cap_state *cp,
316 void *buf, int len)
317{
318 struct ldc_channel *lp = dp->lp;
319 struct ds_data *dpkt = buf;
320 struct ds_shutdown_req *rp;
321 struct {
322 struct ds_data data;
323 struct ds_shutdown_res res;
324 } pkt;
325
326 rp = (struct ds_shutdown_req *) (dpkt + 1);
327
328 printk(KERN_ALERT "ds-%lu: Shutdown request from "
329 "LDOM manager received.\n", dp->id);
330
331 memset(&pkt, 0, sizeof(pkt));
332 pkt.data.tag.type = DS_DATA;
333 pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
334 pkt.data.handle = cp->handle;
335 pkt.res.req_num = rp->req_num;
336 pkt.res.result = DS_OK;
337 pkt.res.reason[0] = 0;
338
339 ds_send(lp, &pkt, sizeof(pkt));
340
341 orderly_poweroff(true);
342}
343
344struct ds_panic_req {
345 __u64 req_num;
346};
347
348struct ds_panic_res {
349 __u64 req_num;
350 __u32 result;
351 char reason[1];
352};
353
354static void domain_panic_data(struct ds_info *dp,
355 struct ds_cap_state *cp,
356 void *buf, int len)
357{
358 struct ldc_channel *lp = dp->lp;
359 struct ds_data *dpkt = buf;
360 struct ds_panic_req *rp;
361 struct {
362 struct ds_data data;
363 struct ds_panic_res res;
364 } pkt;
365
366 rp = (struct ds_panic_req *) (dpkt + 1);
367
368 printk(KERN_ALERT "ds-%lu: Panic request from "
369 "LDOM manager received.\n", dp->id);
370
371 memset(&pkt, 0, sizeof(pkt));
372 pkt.data.tag.type = DS_DATA;
373 pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
374 pkt.data.handle = cp->handle;
375 pkt.res.req_num = rp->req_num;
376 pkt.res.result = DS_OK;
377 pkt.res.reason[0] = 0;
378
379 ds_send(lp, &pkt, sizeof(pkt));
380
381 panic("PANIC requested by LDOM manager.");
382}
383
384#ifdef CONFIG_HOTPLUG_CPU
385struct dr_cpu_tag {
386 __u64 req_num;
387 __u32 type;
388#define DR_CPU_CONFIGURE 0x43
389#define DR_CPU_UNCONFIGURE 0x55
390#define DR_CPU_FORCE_UNCONFIGURE 0x46
391#define DR_CPU_STATUS 0x53
392
393/* Responses */
394#define DR_CPU_OK 0x6f
395#define DR_CPU_ERROR 0x65
396
397 __u32 num_records;
398};
399
400struct dr_cpu_resp_entry {
401 __u32 cpu;
402 __u32 result;
403#define DR_CPU_RES_OK 0x00
404#define DR_CPU_RES_FAILURE 0x01
405#define DR_CPU_RES_BLOCKED 0x02
406#define DR_CPU_RES_CPU_NOT_RESPONDING 0x03
407#define DR_CPU_RES_NOT_IN_MD 0x04
408
409 __u32 stat;
410#define DR_CPU_STAT_NOT_PRESENT 0x00
411#define DR_CPU_STAT_UNCONFIGURED 0x01
412#define DR_CPU_STAT_CONFIGURED 0x02
413
414 __u32 str_off;
415};
416
417static void __dr_cpu_send_error(struct ds_info *dp,
418 struct ds_cap_state *cp,
419 struct ds_data *data)
420{
421 struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
422 struct {
423 struct ds_data data;
424 struct dr_cpu_tag tag;
425 } pkt;
426 int msg_len;
427
428 memset(&pkt, 0, sizeof(pkt));
429 pkt.data.tag.type = DS_DATA;
430 pkt.data.handle = cp->handle;
431 pkt.tag.req_num = tag->req_num;
432 pkt.tag.type = DR_CPU_ERROR;
433 pkt.tag.num_records = 0;
434
435 msg_len = (sizeof(struct ds_data) +
436 sizeof(struct dr_cpu_tag));
437
438 pkt.data.tag.len = msg_len - sizeof(struct ds_msg_tag);
439
440 __ds_send(dp->lp, &pkt, msg_len);
441}
442
443static void dr_cpu_send_error(struct ds_info *dp,
444 struct ds_cap_state *cp,
445 struct ds_data *data)
446{
447 unsigned long flags;
448
449 spin_lock_irqsave(&ds_lock, flags);
450 __dr_cpu_send_error(dp, cp, data);
451 spin_unlock_irqrestore(&ds_lock, flags);
452}
453
454#define CPU_SENTINEL 0xffffffff
455
456static void purge_dups(u32 *list, u32 num_ents)
457{
458 unsigned int i;
459
460 for (i = 0; i < num_ents; i++) {
461 u32 cpu = list[i];
462 unsigned int j;
463
464 if (cpu == CPU_SENTINEL)
465 continue;
466
467 for (j = i + 1; j < num_ents; j++) {
468 if (list[j] == cpu)
469 list[j] = CPU_SENTINEL;
470 }
471 }
472}
473
474static int dr_cpu_size_response(int ncpus)
475{
476 return (sizeof(struct ds_data) +
477 sizeof(struct dr_cpu_tag) +
478 (sizeof(struct dr_cpu_resp_entry) * ncpus));
479}
480
481static void dr_cpu_init_response(struct ds_data *resp, u64 req_num,
482 u64 handle, int resp_len, int ncpus,
483 cpumask_t *mask, u32 default_stat)
484{
485 struct dr_cpu_resp_entry *ent;
486 struct dr_cpu_tag *tag;
487 int i, cpu;
488
489 tag = (struct dr_cpu_tag *) (resp + 1);
490 ent = (struct dr_cpu_resp_entry *) (tag + 1);
491
492 resp->tag.type = DS_DATA;
493 resp->tag.len = resp_len - sizeof(struct ds_msg_tag);
494 resp->handle = handle;
495 tag->req_num = req_num;
496 tag->type = DR_CPU_OK;
497 tag->num_records = ncpus;
498
499 i = 0;
500 for_each_cpu_mask(cpu, *mask) {
501 ent[i].cpu = cpu;
502 ent[i].result = DR_CPU_RES_OK;
503 ent[i].stat = default_stat;
504 i++;
505 }
506 BUG_ON(i != ncpus);
507}
508
509static void dr_cpu_mark(struct ds_data *resp, int cpu, int ncpus,
510 u32 res, u32 stat)
511{
512 struct dr_cpu_resp_entry *ent;
513 struct dr_cpu_tag *tag;
514 int i;
515
516 tag = (struct dr_cpu_tag *) (resp + 1);
517 ent = (struct dr_cpu_resp_entry *) (tag + 1);
518
519 for (i = 0; i < ncpus; i++) {
520 if (ent[i].cpu != cpu)
521 continue;
522 ent[i].result = res;
523 ent[i].stat = stat;
524 break;
525 }
526}
527
528static int __cpuinit dr_cpu_configure(struct ds_info *dp,
529 struct ds_cap_state *cp,
530 u64 req_num,
531 cpumask_t *mask)
532{
533 struct ds_data *resp;
534 int resp_len, ncpus, cpu;
535 unsigned long flags;
536
537 ncpus = cpus_weight(*mask);
538 resp_len = dr_cpu_size_response(ncpus);
539 resp = kzalloc(resp_len, GFP_KERNEL);
540 if (!resp)
541 return -ENOMEM;
542
543 dr_cpu_init_response(resp, req_num, cp->handle,
544 resp_len, ncpus, mask,
545 DR_CPU_STAT_CONFIGURED);
546
547 mdesc_fill_in_cpu_data(*mask);
548
549 for_each_cpu_mask(cpu, *mask) {
550 int err;
551
552 printk(KERN_INFO "ds-%lu: Starting cpu %d...\n",
553 dp->id, cpu);
554 err = cpu_up(cpu);
555 if (err) {
556 __u32 res = DR_CPU_RES_FAILURE;
557 __u32 stat = DR_CPU_STAT_UNCONFIGURED;
558
559 if (!cpu_present(cpu)) {
560 /* CPU not present in MD */
561 res = DR_CPU_RES_NOT_IN_MD;
562 stat = DR_CPU_STAT_NOT_PRESENT;
563 } else if (err == -ENODEV) {
564 /* CPU did not call in successfully */
565 res = DR_CPU_RES_CPU_NOT_RESPONDING;
566 }
567
568 printk(KERN_INFO "ds-%lu: CPU startup failed err=%d\n",
569 dp->id, err);
570 dr_cpu_mark(resp, cpu, ncpus, res, stat);
571 }
572 }
573
574 spin_lock_irqsave(&ds_lock, flags);
575 __ds_send(dp->lp, resp, resp_len);
576 spin_unlock_irqrestore(&ds_lock, flags);
577
578 kfree(resp);
579
580 /* Redistribute IRQs, taking into account the new cpus. */
581 fixup_irqs();
582
583 return 0;
584}
585
586static int dr_cpu_unconfigure(struct ds_info *dp,
587 struct ds_cap_state *cp,
588 u64 req_num,
589 cpumask_t *mask)
590{
591 struct ds_data *resp;
592 int resp_len, ncpus, cpu;
593 unsigned long flags;
594
595 ncpus = cpus_weight(*mask);
596 resp_len = dr_cpu_size_response(ncpus);
597 resp = kzalloc(resp_len, GFP_KERNEL);
598 if (!resp)
599 return -ENOMEM;
600
601 dr_cpu_init_response(resp, req_num, cp->handle,
602 resp_len, ncpus, mask,
603 DR_CPU_STAT_UNCONFIGURED);
604
605 for_each_cpu_mask(cpu, *mask) {
606 int err;
607
608 printk(KERN_INFO "ds-%lu: Shutting down cpu %d...\n",
609 dp->id, cpu);
610 err = cpu_down(cpu);
611 if (err)
612 dr_cpu_mark(resp, cpu, ncpus,
613 DR_CPU_RES_FAILURE,
614 DR_CPU_STAT_CONFIGURED);
615 }
616
617 spin_lock_irqsave(&ds_lock, flags);
618 __ds_send(dp->lp, resp, resp_len);
619 spin_unlock_irqrestore(&ds_lock, flags);
620
621 kfree(resp);
622
623 return 0;
624}
625
626static void __cpuinit dr_cpu_data(struct ds_info *dp,
627 struct ds_cap_state *cp,
628 void *buf, int len)
629{
630 struct ds_data *data = buf;
631 struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
632 u32 *cpu_list = (u32 *) (tag + 1);
633 u64 req_num = tag->req_num;
634 cpumask_t mask;
635 unsigned int i;
636 int err;
637
638 switch (tag->type) {
639 case DR_CPU_CONFIGURE:
640 case DR_CPU_UNCONFIGURE:
641 case DR_CPU_FORCE_UNCONFIGURE:
642 break;
643
644 default:
645 dr_cpu_send_error(dp, cp, data);
646 return;
647 }
648
649 purge_dups(cpu_list, tag->num_records);
650
651 cpus_clear(mask);
652 for (i = 0; i < tag->num_records; i++) {
653 if (cpu_list[i] == CPU_SENTINEL)
654 continue;
655
656 if (cpu_list[i] < NR_CPUS)
657 cpu_set(cpu_list[i], mask);
658 }
659
660 if (tag->type == DR_CPU_CONFIGURE)
661 err = dr_cpu_configure(dp, cp, req_num, &mask);
662 else
663 err = dr_cpu_unconfigure(dp, cp, req_num, &mask);
664
665 if (err)
666 dr_cpu_send_error(dp, cp, data);
667}
668#endif /* CONFIG_HOTPLUG_CPU */
669
670struct ds_pri_msg {
671 __u64 req_num;
672 __u64 type;
673#define DS_PRI_REQUEST 0x00
674#define DS_PRI_DATA 0x01
675#define DS_PRI_UPDATE 0x02
676};
677
678static void ds_pri_data(struct ds_info *dp,
679 struct ds_cap_state *cp,
680 void *buf, int len)
681{
682 struct ds_data *dpkt = buf;
683 struct ds_pri_msg *rp;
684
685 rp = (struct ds_pri_msg *) (dpkt + 1);
686
687 printk(KERN_INFO "ds-%lu: PRI REQ [%lx:%lx], len=%d\n",
688 dp->id, rp->req_num, rp->type, len);
689}
690
691struct ds_var_hdr {
692 __u32 type;
693#define DS_VAR_SET_REQ 0x00
694#define DS_VAR_DELETE_REQ 0x01
695#define DS_VAR_SET_RESP 0x02
696#define DS_VAR_DELETE_RESP 0x03
697};
698
699struct ds_var_set_msg {
700 struct ds_var_hdr hdr;
701 char name_and_value[0];
702};
703
704struct ds_var_delete_msg {
705 struct ds_var_hdr hdr;
706 char name[0];
707};
708
709struct ds_var_resp {
710 struct ds_var_hdr hdr;
711 __u32 result;
712#define DS_VAR_SUCCESS 0x00
713#define DS_VAR_NO_SPACE 0x01
714#define DS_VAR_INVALID_VAR 0x02
715#define DS_VAR_INVALID_VAL 0x03
716#define DS_VAR_NOT_PRESENT 0x04
717};
718
719static DEFINE_MUTEX(ds_var_mutex);
720static int ds_var_doorbell;
721static int ds_var_response;
722
723static void ds_var_data(struct ds_info *dp,
724 struct ds_cap_state *cp,
725 void *buf, int len)
726{
727 struct ds_data *dpkt = buf;
728 struct ds_var_resp *rp;
729
730 rp = (struct ds_var_resp *) (dpkt + 1);
731
732 if (rp->hdr.type != DS_VAR_SET_RESP &&
733 rp->hdr.type != DS_VAR_DELETE_RESP)
734 return;
735
736 ds_var_response = rp->result;
737 wmb();
738 ds_var_doorbell = 1;
739}
740
741void ldom_set_var(const char *var, const char *value)
742{
743 struct ds_cap_state *cp;
744 struct ds_info *dp;
745 unsigned long flags;
746
747 spin_lock_irqsave(&ds_lock, flags);
748 cp = NULL;
749 for (dp = ds_info_list; dp; dp = dp->next) {
750 struct ds_cap_state *tmp;
751
752 tmp = find_cap_by_string(dp, "var-config");
753 if (tmp && tmp->state == CAP_STATE_REGISTERED) {
754 cp = tmp;
755 break;
756 }
757 }
758 if (!cp) {
759 for (dp = ds_info_list; dp; dp = dp->next) {
760 struct ds_cap_state *tmp;
761
762 tmp = find_cap_by_string(dp, "var-config-backup");
763 if (tmp && tmp->state == CAP_STATE_REGISTERED) {
764 cp = tmp;
765 break;
766 }
767 }
768 }
769 spin_unlock_irqrestore(&ds_lock, flags);
770
771 if (cp) {
772 union {
773 struct {
774 struct ds_data data;
775 struct ds_var_set_msg msg;
776 } header;
777 char all[512];
778 } pkt;
779 char *base, *p;
780 int msg_len, loops;
781
782 memset(&pkt, 0, sizeof(pkt));
783 pkt.header.data.tag.type = DS_DATA;
784 pkt.header.data.handle = cp->handle;
785 pkt.header.msg.hdr.type = DS_VAR_SET_REQ;
786 base = p = &pkt.header.msg.name_and_value[0];
787 strcpy(p, var);
788 p += strlen(var) + 1;
789 strcpy(p, value);
790 p += strlen(value) + 1;
791
792 msg_len = (sizeof(struct ds_data) +
793 sizeof(struct ds_var_set_msg) +
794 (p - base));
795 msg_len = (msg_len + 3) & ~3;
796 pkt.header.data.tag.len = msg_len - sizeof(struct ds_msg_tag);
797
798 mutex_lock(&ds_var_mutex);
799
800 spin_lock_irqsave(&ds_lock, flags);
801 ds_var_doorbell = 0;
802 ds_var_response = -1;
803
804 __ds_send(dp->lp, &pkt, msg_len);
805 spin_unlock_irqrestore(&ds_lock, flags);
806
807 loops = 1000;
808 while (ds_var_doorbell == 0) {
809 if (loops-- < 0)
810 break;
811 barrier();
812 udelay(100);
813 }
814
815 mutex_unlock(&ds_var_mutex);
816
817 if (ds_var_doorbell == 0 ||
818 ds_var_response != DS_VAR_SUCCESS)
819 printk(KERN_ERR "ds-%lu: var-config [%s:%s] "
820 "failed, response(%d).\n",
821 dp->id, var, value,
822 ds_var_response);
823 } else {
824 printk(KERN_ERR PFX "var-config not registered so "
825 "could not set (%s) variable to (%s).\n",
826 var, value);
827 }
828}
829
830void ldom_reboot(const char *boot_command)
831{
832 /* Don't bother with any of this if the boot_command
833 * is empty.
834 */
835 if (boot_command && strlen(boot_command)) {
836 char full_boot_str[256];
837
838 strcpy(full_boot_str, "boot ");
839 strcpy(full_boot_str + strlen("boot "), boot_command);
840
841 ldom_set_var("reboot-command", full_boot_str);
842 }
843 sun4v_mach_sir();
844}
845
846void ldom_power_off(void)
847{
848 sun4v_mach_exit(0);
849}
850
851static void ds_conn_reset(struct ds_info *dp)
852{
853 printk(KERN_ERR "ds-%lu: ds_conn_reset() from %p\n",
854 dp->id, __builtin_return_address(0));
855}
856
857static int register_services(struct ds_info *dp)
858{
859 struct ldc_channel *lp = dp->lp;
860 int i;
861
862 for (i = 0; i < dp->num_ds_states; i++) {
863 struct {
864 struct ds_reg_req req;
865 u8 id_buf[256];
866 } pbuf;
867 struct ds_cap_state *cp = &dp->ds_states[i];
868 int err, msg_len;
869 u64 new_count;
870
871 if (cp->state == CAP_STATE_REGISTERED)
872 continue;
873
874 new_count = sched_clock() & 0xffffffff;
875 cp->handle = ((u64) i << 32) | new_count;
876
877 msg_len = (sizeof(struct ds_reg_req) +
878 strlen(cp->service_id));
879
880 memset(&pbuf, 0, sizeof(pbuf));
881 pbuf.req.tag.type = DS_REG_REQ;
882 pbuf.req.tag.len = (msg_len - sizeof(struct ds_msg_tag));
883 pbuf.req.handle = cp->handle;
884 pbuf.req.major = 1;
885 pbuf.req.minor = 0;
886 strcpy(pbuf.req.svc_id, cp->service_id);
887
888 err = __ds_send(lp, &pbuf, msg_len);
889 if (err > 0)
890 cp->state = CAP_STATE_REG_SENT;
891 }
892 return 0;
893}
894
895static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt)
896{
897
898 if (dp->hs_state == DS_HS_START) {
899 if (pkt->type != DS_INIT_ACK)
900 goto conn_reset;
901
902 dp->hs_state = DS_HS_DONE;
903
904 return register_services(dp);
905 }
906
907 if (dp->hs_state != DS_HS_DONE)
908 goto conn_reset;
909
910 if (pkt->type == DS_REG_ACK) {
911 struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;
912 struct ds_cap_state *cp = find_cap(dp, ap->handle);
913
914 if (!cp) {
915 printk(KERN_ERR "ds-%lu: REG ACK for unknown "
916 "handle %lx\n", dp->id, ap->handle);
917 return 0;
918 }
919 printk(KERN_INFO "ds-%lu: Registered %s service.\n",
920 dp->id, cp->service_id);
921 cp->state = CAP_STATE_REGISTERED;
922 } else if (pkt->type == DS_REG_NACK) {
923 struct ds_reg_nack *np = (struct ds_reg_nack *) pkt;
924 struct ds_cap_state *cp = find_cap(dp, np->handle);
925
926 if (!cp) {
927 printk(KERN_ERR "ds-%lu: REG NACK for "
928 "unknown handle %lx\n",
929 dp->id, np->handle);
930 return 0;
931 }
932 cp->state = CAP_STATE_UNKNOWN;
933 }
934
935 return 0;
936
937conn_reset:
938 ds_conn_reset(dp);
939 return -ECONNRESET;
940}
941
942static void __send_ds_nack(struct ds_info *dp, u64 handle)
943{
944 struct ds_data_nack nack = {
945 .tag = {
946 .type = DS_NACK,
947 .len = (sizeof(struct ds_data_nack) -
948 sizeof(struct ds_msg_tag)),
949 },
950 .handle = handle,
951 .result = DS_INV_HDL,
952 };
953
954 __ds_send(dp->lp, &nack, sizeof(nack));
955}
956
957static LIST_HEAD(ds_work_list);
958static DECLARE_WAIT_QUEUE_HEAD(ds_wait);
959
960struct ds_queue_entry {
961 struct list_head list;
962 struct ds_info *dp;
963 int req_len;
964 int __pad;
965 u64 req[0];
966};
967
968static void process_ds_work(void)
969{
970 struct ds_queue_entry *qp, *tmp;
971 unsigned long flags;
972 LIST_HEAD(todo);
973
974 spin_lock_irqsave(&ds_lock, flags);
975 list_splice_init(&ds_work_list, &todo);
976 spin_unlock_irqrestore(&ds_lock, flags);
977
978 list_for_each_entry_safe(qp, tmp, &todo, list) {
979 struct ds_data *dpkt = (struct ds_data *) qp->req;
980 struct ds_info *dp = qp->dp;
981 struct ds_cap_state *cp = find_cap(dp, dpkt->handle);
982 int req_len = qp->req_len;
983
984 if (!cp) {
985 printk(KERN_ERR "ds-%lu: Data for unknown "
986 "handle %lu\n",
987 dp->id, dpkt->handle);
988
989 spin_lock_irqsave(&ds_lock, flags);
990 __send_ds_nack(dp, dpkt->handle);
991 spin_unlock_irqrestore(&ds_lock, flags);
992 } else {
993 cp->data(dp, cp, dpkt, req_len);
994 }
995
996 list_del(&qp->list);
997 kfree(qp);
998 }
999}
1000
1001static int ds_thread(void *__unused)
1002{
1003 DEFINE_WAIT(wait);
1004
1005 while (1) {
1006 prepare_to_wait(&ds_wait, &wait, TASK_INTERRUPTIBLE);
1007 if (list_empty(&ds_work_list))
1008 schedule();
1009 finish_wait(&ds_wait, &wait);
1010
1011 if (kthread_should_stop())
1012 break;
1013
1014 process_ds_work();
1015 }
1016
1017 return 0;
1018}
1019
1020static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len)
1021{
1022 struct ds_data *dpkt = (struct ds_data *) pkt;
1023 struct ds_queue_entry *qp;
1024
1025 qp = kmalloc(sizeof(struct ds_queue_entry) + len, GFP_ATOMIC);
1026 if (!qp) {
1027 __send_ds_nack(dp, dpkt->handle);
1028 } else {
1029 qp->dp = dp;
1030 memcpy(&qp->req, pkt, len);
1031 list_add_tail(&qp->list, &ds_work_list);
1032 wake_up(&ds_wait);
1033 }
1034 return 0;
1035}
1036
1037static void ds_up(struct ds_info *dp)
1038{
1039 struct ldc_channel *lp = dp->lp;
1040 struct ds_ver_req req;
1041 int err;
1042
1043 req.tag.type = DS_INIT_REQ;
1044 req.tag.len = sizeof(req) - sizeof(struct ds_msg_tag);
1045 req.ver.major = 1;
1046 req.ver.minor = 0;
1047
1048 err = __ds_send(lp, &req, sizeof(req));
1049 if (err > 0)
1050 dp->hs_state = DS_HS_START;
1051}
1052
1053static void ds_reset(struct ds_info *dp)
1054{
1055 int i;
1056
1057 dp->hs_state = 0;
1058
1059 for (i = 0; i < dp->num_ds_states; i++) {
1060 struct ds_cap_state *cp = &dp->ds_states[i];
1061
1062 cp->state = CAP_STATE_UNKNOWN;
1063 }
1064}
1065
1066static void ds_event(void *arg, int event)
1067{
1068 struct ds_info *dp = arg;
1069 struct ldc_channel *lp = dp->lp;
1070 unsigned long flags;
1071 int err;
1072
1073 spin_lock_irqsave(&ds_lock, flags);
1074
1075 if (event == LDC_EVENT_UP) {
1076 ds_up(dp);
1077 spin_unlock_irqrestore(&ds_lock, flags);
1078 return;
1079 }
1080
1081 if (event == LDC_EVENT_RESET) {
1082 ds_reset(dp);
1083 spin_unlock_irqrestore(&ds_lock, flags);
1084 return;
1085 }
1086
1087 if (event != LDC_EVENT_DATA_READY) {
1088 printk(KERN_WARNING "ds-%lu: Unexpected LDC event %d\n",
1089 dp->id, event);
1090 spin_unlock_irqrestore(&ds_lock, flags);
1091 return;
1092 }
1093
1094 err = 0;
1095 while (1) {
1096 struct ds_msg_tag *tag;
1097
1098 err = ldc_read(lp, dp->rcv_buf, sizeof(*tag));
1099
1100 if (unlikely(err < 0)) {
1101 if (err == -ECONNRESET)
1102 ds_conn_reset(dp);
1103 break;
1104 }
1105 if (err == 0)
1106 break;
1107
1108 tag = dp->rcv_buf;
1109 err = ldc_read(lp, tag + 1, tag->len);
1110
1111 if (unlikely(err < 0)) {
1112 if (err == -ECONNRESET)
1113 ds_conn_reset(dp);
1114 break;
1115 }
1116 if (err < tag->len)
1117 break;
1118
1119 if (tag->type < DS_DATA)
1120 err = ds_handshake(dp, dp->rcv_buf);
1121 else
1122 err = ds_data(dp, dp->rcv_buf,
1123 sizeof(*tag) + err);
1124 if (err == -ECONNRESET)
1125 break;
1126 }
1127
1128 spin_unlock_irqrestore(&ds_lock, flags);
1129}
1130
1131static int __devinit ds_probe(struct vio_dev *vdev,
1132 const struct vio_device_id *id)
1133{
1134 static int ds_version_printed;
1135 struct ldc_channel_config ds_cfg = {
1136 .event = ds_event,
1137 .mtu = 4096,
1138 .mode = LDC_MODE_STREAM,
1139 };
1140 struct mdesc_handle *hp;
1141 struct ldc_channel *lp;
1142 struct ds_info *dp;
1143 const u64 *val;
1144 int err, i;
1145
1146 if (ds_version_printed++ == 0)
1147 printk(KERN_INFO "%s", version);
1148
1149 dp = kzalloc(sizeof(*dp), GFP_KERNEL);
1150 err = -ENOMEM;
1151 if (!dp)
1152 goto out_err;
1153
1154 hp = mdesc_grab();
1155 val = mdesc_get_property(hp, vdev->mp, "id", NULL);
1156 if (val)
1157 dp->id = *val;
1158 mdesc_release(hp);
1159
1160 dp->rcv_buf = kzalloc(4096, GFP_KERNEL);
1161 if (!dp->rcv_buf)
1162 goto out_free_dp;
1163
1164 dp->rcv_buf_len = 4096;
1165
1166 dp->ds_states = kzalloc(sizeof(ds_states_template),
1167 GFP_KERNEL);
1168 if (!dp->ds_states)
1169 goto out_free_rcv_buf;
1170
1171 memcpy(dp->ds_states, ds_states_template,
1172 sizeof(ds_states_template));
1173 dp->num_ds_states = ARRAY_SIZE(ds_states_template);
1174
1175 for (i = 0; i < dp->num_ds_states; i++)
1176 dp->ds_states[i].handle = ((u64)i << 32);
1177
1178 ds_cfg.tx_irq = vdev->tx_irq;
1179 ds_cfg.rx_irq = vdev->rx_irq;
1180
1181 lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp);
1182 if (IS_ERR(lp)) {
1183 err = PTR_ERR(lp);
1184 goto out_free_ds_states;
1185 }
1186 dp->lp = lp;
1187
1188 err = ldc_bind(lp, "DS");
1189 if (err)
1190 goto out_free_ldc;
1191
1192 spin_lock_irq(&ds_lock);
1193 dp->next = ds_info_list;
1194 ds_info_list = dp;
1195 spin_unlock_irq(&ds_lock);
1196
1197 return err;
1198
1199out_free_ldc:
1200 ldc_free(dp->lp);
1201
1202out_free_ds_states:
1203 kfree(dp->ds_states);
1204
1205out_free_rcv_buf:
1206 kfree(dp->rcv_buf);
1207
1208out_free_dp:
1209 kfree(dp);
1210
1211out_err:
1212 return err;
1213}
1214
1215static int ds_remove(struct vio_dev *vdev)
1216{
1217 return 0;
1218}
1219
1220static struct vio_device_id __initdata ds_match[] = {
1221 {
1222 .type = "domain-services-port",
1223 },
1224 {},
1225};
1226
1227static struct vio_driver ds_driver = {
1228 .id_table = ds_match,
1229 .probe = ds_probe,
1230 .remove = ds_remove,
1231 .driver = {
1232 .name = "ds",
1233 .owner = THIS_MODULE,
1234 }
1235};
1236
1237static int __init ds_init(void)
1238{
1239 kthread_run(ds_thread, NULL, "kldomd");
1240
1241 return vio_register_driver(&ds_driver);
1242}
1243
1244subsys_initcall(ds_init);