blob: 4e20ef232c51ffe0683f0ca3b628722a5172dd3c [file] [log] [blame]
David S. Millere4509922007-07-11 18:51:31 -07001/* 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>
David S. Millerb3e13fb2007-07-12 15:55:55 -070014#include <linux/mutex.h>
David S. Millere4509922007-07-11 18:51:31 -070015
16#include <asm/ldc.h>
17#include <asm/vio.h>
18#include <asm/power.h>
David S. Miller43fdf272007-07-12 13:47:50 -070019#include <asm/mdesc.h>
David S. Millere4509922007-07-11 18:51:31 -070020
21#define DRV_MODULE_NAME "ds"
22#define PFX DRV_MODULE_NAME ": "
23#define DRV_MODULE_VERSION "1.0"
24#define DRV_MODULE_RELDATE "Jul 11, 2007"
25
26static char version[] __devinitdata =
27 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
28MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
29MODULE_DESCRIPTION("Sun LDOM domain services driver");
30MODULE_LICENSE("GPL");
31MODULE_VERSION(DRV_MODULE_VERSION);
32
33struct ds_msg_tag {
34 __u32 type;
35#define DS_INIT_REQ 0x00
36#define DS_INIT_ACK 0x01
37#define DS_INIT_NACK 0x02
38#define DS_REG_REQ 0x03
39#define DS_REG_ACK 0x04
40#define DS_REG_NACK 0x05
41#define DS_UNREG_REQ 0x06
42#define DS_UNREG_ACK 0x07
43#define DS_UNREG_NACK 0x08
44#define DS_DATA 0x09
45#define DS_NACK 0x0a
46
47 __u32 len;
48};
49
50/* Result codes */
51#define DS_OK 0x00
52#define DS_REG_VER_NACK 0x01
53#define DS_REG_DUP 0x02
54#define DS_INV_HDL 0x03
55#define DS_TYPE_UNKNOWN 0x04
56
57struct ds_version {
58 __u16 major;
59 __u16 minor;
60};
61
62struct ds_ver_req {
63 struct ds_msg_tag tag;
64 struct ds_version ver;
65};
66
67struct ds_ver_ack {
68 struct ds_msg_tag tag;
69 __u16 minor;
70};
71
72struct ds_ver_nack {
73 struct ds_msg_tag tag;
74 __u16 major;
75};
76
77struct ds_reg_req {
78 struct ds_msg_tag tag;
79 __u64 handle;
80 __u16 major;
81 __u16 minor;
82 char svc_id[0];
83};
84
85struct ds_reg_ack {
86 struct ds_msg_tag tag;
87 __u64 handle;
88 __u16 minor;
89};
90
91struct ds_reg_nack {
92 struct ds_msg_tag tag;
93 __u64 handle;
94 __u16 major;
95};
96
97struct ds_unreg_req {
98 struct ds_msg_tag tag;
99 __u64 handle;
100};
101
102struct ds_unreg_ack {
103 struct ds_msg_tag tag;
104 __u64 handle;
105};
106
107struct ds_unreg_nack {
108 struct ds_msg_tag tag;
109 __u64 handle;
110};
111
112struct ds_data {
113 struct ds_msg_tag tag;
114 __u64 handle;
115};
116
117struct ds_data_nack {
118 struct ds_msg_tag tag;
119 __u64 handle;
120 __u64 result;
121};
122
123struct ds_cap_state {
124 __u64 handle;
125
126 void (*data)(struct ldc_channel *lp,
127 struct ds_cap_state *dp,
128 void *buf, int len);
129
130 const char *service_id;
131
132 u8 state;
133#define CAP_STATE_UNKNOWN 0x00
134#define CAP_STATE_REG_SENT 0x01
135#define CAP_STATE_REGISTERED 0x02
136};
137
138static int ds_send(struct ldc_channel *lp, void *data, int len)
139{
140 int err, limit = 1000;
141
142 err = -EINVAL;
143 while (limit-- > 0) {
144 err = ldc_write(lp, data, len);
145 if (!err || (err != -EAGAIN))
146 break;
147 udelay(1);
148 }
149
150 return err;
151}
152
153struct ds_md_update_req {
154 __u64 req_num;
155};
156
157struct ds_md_update_res {
158 __u64 req_num;
159 __u32 result;
160};
161
162static void md_update_data(struct ldc_channel *lp,
163 struct ds_cap_state *dp,
164 void *buf, int len)
165{
166 struct ds_data *dpkt = buf;
167 struct ds_md_update_req *rp;
168 struct {
169 struct ds_data data;
170 struct ds_md_update_res res;
171 } pkt;
172
173 rp = (struct ds_md_update_req *) (dpkt + 1);
174
David S. Millerb3e13fb2007-07-12 15:55:55 -0700175 printk(KERN_INFO PFX "Machine description update.\n");
David S. Millere4509922007-07-11 18:51:31 -0700176
177 memset(&pkt, 0, sizeof(pkt));
178 pkt.data.tag.type = DS_DATA;
179 pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
180 pkt.data.handle = dp->handle;
181 pkt.res.req_num = rp->req_num;
182 pkt.res.result = DS_OK;
183
184 ds_send(lp, &pkt, sizeof(pkt));
David S. Miller43fdf272007-07-12 13:47:50 -0700185
186 mdesc_update();
David S. Millere4509922007-07-11 18:51:31 -0700187}
188
189struct ds_shutdown_req {
190 __u64 req_num;
191 __u32 ms_delay;
192};
193
194struct ds_shutdown_res {
195 __u64 req_num;
196 __u32 result;
197 char reason[1];
198};
199
200static void domain_shutdown_data(struct ldc_channel *lp,
201 struct ds_cap_state *dp,
202 void *buf, int len)
203{
204 struct ds_data *dpkt = buf;
205 struct ds_shutdown_req *rp;
206 struct {
207 struct ds_data data;
208 struct ds_shutdown_res res;
209 } pkt;
210
211 rp = (struct ds_shutdown_req *) (dpkt + 1);
212
213 printk(KERN_ALERT PFX "Shutdown request from "
214 "LDOM manager received.\n");
215
216 memset(&pkt, 0, sizeof(pkt));
217 pkt.data.tag.type = DS_DATA;
218 pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
219 pkt.data.handle = dp->handle;
220 pkt.res.req_num = rp->req_num;
221 pkt.res.result = DS_OK;
222 pkt.res.reason[0] = 0;
223
224 ds_send(lp, &pkt, sizeof(pkt));
225
226 wake_up_powerd();
227}
228
229struct ds_panic_req {
230 __u64 req_num;
231};
232
233struct ds_panic_res {
234 __u64 req_num;
235 __u32 result;
236 char reason[1];
237};
238
239static void domain_panic_data(struct ldc_channel *lp,
240 struct ds_cap_state *dp,
241 void *buf, int len)
242{
243 struct ds_data *dpkt = buf;
244 struct ds_panic_req *rp;
245 struct {
246 struct ds_data data;
247 struct ds_panic_res res;
248 } pkt;
249
250 rp = (struct ds_panic_req *) (dpkt + 1);
251
David S. Millerb3e13fb2007-07-12 15:55:55 -0700252 printk(KERN_ALERT PFX "Panic request from "
253 "LDOM manager received.\n");
David S. Millere4509922007-07-11 18:51:31 -0700254
255 memset(&pkt, 0, sizeof(pkt));
256 pkt.data.tag.type = DS_DATA;
257 pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
258 pkt.data.handle = dp->handle;
259 pkt.res.req_num = rp->req_num;
260 pkt.res.result = DS_OK;
261 pkt.res.reason[0] = 0;
262
263 ds_send(lp, &pkt, sizeof(pkt));
264
265 panic("PANIC requested by LDOM manager.");
266}
267
268struct ds_cpu_tag {
269 __u64 req_num;
270 __u32 type;
271#define DS_CPU_CONFIGURE 0x43
272#define DS_CPU_UNCONFIGURE 0x55
273#define DS_CPU_FORCE_UNCONFIGURE 0x46
274#define DS_CPU_STATUS 0x53
275
276/* Responses */
277#define DS_CPU_OK 0x6f
278#define DS_CPU_ERROR 0x65
279
280 __u32 num_records;
281};
282
283struct ds_cpu_record {
284 __u32 cpu_id;
285};
286
287static void dr_cpu_data(struct ldc_channel *lp,
288 struct ds_cap_state *dp,
289 void *buf, int len)
290{
291 struct ds_data *dpkt = buf;
292 struct ds_cpu_tag *rp;
293
294 rp = (struct ds_cpu_tag *) (dpkt + 1);
295
296 printk(KERN_ERR PFX "CPU REQ [%lx:%x], len=%d\n",
297 rp->req_num, rp->type, len);
298}
299
300struct ds_pri_msg {
301 __u64 req_num;
302 __u64 type;
303#define DS_PRI_REQUEST 0x00
304#define DS_PRI_DATA 0x01
305#define DS_PRI_UPDATE 0x02
306};
307
308static void ds_pri_data(struct ldc_channel *lp,
309 struct ds_cap_state *dp,
310 void *buf, int len)
311{
312 struct ds_data *dpkt = buf;
313 struct ds_pri_msg *rp;
314
315 rp = (struct ds_pri_msg *) (dpkt + 1);
316
David S. Millerb3e13fb2007-07-12 15:55:55 -0700317 printk(KERN_INFO PFX "PRI REQ [%lx:%lx], len=%d\n",
David S. Millere4509922007-07-11 18:51:31 -0700318 rp->req_num, rp->type, len);
319}
320
David S. Millerb3e13fb2007-07-12 15:55:55 -0700321struct 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
David S. Millere4509922007-07-11 18:51:31 -0700371struct ds_cap_state ds_states[] = {
372 {
373 .service_id = "md-update",
374 .data = md_update_data,
375 },
376 {
377 .service_id = "domain-shutdown",
378 .data = domain_shutdown_data,
379 },
380 {
381 .service_id = "domain-panic",
382 .data = domain_panic_data,
383 },
384 {
385 .service_id = "dr-cpu",
386 .data = dr_cpu_data,
387 },
388 {
389 .service_id = "pri",
390 .data = ds_pri_data,
391 },
David S. Millerb3e13fb2007-07-12 15:55:55 -0700392 {
393 .service_id = "var-config",
394 .data = ds_var_data,
395 },
396 {
397 .service_id = "var-config-backup",
398 .data = ds_var_data,
399 },
David S. Millere4509922007-07-11 18:51:31 -0700400};
401
David S. Millere4509922007-07-11 18:51:31 -0700402static DEFINE_SPINLOCK(ds_lock);
403
404struct ds_info {
405 struct ldc_channel *lp;
406 u8 hs_state;
407#define DS_HS_START 0x01
408#define DS_HS_DONE 0x02
409
410 void *rcv_buf;
411 int rcv_buf_len;
412};
413
David S. Millerb3e13fb2007-07-12 15:55:55 -0700414static 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
David S. Millere4509922007-07-11 18:51:31 -0700523static void ds_conn_reset(struct ds_info *dp)
524{
525 printk(KERN_ERR PFX "ds_conn_reset() from %p\n",
526 __builtin_return_address(0));
527}
528
529static int register_services(struct ds_info *dp)
530{
531 struct ldc_channel *lp = dp->lp;
532 int i;
533
534 for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
535 struct {
536 struct ds_reg_req req;
537 u8 id_buf[256];
538 } pbuf;
539 struct ds_cap_state *cp = &ds_states[i];
540 int err, msg_len;
541 u64 new_count;
542
543 if (cp->state == CAP_STATE_REGISTERED)
544 continue;
545
546 new_count = sched_clock() & 0xffffffff;
547 cp->handle = ((u64) i << 32) | new_count;
548
549 msg_len = (sizeof(struct ds_reg_req) +
550 strlen(cp->service_id));
551
552 memset(&pbuf, 0, sizeof(pbuf));
553 pbuf.req.tag.type = DS_REG_REQ;
554 pbuf.req.tag.len = (msg_len - sizeof(struct ds_msg_tag));
555 pbuf.req.handle = cp->handle;
556 pbuf.req.major = 1;
557 pbuf.req.minor = 0;
558 strcpy(pbuf.req.svc_id, cp->service_id);
559
560 err = ds_send(lp, &pbuf, msg_len);
561 if (err > 0)
562 cp->state = CAP_STATE_REG_SENT;
563 }
564 return 0;
565}
566
567static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt)
568{
569
570 if (dp->hs_state == DS_HS_START) {
571 if (pkt->type != DS_INIT_ACK)
572 goto conn_reset;
573
574 dp->hs_state = DS_HS_DONE;
575
576 return register_services(dp);
577 }
578
579 if (dp->hs_state != DS_HS_DONE)
580 goto conn_reset;
581
582 if (pkt->type == DS_REG_ACK) {
583 struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;
584 struct ds_cap_state *cp = find_cap(ap->handle);
585
586 if (!cp) {
587 printk(KERN_ERR PFX "REG ACK for unknown handle %lx\n",
588 ap->handle);
589 return 0;
590 }
591 printk(KERN_INFO PFX "Registered %s service.\n",
592 cp->service_id);
593 cp->state = CAP_STATE_REGISTERED;
594 } else if (pkt->type == DS_REG_NACK) {
595 struct ds_reg_nack *np = (struct ds_reg_nack *) pkt;
596 struct ds_cap_state *cp = find_cap(np->handle);
597
598 if (!cp) {
599 printk(KERN_ERR PFX "REG NACK for "
600 "unknown handle %lx\n",
601 np->handle);
602 return 0;
603 }
604 printk(KERN_ERR PFX "Could not register %s service\n",
605 cp->service_id);
606 cp->state = CAP_STATE_UNKNOWN;
607 }
608
609 return 0;
610
611conn_reset:
612 ds_conn_reset(dp);
613 return -ECONNRESET;
614}
615
616static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len)
617{
618 struct ds_data *dpkt = (struct ds_data *) pkt;
619 struct ds_cap_state *cp = find_cap(dpkt->handle);
620
621 if (!cp) {
622 struct ds_data_nack nack = {
623 .tag = {
624 .type = DS_NACK,
625 .len = (sizeof(struct ds_data_nack) -
626 sizeof(struct ds_msg_tag)),
627 },
628 .handle = dpkt->handle,
629 .result = DS_INV_HDL,
630 };
631
632 printk(KERN_ERR PFX "Data for unknown handle %lu\n",
633 dpkt->handle);
634 ds_send(dp->lp, &nack, sizeof(nack));
635 } else {
636 cp->data(dp->lp, cp, dpkt, len);
637 }
638 return 0;
639}
640
641static void ds_up(struct ds_info *dp)
642{
643 struct ldc_channel *lp = dp->lp;
644 struct ds_ver_req req;
645 int err;
646
647 req.tag.type = DS_INIT_REQ;
648 req.tag.len = sizeof(req) - sizeof(struct ds_msg_tag);
649 req.ver.major = 1;
650 req.ver.minor = 0;
651
652 err = ds_send(lp, &req, sizeof(req));
653 if (err > 0)
654 dp->hs_state = DS_HS_START;
655}
656
657static void ds_event(void *arg, int event)
658{
659 struct ds_info *dp = arg;
660 struct ldc_channel *lp = dp->lp;
661 unsigned long flags;
662 int err;
663
664 spin_lock_irqsave(&ds_lock, flags);
665
666 if (event == LDC_EVENT_UP) {
667 ds_up(dp);
668 spin_unlock_irqrestore(&ds_lock, flags);
669 return;
670 }
671
672 if (event != LDC_EVENT_DATA_READY) {
673 printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
674 spin_unlock_irqrestore(&ds_lock, flags);
675 return;
676 }
677
678 err = 0;
679 while (1) {
680 struct ds_msg_tag *tag;
681
682 err = ldc_read(lp, dp->rcv_buf, sizeof(*tag));
683
684 if (unlikely(err < 0)) {
685 if (err == -ECONNRESET)
686 ds_conn_reset(dp);
687 break;
688 }
689 if (err == 0)
690 break;
691
692 tag = dp->rcv_buf;
693 err = ldc_read(lp, tag + 1, tag->len);
694
695 if (unlikely(err < 0)) {
696 if (err == -ECONNRESET)
697 ds_conn_reset(dp);
698 break;
699 }
700 if (err < tag->len)
701 break;
702
703 if (tag->type < DS_DATA)
704 err = ds_handshake(dp, dp->rcv_buf);
705 else
706 err = ds_data(dp, dp->rcv_buf,
707 sizeof(*tag) + err);
708 if (err == -ECONNRESET)
709 break;
710 }
711
712 spin_unlock_irqrestore(&ds_lock, flags);
713}
714
715static int __devinit ds_probe(struct vio_dev *vdev,
716 const struct vio_device_id *id)
717{
718 static int ds_version_printed;
David S. Millere4509922007-07-11 18:51:31 -0700719 struct ldc_channel_config ds_cfg = {
720 .event = ds_event,
721 .mtu = 4096,
722 .mode = LDC_MODE_STREAM,
723 };
724 struct ldc_channel *lp;
725 struct ds_info *dp;
David S. Millere4509922007-07-11 18:51:31 -0700726 int err;
727
728 if (ds_version_printed++ == 0)
729 printk(KERN_INFO "%s", version);
730
David S. Millere4509922007-07-11 18:51:31 -0700731 dp = kzalloc(sizeof(*dp), GFP_KERNEL);
732 err = -ENOMEM;
733 if (!dp)
734 goto out_err;
735
736 dp->rcv_buf = kzalloc(4096, GFP_KERNEL);
737 if (!dp->rcv_buf)
738 goto out_free_dp;
739
740 dp->rcv_buf_len = 4096;
741
David S. Miller43fdf272007-07-12 13:47:50 -0700742 ds_cfg.tx_irq = vdev->tx_irq;
743 ds_cfg.rx_irq = vdev->rx_irq;
David S. Millere4509922007-07-11 18:51:31 -0700744
David S. Miller43fdf272007-07-12 13:47:50 -0700745 lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp);
David S. Millere4509922007-07-11 18:51:31 -0700746 if (IS_ERR(lp)) {
747 err = PTR_ERR(lp);
748 goto out_free_rcv_buf;
749 }
750 dp->lp = lp;
751
David S. Miller133f09a2007-07-11 23:22:55 -0700752 err = ldc_bind(lp, "DS");
David S. Millere4509922007-07-11 18:51:31 -0700753 if (err)
754 goto out_free_ldc;
755
David S. Millerb3e13fb2007-07-12 15:55:55 -0700756 ds_info = dp;
757
David S. Millere4509922007-07-11 18:51:31 -0700758 start_powerd();
759
760 return err;
761
762out_free_ldc:
763 ldc_free(dp->lp);
764
765out_free_rcv_buf:
766 kfree(dp->rcv_buf);
767
768out_free_dp:
769 kfree(dp);
770
771out_err:
772 return err;
773}
774
775static int ds_remove(struct vio_dev *vdev)
776{
777 return 0;
778}
779
780static struct vio_device_id ds_match[] = {
781 {
782 .type = "domain-services-port",
783 },
784 {},
785};
786
787static struct vio_driver ds_driver = {
788 .id_table = ds_match,
789 .probe = ds_probe,
790 .remove = ds_remove,
791 .driver = {
792 .name = "ds",
793 .owner = THIS_MODULE,
794 }
795};
796
797static int __init ds_init(void)
798{
799 int i;
800
801 for (i = 0; i < ARRAY_SIZE(ds_states); i++)
802 ds_states[i].handle = ((u64)i << 32);
803
804 return vio_register_driver(&ds_driver);
805}
806
807subsys_initcall(ds_init);