diff options
author | Manish Ahuja <ahuja@austin.ibm.com> | 2008-03-21 19:43:15 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-03-25 17:44:06 -0400 |
commit | 2c4f41139cc4ffc3ad12d7fdb8dd71dc36824a6e (patch) | |
tree | 4a6dc1b277692e9f8dd644b987a5cd801c288a2d /arch/powerpc/platforms/pseries | |
parent | d5a29c7a36958ddec1ae7ab685ce09a002356548 (diff) |
[POWERPC] pseries: phyp dump: Register dump area
Set up the actual dump header, register it with the hypervisor.
Signed-off-by: Manish Ahuja <mahuja@us.ibm.com>
Signed-off-by: Linas Vepstas <linasvepstas@gmail.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/phyp_dump.c | 137 |
1 files changed, 131 insertions, 6 deletions
diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c index f355f052a56..d93f1b1585a 100644 --- a/arch/powerpc/platforms/pseries/phyp_dump.c +++ b/arch/powerpc/platforms/pseries/phyp_dump.c | |||
@@ -29,6 +29,117 @@ | |||
29 | static struct phyp_dump phyp_dump_vars; | 29 | static struct phyp_dump phyp_dump_vars; |
30 | struct phyp_dump *phyp_dump_info = &phyp_dump_vars; | 30 | struct phyp_dump *phyp_dump_info = &phyp_dump_vars; |
31 | 31 | ||
32 | static int ibm_configure_kernel_dump; | ||
33 | /* ------------------------------------------------- */ | ||
34 | /* RTAS interfaces to declare the dump regions */ | ||
35 | |||
36 | struct dump_section { | ||
37 | u32 dump_flags; | ||
38 | u16 source_type; | ||
39 | u16 error_flags; | ||
40 | u64 source_address; | ||
41 | u64 source_length; | ||
42 | u64 length_copied; | ||
43 | u64 destination_address; | ||
44 | }; | ||
45 | |||
46 | struct phyp_dump_header { | ||
47 | u32 version; | ||
48 | u16 num_of_sections; | ||
49 | u16 status; | ||
50 | |||
51 | u32 first_offset_section; | ||
52 | u32 dump_disk_section; | ||
53 | u64 block_num_dd; | ||
54 | u64 num_of_blocks_dd; | ||
55 | u32 offset_dd; | ||
56 | u32 maxtime_to_auto; | ||
57 | /* No dump disk path string used */ | ||
58 | |||
59 | struct dump_section cpu_data; | ||
60 | struct dump_section hpte_data; | ||
61 | struct dump_section kernel_data; | ||
62 | }; | ||
63 | |||
64 | /* The dump header *must be* in low memory, so .bss it */ | ||
65 | static struct phyp_dump_header phdr; | ||
66 | |||
67 | #define NUM_DUMP_SECTIONS 3 | ||
68 | #define DUMP_HEADER_VERSION 0x1 | ||
69 | #define DUMP_REQUEST_FLAG 0x1 | ||
70 | #define DUMP_SOURCE_CPU 0x0001 | ||
71 | #define DUMP_SOURCE_HPTE 0x0002 | ||
72 | #define DUMP_SOURCE_RMO 0x0011 | ||
73 | |||
74 | /** | ||
75 | * init_dump_header() - initialize the header declaring a dump | ||
76 | * Returns: length of dump save area. | ||
77 | * | ||
78 | * When the hypervisor saves crashed state, it needs to put | ||
79 | * it somewhere. The dump header tells the hypervisor where | ||
80 | * the data can be saved. | ||
81 | */ | ||
82 | static unsigned long init_dump_header(struct phyp_dump_header *ph) | ||
83 | { | ||
84 | unsigned long addr_offset = 0; | ||
85 | |||
86 | /* Set up the dump header */ | ||
87 | ph->version = DUMP_HEADER_VERSION; | ||
88 | ph->num_of_sections = NUM_DUMP_SECTIONS; | ||
89 | ph->status = 0; | ||
90 | |||
91 | ph->first_offset_section = | ||
92 | (u32)offsetof(struct phyp_dump_header, cpu_data); | ||
93 | ph->dump_disk_section = 0; | ||
94 | ph->block_num_dd = 0; | ||
95 | ph->num_of_blocks_dd = 0; | ||
96 | ph->offset_dd = 0; | ||
97 | |||
98 | ph->maxtime_to_auto = 0; /* disabled */ | ||
99 | |||
100 | /* The first two sections are mandatory */ | ||
101 | ph->cpu_data.dump_flags = DUMP_REQUEST_FLAG; | ||
102 | ph->cpu_data.source_type = DUMP_SOURCE_CPU; | ||
103 | ph->cpu_data.source_address = 0; | ||
104 | ph->cpu_data.source_length = phyp_dump_info->cpu_state_size; | ||
105 | ph->cpu_data.destination_address = addr_offset; | ||
106 | addr_offset += phyp_dump_info->cpu_state_size; | ||
107 | |||
108 | ph->hpte_data.dump_flags = DUMP_REQUEST_FLAG; | ||
109 | ph->hpte_data.source_type = DUMP_SOURCE_HPTE; | ||
110 | ph->hpte_data.source_address = 0; | ||
111 | ph->hpte_data.source_length = phyp_dump_info->hpte_region_size; | ||
112 | ph->hpte_data.destination_address = addr_offset; | ||
113 | addr_offset += phyp_dump_info->hpte_region_size; | ||
114 | |||
115 | /* This section describes the low kernel region */ | ||
116 | ph->kernel_data.dump_flags = DUMP_REQUEST_FLAG; | ||
117 | ph->kernel_data.source_type = DUMP_SOURCE_RMO; | ||
118 | ph->kernel_data.source_address = PHYP_DUMP_RMR_START; | ||
119 | ph->kernel_data.source_length = PHYP_DUMP_RMR_END; | ||
120 | ph->kernel_data.destination_address = addr_offset; | ||
121 | addr_offset += ph->kernel_data.source_length; | ||
122 | |||
123 | return addr_offset; | ||
124 | } | ||
125 | |||
126 | static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) | ||
127 | { | ||
128 | int rc; | ||
129 | ph->cpu_data.destination_address += addr; | ||
130 | ph->hpte_data.destination_address += addr; | ||
131 | ph->kernel_data.destination_address += addr; | ||
132 | |||
133 | do { | ||
134 | rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, | ||
135 | 1, ph, sizeof(struct phyp_dump_header)); | ||
136 | } while (rtas_busy_delay(rc)); | ||
137 | |||
138 | if (rc) | ||
139 | printk(KERN_ERR "phyp-dump: unexpected error (%d) on " | ||
140 | "register\n", rc); | ||
141 | } | ||
142 | |||
32 | /* ------------------------------------------------- */ | 143 | /* ------------------------------------------------- */ |
33 | /** | 144 | /** |
34 | * release_memory_range -- release memory previously lmb_reserved | 145 | * release_memory_range -- release memory previously lmb_reserved |
@@ -107,7 +218,9 @@ static struct kobj_attribute rr = __ATTR(release_region, 0600, | |||
107 | static int __init phyp_dump_setup(void) | 218 | static int __init phyp_dump_setup(void) |
108 | { | 219 | { |
109 | struct device_node *rtas; | 220 | struct device_node *rtas; |
110 | const int *dump_header = NULL; | 221 | const struct phyp_dump_header *dump_header = NULL; |
222 | unsigned long dump_area_start; | ||
223 | unsigned long dump_area_length; | ||
111 | int header_len = 0; | 224 | int header_len = 0; |
112 | int rc; | 225 | int rc; |
113 | 226 | ||
@@ -119,7 +232,13 @@ static int __init phyp_dump_setup(void) | |||
119 | if (!phyp_dump_info->phyp_dump_configured) | 232 | if (!phyp_dump_info->phyp_dump_configured) |
120 | return -ENOSYS; | 233 | return -ENOSYS; |
121 | 234 | ||
122 | /* Is there dump data waiting for us? */ | 235 | /* Is there dump data waiting for us? If there isn't, |
236 | * then register a new dump area, and release all of | ||
237 | * the rest of the reserved ram. | ||
238 | * | ||
239 | * The /rtas/ibm,kernel-dump rtas node is present only | ||
240 | * if there is dump data waiting for us. | ||
241 | */ | ||
123 | rtas = of_find_node_by_path("/rtas"); | 242 | rtas = of_find_node_by_path("/rtas"); |
124 | if (rtas) { | 243 | if (rtas) { |
125 | dump_header = of_get_property(rtas, "ibm,kernel-dump", | 244 | dump_header = of_get_property(rtas, "ibm,kernel-dump", |
@@ -127,17 +246,23 @@ static int __init phyp_dump_setup(void) | |||
127 | of_node_put(rtas); | 246 | of_node_put(rtas); |
128 | } | 247 | } |
129 | 248 | ||
130 | if (dump_header == NULL) | 249 | dump_area_length = init_dump_header(&phdr); |
250 | |||
251 | /* align down */ | ||
252 | dump_area_start = phyp_dump_info->init_reserve_start & PAGE_MASK; | ||
253 | |||
254 | if (dump_header == NULL) { | ||
255 | register_dump_area(&phdr, dump_area_start); | ||
131 | return 0; | 256 | return 0; |
257 | } | ||
132 | 258 | ||
133 | /* Should we create a dump_subsys, analogous to s390/ipl.c ? */ | 259 | /* Should we create a dump_subsys, analogous to s390/ipl.c ? */ |
134 | rc = sysfs_create_file(kernel_kobj, &rr.attr); | 260 | rc = sysfs_create_file(kernel_kobj, &rr.attr); |
135 | if (rc) { | 261 | if (rc) |
136 | printk(KERN_ERR "phyp-dump: unable to create sysfs file (%d)\n", | 262 | printk(KERN_ERR "phyp-dump: unable to create sysfs file (%d)\n", |
137 | rc); | 263 | rc); |
138 | return 0; | ||
139 | } | ||
140 | 264 | ||
265 | /* ToDo: re-register the dump area, for next time. */ | ||
141 | return 0; | 266 | return 0; |
142 | } | 267 | } |
143 | machine_subsys_initcall(pseries, phyp_dump_setup); | 268 | machine_subsys_initcall(pseries, phyp_dump_setup); |