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>
15 #include <linux/reboot.h>
18 #include <asm/hypervisor.h>
27 #define DRV_MODULE_NAME "ds"
28 #define PFX DRV_MODULE_NAME ": "
29 #define DRV_MODULE_VERSION "1.0"
30 #define DRV_MODULE_RELDATE "Jul 11, 2007"
41 #define DS_INIT_REQ 0x00
42 #define DS_INIT_ACK 0x01
43 #define DS_INIT_NACK 0x02
44 #define DS_REG_REQ 0x03
45 #define DS_REG_ACK 0x04
46 #define DS_REG_NACK 0x05
47 #define DS_UNREG_REQ 0x06
48 #define DS_UNREG_ACK 0x07
49 #define DS_UNREG_NACK 0x08
58 #define DS_REG_VER_NACK 0x01
59 #define DS_REG_DUP 0x02
60 #define DS_INV_HDL 0x03
61 #define DS_TYPE_UNKNOWN 0x04
140 #define CAP_STATE_UNKNOWN 0x00
141 #define CAP_STATE_REG_SENT 0x01
142 #define CAP_STATE_REGISTERED 0x02
147 static void domain_shutdown_data(
struct ds_info *
dp,
150 static void domain_panic_data(
struct ds_info *
dp,
153 #ifdef CONFIG_HOTPLUG_CPU
154 static void dr_cpu_data(
struct ds_info *
dp,
158 static void ds_pri_data(
struct ds_info *
dp,
161 static void ds_var_data(
struct ds_info *
dp,
167 .service_id =
"md-update",
168 .data = md_update_data,
171 .service_id =
"domain-shutdown",
172 .data = domain_shutdown_data,
175 .service_id =
"domain-panic",
176 .data = domain_panic_data,
178 #ifdef CONFIG_HOTPLUG_CPU
180 .service_id =
"dr-cpu",
189 .service_id =
"var-config",
193 .service_id =
"var-config-backup",
203 #define DS_HS_START 0x01
204 #define DS_HS_DONE 0x02
217 static struct ds_info *ds_info_list;
221 unsigned int index = handle >> 32;
247 while (limit-- > 0) {
249 if (!err || (err != -
EAGAIN))
257 static int ds_send(
struct ldc_channel *lp,
void *data,
int len)
263 err = __ds_send(lp, data, len);
264 spin_unlock_irqrestore(&ds_lock, flags);
278 static void md_update_data(
struct ds_info *dp,
296 memset(&pkt, 0,
sizeof(pkt));
298 pkt.data.tag.len =
sizeof(pkt) -
sizeof(
struct ds_msg_tag);
299 pkt.data.handle = cp->
handle;
301 pkt.res.result =
DS_OK;
303 ds_send(lp, &pkt,
sizeof(pkt));
317 static void domain_shutdown_data(
struct ds_info *dp,
332 "LDOM manager received.\n", dp->
id);
334 memset(&pkt, 0,
sizeof(pkt));
336 pkt.data.tag.len =
sizeof(pkt) -
sizeof(
struct ds_msg_tag);
337 pkt.data.handle = cp->
handle;
339 pkt.res.result =
DS_OK;
340 pkt.res.reason[0] = 0;
342 ds_send(lp, &pkt,
sizeof(pkt));
357 static void domain_panic_data(
struct ds_info *dp,
372 "LDOM manager received.\n", dp->
id);
374 memset(&pkt, 0,
sizeof(pkt));
376 pkt.data.tag.len =
sizeof(pkt) -
sizeof(
struct ds_msg_tag);
377 pkt.data.handle = cp->
handle;
379 pkt.res.result =
DS_OK;
380 pkt.res.reason[0] = 0;
382 ds_send(lp, &pkt,
sizeof(pkt));
384 panic(
"PANIC requested by LDOM manager.");
387 #ifdef CONFIG_HOTPLUG_CPU
391 #define DR_CPU_CONFIGURE 0x43
392 #define DR_CPU_UNCONFIGURE 0x55
393 #define DR_CPU_FORCE_UNCONFIGURE 0x46
394 #define DR_CPU_STATUS 0x53
397 #define DR_CPU_OK 0x6f
398 #define DR_CPU_ERROR 0x65
403 struct dr_cpu_resp_entry {
406 #define DR_CPU_RES_OK 0x00
407 #define DR_CPU_RES_FAILURE 0x01
408 #define DR_CPU_RES_BLOCKED 0x02
409 #define DR_CPU_RES_CPU_NOT_RESPONDING 0x03
410 #define DR_CPU_RES_NOT_IN_MD 0x04
413 #define DR_CPU_STAT_NOT_PRESENT 0x00
414 #define DR_CPU_STAT_UNCONFIGURED 0x01
415 #define DR_CPU_STAT_CONFIGURED 0x02
420 static void __dr_cpu_send_error(
struct ds_info *dp,
424 struct dr_cpu_tag *
tag = (
struct dr_cpu_tag *) (data + 1);
427 struct dr_cpu_tag tag;
431 memset(&pkt, 0,
sizeof(pkt));
433 pkt.data.handle = cp->
handle;
434 pkt.tag.req_num = tag->req_num;
435 pkt.tag.type = DR_CPU_ERROR;
436 pkt.tag.num_records = 0;
438 msg_len = (
sizeof(
struct ds_data) +
441 pkt.data.tag.len = msg_len -
sizeof(
struct ds_msg_tag);
443 __ds_send(dp->
lp, &pkt, msg_len);
446 static void dr_cpu_send_error(
struct ds_info *dp,
453 __dr_cpu_send_error(dp, cp, data);
454 spin_unlock_irqrestore(&ds_lock, flags);
457 #define CPU_SENTINEL 0xffffffff
459 static void purge_dups(
u32 *
list,
u32 num_ents)
463 for (i = 0; i < num_ents; i++) {
467 if (cpu == CPU_SENTINEL)
470 for (j = i + 1; j < num_ents; j++) {
472 list[
j] = CPU_SENTINEL;
477 static int dr_cpu_size_response(
int ncpus)
479 return (
sizeof(
struct ds_data) +
480 sizeof(
struct dr_cpu_tag) +
481 (
sizeof(
struct dr_cpu_resp_entry) * ncpus));
484 static void dr_cpu_init_response(
struct ds_data *
resp,
u64 req_num,
488 struct dr_cpu_resp_entry *
ent;
489 struct dr_cpu_tag *
tag;
492 tag = (
struct dr_cpu_tag *) (resp + 1);
493 ent = (
struct dr_cpu_resp_entry *) (tag + 1);
498 tag->req_num = req_num;
499 tag->type = DR_CPU_OK;
500 tag->num_records =
ncpus;
505 ent[
i].result = DR_CPU_RES_OK;
506 ent[
i].stat = default_stat;
512 static void dr_cpu_mark(
struct ds_data *resp,
int cpu,
int ncpus,
515 struct dr_cpu_resp_entry *ent;
516 struct dr_cpu_tag *
tag;
519 tag = (
struct dr_cpu_tag *) (resp + 1);
520 ent = (
struct dr_cpu_resp_entry *) (tag + 1);
522 for (i = 0; i <
ncpus; i++) {
523 if (ent[i].cpu != cpu)
540 ncpus = cpumask_weight(mask);
541 resp_len = dr_cpu_size_response(ncpus);
546 dr_cpu_init_response(resp, req_num, cp->
handle,
547 resp_len, ncpus, mask,
548 DR_CPU_STAT_CONFIGURED);
560 __u32 res = DR_CPU_RES_FAILURE;
561 __u32 stat = DR_CPU_STAT_UNCONFIGURED;
565 res = DR_CPU_RES_NOT_IN_MD;
566 stat = DR_CPU_STAT_NOT_PRESENT;
567 }
else if (err == -
ENODEV) {
569 res = DR_CPU_RES_CPU_NOT_RESPONDING;
574 dr_cpu_mark(resp, cpu, ncpus, res, stat);
579 __ds_send(dp->
lp, resp, resp_len);
580 spin_unlock_irqrestore(&ds_lock, flags);
590 static int dr_cpu_unconfigure(
struct ds_info *dp,
599 ncpus = cpumask_weight(mask);
600 resp_len = dr_cpu_size_response(ncpus);
605 dr_cpu_init_response(resp, req_num, cp->
handle,
606 resp_len, ncpus, mask,
607 DR_CPU_STAT_UNCONFIGURED);
616 dr_cpu_mark(resp, cpu, ncpus,
618 DR_CPU_STAT_CONFIGURED);
622 __ds_send(dp->
lp, resp, resp_len);
623 spin_unlock_irqrestore(&ds_lock, flags);
635 struct dr_cpu_tag *tag = (
struct dr_cpu_tag *) (data + 1);
636 u32 *cpu_list = (
u32 *) (tag + 1);
637 u64 req_num = tag->req_num;
643 case DR_CPU_CONFIGURE:
644 case DR_CPU_UNCONFIGURE:
645 case DR_CPU_FORCE_UNCONFIGURE:
649 dr_cpu_send_error(dp, cp, data);
653 purge_dups(cpu_list, tag->num_records);
655 cpumask_clear(&mask);
656 for (i = 0; i < tag->num_records; i++) {
657 if (cpu_list[i] == CPU_SENTINEL)
660 if (cpu_list[i] < nr_cpu_ids)
661 cpumask_set_cpu(cpu_list[i], &mask);
664 if (tag->type == DR_CPU_CONFIGURE)
665 err = dr_cpu_configure(dp, cp, req_num, &mask);
667 err = dr_cpu_unconfigure(dp, cp, req_num, &mask);
670 dr_cpu_send_error(dp, cp, data);
677 #define DS_PRI_REQUEST 0x00
678 #define DS_PRI_DATA 0x01
679 #define DS_PRI_UPDATE 0x02
682 static void ds_pri_data(
struct ds_info *dp,
697 #define DS_VAR_SET_REQ 0x00
698 #define DS_VAR_DELETE_REQ 0x01
699 #define DS_VAR_SET_RESP 0x02
700 #define DS_VAR_DELETE_RESP 0x03
716 #define DS_VAR_SUCCESS 0x00
717 #define DS_VAR_NO_SPACE 0x01
718 #define DS_VAR_INVALID_VAR 0x02
719 #define DS_VAR_INVALID_VAL 0x03
720 #define DS_VAR_NOT_PRESENT 0x04
724 static int ds_var_doorbell;
725 static int ds_var_response;
727 static void ds_var_data(
struct ds_info *dp,
740 ds_var_response = rp->
result;
753 for (dp = ds_info_list;
dp; dp = dp->
next) {
756 tmp = find_cap_by_string(dp,
"var-config");
763 for (dp = ds_info_list;
dp; dp = dp->
next) {
766 tmp = find_cap_by_string(dp,
"var-config-backup");
773 spin_unlock_irqrestore(&ds_lock, flags);
786 memset(&pkt, 0,
sizeof(pkt));
787 pkt.header.data.tag.type =
DS_DATA;
788 pkt.header.data.handle = cp->
handle;
790 base = p = &pkt.header.msg.name_and_value[0];
796 msg_len = (
sizeof(
struct ds_data) +
797 sizeof(struct ds_var_set_msg) +
799 msg_len = (msg_len + 3) & ~3;
800 pkt.header.data.tag.len = msg_len -
sizeof(
struct ds_msg_tag);
806 ds_var_response = -1;
808 __ds_send(dp->
lp, &pkt, msg_len);
809 spin_unlock_irqrestore(&ds_lock, flags);
812 while (ds_var_doorbell == 0) {
821 if (ds_var_doorbell == 0 ||
824 "failed, response(%d).\n",
829 "could not set (%s) variable to (%s).\n",
835 static int reboot_data_supported;
842 if (boot_command &&
strlen(boot_command)) {
845 strcpy(full_boot_str,
"boot ");
847 len =
strlen(full_boot_str);
849 if (reboot_data_supported) {
850 unsigned long ra = kimage_addr_to_ra(full_boot_str);
851 unsigned long hv_ret;
855 pr_err(
"SUN4V: Unable to set reboot data "
856 "hv_ret=%lu\n", hv_ret);
869 static void ds_conn_reset(
struct ds_info *dp)
872 dp->
id, __builtin_return_address(0));
875 static int register_services(
struct ds_info *dp)
893 cp->
handle = ((
u64) i << 32) | new_count;
898 memset(&pbuf, 0,
sizeof(pbuf));
900 pbuf.req.tag.len = (msg_len -
sizeof(
struct ds_msg_tag));
901 pbuf.req.handle = cp->
handle;
906 err = __ds_send(lp, &pbuf, msg_len);
922 return register_services(dp);
934 "handle %llx\n", dp->
id, ap->
handle);
946 "unknown handle %llx\n",
960 static void __send_ds_nack(
struct ds_info *dp,
u64 handle)
972 __ds_send(dp->
lp, &nack,
sizeof(nack));
986 static void process_ds_work(
void)
993 list_splice_init(&ds_work_list, &
todo);
994 spin_unlock_irqrestore(&ds_lock, flags);
1008 __send_ds_nack(dp, dpkt->
handle);
1009 spin_unlock_irqrestore(&ds_lock, flags);
1011 cp->
data(dp, cp, dpkt, req_len);
1019 static int ds_thread(
void *
__unused)
1025 if (list_empty(&ds_work_list))
1045 __send_ds_nack(dp, dpkt->
handle);
1055 static void ds_up(
struct ds_info *dp)
1066 err = __ds_send(lp, &
req,
sizeof(
req));
1071 static void ds_reset(
struct ds_info *dp)
1084 static void ds_event(
void *
arg,
int event)
1088 unsigned long flags;
1095 spin_unlock_irqrestore(&ds_lock, flags);
1101 spin_unlock_irqrestore(&ds_lock, flags);
1108 spin_unlock_irqrestore(&ds_lock, flags);
1138 err = ds_handshake(dp, dp->
rcv_buf);
1141 sizeof(*tag) + err);
1146 spin_unlock_irqrestore(&ds_lock, flags);
1152 static int ds_version_printed;
1164 if (ds_version_printed++ == 0)
1187 goto out_free_rcv_buf;
1200 goto out_free_ds_states;
1208 spin_lock_irq(&ds_lock);
1209 dp->
next = ds_info_list;
1211 spin_unlock_irq(&ds_lock);
1231 static int ds_remove(
struct vio_dev *vdev)
1238 .type =
"domain-services-port",
1244 .id_table = ds_match,
1246 .remove = ds_remove,
1250 static int __init ds_init(
void)
1257 pr_info(
"SUN4V: Reboot data supported (maj=%lu,min=%lu).\n",
1259 reboot_data_supported = 1;