]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/sparc64/kernel/ds.c
[SPARC64]: Initial domain-services driver.
[linux-2.6-omap-h63xx.git] / arch / sparc64 / kernel / ds.c
1 /* ds.c: Domain Services driver for Logical Domains
2  *
3  * Copyright (C) 2007 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/module.h>
10 #include <linux/string.h>
11 #include <linux/slab.h>
12 #include <linux/sched.h>
13 #include <linux/delay.h>
14
15 #include <asm/ldc.h>
16 #include <asm/vio.h>
17 #include <asm/power.h>
18
19 #define DRV_MODULE_NAME         "ds"
20 #define PFX DRV_MODULE_NAME     ": "
21 #define DRV_MODULE_VERSION      "1.0"
22 #define DRV_MODULE_RELDATE      "Jul 11, 2007"
23
24 static char version[] __devinitdata =
25         DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
26 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
27 MODULE_DESCRIPTION("Sun LDOM domain services driver");
28 MODULE_LICENSE("GPL");
29 MODULE_VERSION(DRV_MODULE_VERSION);
30
31 struct ds_msg_tag {
32         __u32                   type;
33 #define DS_INIT_REQ             0x00
34 #define DS_INIT_ACK             0x01
35 #define DS_INIT_NACK            0x02
36 #define DS_REG_REQ              0x03
37 #define DS_REG_ACK              0x04
38 #define DS_REG_NACK             0x05
39 #define DS_UNREG_REQ            0x06
40 #define DS_UNREG_ACK            0x07
41 #define DS_UNREG_NACK           0x08
42 #define DS_DATA                 0x09
43 #define DS_NACK                 0x0a
44
45         __u32                   len;
46 };
47
48 /* Result codes */
49 #define DS_OK                   0x00
50 #define DS_REG_VER_NACK         0x01
51 #define DS_REG_DUP              0x02
52 #define DS_INV_HDL              0x03
53 #define DS_TYPE_UNKNOWN         0x04
54
55 struct ds_version {
56         __u16                   major;
57         __u16                   minor;
58 };
59
60 struct ds_ver_req {
61         struct ds_msg_tag       tag;
62         struct ds_version       ver;
63 };
64
65 struct ds_ver_ack {
66         struct ds_msg_tag       tag;
67         __u16                   minor;
68 };
69
70 struct ds_ver_nack {
71         struct ds_msg_tag       tag;
72         __u16                   major;
73 };
74
75 struct ds_reg_req {
76         struct ds_msg_tag       tag;
77         __u64                   handle;
78         __u16                   major;
79         __u16                   minor;
80         char                    svc_id[0];
81 };
82
83 struct ds_reg_ack {
84         struct ds_msg_tag       tag;
85         __u64                   handle;
86         __u16                   minor;
87 };
88
89 struct ds_reg_nack {
90         struct ds_msg_tag       tag;
91         __u64                   handle;
92         __u16                   major;
93 };
94
95 struct ds_unreg_req {
96         struct ds_msg_tag       tag;
97         __u64                   handle;
98 };
99
100 struct ds_unreg_ack {
101         struct ds_msg_tag       tag;
102         __u64                   handle;
103 };
104
105 struct ds_unreg_nack {
106         struct ds_msg_tag       tag;
107         __u64                   handle;
108 };
109
110 struct ds_data {
111         struct ds_msg_tag       tag;
112         __u64                   handle;
113 };
114
115 struct ds_data_nack {
116         struct ds_msg_tag       tag;
117         __u64                   handle;
118         __u64                   result;
119 };
120
121 struct ds_cap_state {
122         __u64                   handle;
123
124         void                    (*data)(struct ldc_channel *lp,
125                                         struct ds_cap_state *dp,
126                                         void *buf, int len);
127
128         const char              *service_id;
129
130         u8                      state;
131 #define CAP_STATE_UNKNOWN       0x00
132 #define CAP_STATE_REG_SENT      0x01
133 #define CAP_STATE_REGISTERED    0x02
134 };
135
136 static int ds_send(struct ldc_channel *lp, void *data, int len)
137 {
138         int err, limit = 1000;
139
140         err = -EINVAL;
141         while (limit-- > 0) {
142                 err = ldc_write(lp, data, len);
143                 if (!err || (err != -EAGAIN))
144                         break;
145                 udelay(1);
146         }
147
148         return err;
149 }
150
151 struct ds_md_update_req {
152         __u64                           req_num;
153 };
154
155 struct ds_md_update_res {
156         __u64                           req_num;
157         __u32                           result;
158 };
159
160 static void md_update_data(struct ldc_channel *lp,
161                            struct ds_cap_state *dp,
162                            void *buf, int len)
163 {
164         struct ds_data *dpkt = buf;
165         struct ds_md_update_req *rp;
166         struct {
167                 struct ds_data          data;
168                 struct ds_md_update_res res;
169         } pkt;
170
171         rp = (struct ds_md_update_req *) (dpkt + 1);
172
173         printk(KERN_ERR PFX "MD update REQ [%lx] len=%d\n",
174                rp->req_num, len);
175
176         memset(&pkt, 0, sizeof(pkt));
177         pkt.data.tag.type = DS_DATA;
178         pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
179         pkt.data.handle = dp->handle;
180         pkt.res.req_num = rp->req_num;
181         pkt.res.result = DS_OK;
182
183         ds_send(lp, &pkt, sizeof(pkt));
184 }
185
186 struct ds_shutdown_req {
187         __u64                           req_num;
188         __u32                           ms_delay;
189 };
190
191 struct ds_shutdown_res {
192         __u64                           req_num;
193         __u32                           result;
194         char                            reason[1];
195 };
196
197 static void domain_shutdown_data(struct ldc_channel *lp,
198                                  struct ds_cap_state *dp,
199                                  void *buf, int len)
200 {
201         struct ds_data *dpkt = buf;
202         struct ds_shutdown_req *rp;
203         struct {
204                 struct ds_data          data;
205                 struct ds_shutdown_res  res;
206         } pkt;
207
208         rp = (struct ds_shutdown_req *) (dpkt + 1);
209
210         printk(KERN_ALERT PFX "Shutdown request from "
211                "LDOM manager received.\n");
212
213         memset(&pkt, 0, sizeof(pkt));
214         pkt.data.tag.type = DS_DATA;
215         pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
216         pkt.data.handle = dp->handle;
217         pkt.res.req_num = rp->req_num;
218         pkt.res.result = DS_OK;
219         pkt.res.reason[0] = 0;
220
221         ds_send(lp, &pkt, sizeof(pkt));
222
223         wake_up_powerd();
224 }
225
226 struct ds_panic_req {
227         __u64                           req_num;
228 };
229
230 struct ds_panic_res {
231         __u64                           req_num;
232         __u32                           result;
233         char                            reason[1];
234 };
235
236 static void domain_panic_data(struct ldc_channel *lp,
237                               struct ds_cap_state *dp,
238                               void *buf, int len)
239 {
240         struct ds_data *dpkt = buf;
241         struct ds_panic_req *rp;
242         struct {
243                 struct ds_data          data;
244                 struct ds_panic_res     res;
245         } pkt;
246
247         rp = (struct ds_panic_req *) (dpkt + 1);
248
249         printk(KERN_ERR PFX "Panic REQ [%lx], len=%d\n",
250                rp->req_num, len);
251
252         memset(&pkt, 0, sizeof(pkt));
253         pkt.data.tag.type = DS_DATA;
254         pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
255         pkt.data.handle = dp->handle;
256         pkt.res.req_num = rp->req_num;
257         pkt.res.result = DS_OK;
258         pkt.res.reason[0] = 0;
259
260         ds_send(lp, &pkt, sizeof(pkt));
261
262         panic("PANIC requested by LDOM manager.");
263 }
264
265 struct ds_cpu_tag {
266         __u64                           req_num;
267         __u32                           type;
268 #define DS_CPU_CONFIGURE                0x43
269 #define DS_CPU_UNCONFIGURE              0x55
270 #define DS_CPU_FORCE_UNCONFIGURE        0x46
271 #define DS_CPU_STATUS                   0x53
272
273 /* Responses */
274 #define DS_CPU_OK                       0x6f
275 #define DS_CPU_ERROR                    0x65
276
277         __u32                           num_records;
278 };
279
280 struct ds_cpu_record {
281         __u32                           cpu_id;
282 };
283
284 static void dr_cpu_data(struct ldc_channel *lp,
285                         struct ds_cap_state *dp,
286                         void *buf, int len)
287 {
288         struct ds_data *dpkt = buf;
289         struct ds_cpu_tag *rp;
290
291         rp = (struct ds_cpu_tag *) (dpkt + 1);
292
293         printk(KERN_ERR PFX "CPU REQ [%lx:%x], len=%d\n",
294                rp->req_num, rp->type, len);
295 }
296
297 struct ds_pri_msg {
298         __u64                           req_num;
299         __u64                           type;
300 #define DS_PRI_REQUEST                  0x00
301 #define DS_PRI_DATA                     0x01
302 #define DS_PRI_UPDATE                   0x02
303 };
304
305 static void ds_pri_data(struct ldc_channel *lp,
306                         struct ds_cap_state *dp,
307                         void *buf, int len)
308 {
309         struct ds_data *dpkt = buf;
310         struct ds_pri_msg *rp;
311
312         rp = (struct ds_pri_msg *) (dpkt + 1);
313
314         printk(KERN_ERR PFX "PRI REQ [%lx:%lx], len=%d\n",
315                rp->req_num, rp->type, len);
316 }
317
318 struct ds_cap_state ds_states[] = {
319         {
320                 .service_id     = "md-update",
321                 .data           = md_update_data,
322         },
323         {
324                 .service_id     = "domain-shutdown",
325                 .data           = domain_shutdown_data,
326         },
327         {
328                 .service_id     = "domain-panic",
329                 .data           = domain_panic_data,
330         },
331         {
332                 .service_id     = "dr-cpu",
333                 .data           = dr_cpu_data,
334         },
335         {
336                 .service_id     = "pri",
337                 .data           = ds_pri_data,
338         },
339 };
340
341 static struct ds_cap_state *find_cap(u64 handle)
342 {
343         unsigned int index = handle >> 32;
344
345         if (index >= ARRAY_SIZE(ds_states))
346                 return NULL;
347         return &ds_states[index];
348 }
349
350 static DEFINE_SPINLOCK(ds_lock);
351
352 struct ds_info {
353         struct ldc_channel      *lp;
354         u8                      hs_state;
355 #define DS_HS_START             0x01
356 #define DS_HS_DONE              0x02
357
358         void                    *rcv_buf;
359         int                     rcv_buf_len;
360 };
361
362 static void ds_conn_reset(struct ds_info *dp)
363 {
364         printk(KERN_ERR PFX "ds_conn_reset() from %p\n",
365                __builtin_return_address(0));
366 }
367
368 static int register_services(struct ds_info *dp)
369 {
370         struct ldc_channel *lp = dp->lp;
371         int i;
372
373         for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
374                 struct {
375                         struct ds_reg_req req;
376                         u8 id_buf[256];
377                 } pbuf;
378                 struct ds_cap_state *cp = &ds_states[i];
379                 int err, msg_len;
380                 u64 new_count;
381
382                 if (cp->state == CAP_STATE_REGISTERED)
383                         continue;
384
385                 new_count = sched_clock() & 0xffffffff;
386                 cp->handle = ((u64) i << 32) | new_count;
387
388                 msg_len = (sizeof(struct ds_reg_req) +
389                            strlen(cp->service_id));
390
391                 memset(&pbuf, 0, sizeof(pbuf));
392                 pbuf.req.tag.type = DS_REG_REQ;
393                 pbuf.req.tag.len = (msg_len - sizeof(struct ds_msg_tag));
394                 pbuf.req.handle = cp->handle;
395                 pbuf.req.major = 1;
396                 pbuf.req.minor = 0;
397                 strcpy(pbuf.req.svc_id, cp->service_id);
398
399                 err = ds_send(lp, &pbuf, msg_len);
400                 if (err > 0)
401                         cp->state = CAP_STATE_REG_SENT;
402         }
403         return 0;
404 }
405
406 static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt)
407 {
408
409         if (dp->hs_state == DS_HS_START) {
410                 if (pkt->type != DS_INIT_ACK)
411                         goto conn_reset;
412
413                 dp->hs_state = DS_HS_DONE;
414
415                 return register_services(dp);
416         }
417
418         if (dp->hs_state != DS_HS_DONE)
419                 goto conn_reset;
420
421         if (pkt->type == DS_REG_ACK) {
422                 struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;
423                 struct ds_cap_state *cp = find_cap(ap->handle);
424
425                 if (!cp) {
426                         printk(KERN_ERR PFX "REG ACK for unknown handle %lx\n",
427                                ap->handle);
428                         return 0;
429                 }
430                 printk(KERN_INFO PFX "Registered %s service.\n",
431                        cp->service_id);
432                 cp->state = CAP_STATE_REGISTERED;
433         } else if (pkt->type == DS_REG_NACK) {
434                 struct ds_reg_nack *np = (struct ds_reg_nack *) pkt;
435                 struct ds_cap_state *cp = find_cap(np->handle);
436
437                 if (!cp) {
438                         printk(KERN_ERR PFX "REG NACK for "
439                                "unknown handle %lx\n",
440                                np->handle);
441                         return 0;
442                 }
443                 printk(KERN_ERR PFX "Could not register %s service\n",
444                        cp->service_id);
445                 cp->state = CAP_STATE_UNKNOWN;
446         }
447
448         return 0;
449
450 conn_reset:
451         ds_conn_reset(dp);
452         return -ECONNRESET;
453 }
454
455 static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len)
456 {
457         struct ds_data *dpkt = (struct ds_data *) pkt;
458         struct ds_cap_state *cp = find_cap(dpkt->handle);
459
460         if (!cp) {
461                 struct ds_data_nack nack = {
462                         .tag = {
463                                 .type = DS_NACK,
464                                 .len = (sizeof(struct ds_data_nack) -
465                                         sizeof(struct ds_msg_tag)),
466                         },
467                         .handle = dpkt->handle,
468                         .result = DS_INV_HDL,
469                 };
470
471                 printk(KERN_ERR PFX "Data for unknown handle %lu\n",
472                        dpkt->handle);
473                 ds_send(dp->lp, &nack, sizeof(nack));
474         } else {
475                 cp->data(dp->lp, cp, dpkt, len);
476         }
477         return 0;
478 }
479
480 static void ds_up(struct ds_info *dp)
481 {
482         struct ldc_channel *lp = dp->lp;
483         struct ds_ver_req req;
484         int err;
485
486         req.tag.type = DS_INIT_REQ;
487         req.tag.len = sizeof(req) - sizeof(struct ds_msg_tag);
488         req.ver.major = 1;
489         req.ver.minor = 0;
490
491         err = ds_send(lp, &req, sizeof(req));
492         if (err > 0)
493                 dp->hs_state = DS_HS_START;
494 }
495
496 static void ds_event(void *arg, int event)
497 {
498         struct ds_info *dp = arg;
499         struct ldc_channel *lp = dp->lp;
500         unsigned long flags;
501         int err;
502
503         spin_lock_irqsave(&ds_lock, flags);
504
505         if (event == LDC_EVENT_UP) {
506                 ds_up(dp);
507                 spin_unlock_irqrestore(&ds_lock, flags);
508                 return;
509         }
510
511         if (event != LDC_EVENT_DATA_READY) {
512                 printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
513                 spin_unlock_irqrestore(&ds_lock, flags);
514                 return;
515         }
516
517         err = 0;
518         while (1) {
519                 struct ds_msg_tag *tag;
520
521                 err = ldc_read(lp, dp->rcv_buf, sizeof(*tag));
522
523                 if (unlikely(err < 0)) {
524                         if (err == -ECONNRESET)
525                                 ds_conn_reset(dp);
526                         break;
527                 }
528                 if (err == 0)
529                         break;
530
531                 tag = dp->rcv_buf;
532                 err = ldc_read(lp, tag + 1, tag->len);
533
534                 if (unlikely(err < 0)) {
535                         if (err == -ECONNRESET)
536                                 ds_conn_reset(dp);
537                         break;
538                 }
539                 if (err < tag->len)
540                         break;
541
542                 if (tag->type < DS_DATA)
543                         err = ds_handshake(dp, dp->rcv_buf);
544                 else
545                         err = ds_data(dp, dp->rcv_buf,
546                                       sizeof(*tag) + err);
547                 if (err == -ECONNRESET)
548                         break;
549         }
550
551         spin_unlock_irqrestore(&ds_lock, flags);
552 }
553
554 static int __devinit ds_probe(struct vio_dev *vdev,
555                               const struct vio_device_id *id)
556 {
557         static int ds_version_printed;
558         struct mdesc_node *endp;
559         struct ldc_channel_config ds_cfg = {
560                 .event          = ds_event,
561                 .mtu            = 4096,
562                 .mode           = LDC_MODE_STREAM,
563         };
564         struct ldc_channel *lp;
565         struct ds_info *dp;
566         const u64 *chan_id;
567         int err;
568
569         if (ds_version_printed++ == 0)
570                 printk(KERN_INFO "%s", version);
571
572         endp = vio_find_endpoint(vdev);
573         if (!endp)
574                 return -ENODEV;
575
576         chan_id = md_get_property(endp, "id", NULL);
577         if (!chan_id)
578                 return -ENODEV;
579
580         dp = kzalloc(sizeof(*dp), GFP_KERNEL);
581         err = -ENOMEM;
582         if (!dp)
583                 goto out_err;
584
585         dp->rcv_buf = kzalloc(4096, GFP_KERNEL);
586         if (!dp->rcv_buf)
587                 goto out_free_dp;
588
589         dp->rcv_buf_len = 4096;
590
591         ds_cfg.tx_irq = endp->irqs[0];
592         ds_cfg.rx_irq = endp->irqs[1];
593
594         lp = ldc_alloc(*chan_id, &ds_cfg, dp);
595         if (IS_ERR(lp)) {
596                 err = PTR_ERR(lp);
597                 goto out_free_rcv_buf;
598         }
599         dp->lp = lp;
600
601         err = ldc_bind(lp);
602         if (err)
603                 goto out_free_ldc;
604
605         start_powerd();
606
607         return err;
608
609 out_free_ldc:
610         ldc_free(dp->lp);
611
612 out_free_rcv_buf:
613         kfree(dp->rcv_buf);
614
615 out_free_dp:
616         kfree(dp);
617
618 out_err:
619         return err;
620 }
621
622 static int ds_remove(struct vio_dev *vdev)
623 {
624         return 0;
625 }
626
627 static struct vio_device_id ds_match[] = {
628         {
629                 .type = "domain-services-port",
630         },
631         {},
632 };
633
634 static struct vio_driver ds_driver = {
635         .id_table       = ds_match,
636         .probe          = ds_probe,
637         .remove         = ds_remove,
638         .driver         = {
639                 .name   = "ds",
640                 .owner  = THIS_MODULE,
641         }
642 };
643
644 static int __init ds_init(void)
645 {
646         int i;
647
648         for (i = 0; i < ARRAY_SIZE(ds_states); i++)
649                 ds_states[i].handle = ((u64)i << 32);
650
651         return vio_register_driver(&ds_driver);
652 }
653
654 subsys_initcall(ds_init);