- more 2.6.17 port work (still does not build)
[linux-flexiantxendom0-3.2.10.git] / drivers / dump / dump_methods.h
1 /*
2  * Generic interfaces for flexible system dump
3  *
4  * Started: Oct 2002 -  Suparna Bhattacharya (suparna@in.ibm.com)
5  *
6  * Copyright (C) 2002 International Business Machines Corp.
7  *
8  * This code is released under version 2 of the GNU GPL.
9  */
10
11 #ifndef _LINUX_DUMP_METHODS_H
12 #define _LINUX_DUMP_METHODS_H
13
14 /*
15  * Inspired by Matt Robinson's suggestion of introducing dump
16  * methods as a way to enable different crash dump facilities to
17  * coexist where each employs its own scheme or dumping policy.
18  *
19  * The code here creates a framework for flexible dump by defining
20  * a set of methods and providing associated helpers that differentiate
21  * between the underlying mechanism (how to dump), overall scheme
22  * (sequencing of stages and data dumped and associated quiescing),
23  * output format (what the dump output looks like), target type
24  * (where to save the dump; see dumpdev.h), and selection policy
25  * (state/data to dump).
26  *
27  * These sets of interfaces can be mixed and matched to build a
28  * dumper suitable for a given situation, allowing for
29  * flexibility as well appropriate degree of code reuse.
30  * For example all features and options of lkcd (including
31  * granular selective dumping in the near future) should be
32  * available even when say, the 2 stage soft-boot based mechanism
33  * is used for taking disruptive dumps.
34  *
35  * Todo: Additionally modules or drivers may supply their own
36  * custom dumpers which extend dump with module specific
37  * information or hardware state, and can even tweak the
38  * mechanism when it comes to saving state relevant to
39  * them.
40  */
41
42 #include <linux/sched.h>
43 #include <linux/slab.h>
44 #include <linux/highmem.h>
45 #include <linux/dumpdev.h>
46 #include <asm/page.h>   /* get_order */
47
48 #define MAX_PASSES      6
49 #define MAX_DEVS        4
50 #define MAX_MBANKS_PER_NODE     8
51 #define MAX_MBANKS      (MAX_NUMNODES * MAX_MBANKS_PER_NODE)
52
53
54 /* To customise selection of pages to be dumped in a given pass/group */
55 struct dump_data_filter{
56         char name[32];
57         int (*selector)(int, unsigned long, unsigned long);
58         ulong level_mask; /* dump level(s) for which this filter applies */
59         loff_t start[MAX_MBANKS], end[MAX_MBANKS]; /* location range applicable */
60         ulong num_mbanks;  /* Number of memory banks. Greater than one for discontig memory (NUMA) */
61 };
62
63
64 /*
65  * Determined by the kind of dump mechanism and appropriate
66  * overall scheme
67  */
68 struct dump_scheme_ops {
69         /* sets aside memory, inits data structures etc */
70         int (*configure)(const char *devid);
71         /* releases  resources */
72         int (*unconfigure)(void);
73
74         /* ordering of passes, invoking iterator */
75         int (*sequencer)(void);
76         /* iterates over system data, selects and acts on data to dump */
77         int (*iterator)(int, int (*)(unsigned long, unsigned long),
78                 struct dump_data_filter *);
79         /* action when data is selected for dump */
80         int (*save_data)(unsigned long, unsigned long);
81         /* action when data is to be excluded from dump */
82         int (*skip_data)(unsigned long, unsigned long);
83         /* policies for space, multiple dump devices etc */
84         int (*write_buffer)(void *, unsigned long);
85 };
86
87 struct dump_scheme {
88         /* the name serves as an anchor to locate the scheme after reboot */
89         char name[32];
90         struct dump_scheme_ops *ops;
91         struct list_head list;
92 };
93
94 /* Quiescing/Silence levels (controls IPI callback behaviour) */
95 extern enum dump_silence_levels {
96         DUMP_SOFT_SPIN_CPUS     = 1,
97         DUMP_HARD_SPIN_CPUS     = 2,
98         DUMP_HALT_CPUS          = 3,
99 } dump_silence_level;
100
101 /* determined by the dump (file) format */
102 struct dump_fmt_ops {
103         /* build header */
104         int (*configure_header)(const char *, const struct pt_regs *);
105         int (*update_header)(void); /* update header and write it out */
106         /* save curr context  */
107         void (*save_context)(int, const struct pt_regs *,
108                 struct task_struct *);
109         /* typically called by the save_data action */
110         /* add formatted data to the dump buffer */
111         int (*add_data)(unsigned long, unsigned long);
112         int (*update_end_marker)(void);
113 };
114
115 struct dump_fmt {
116         unsigned long magic;
117         char name[32];  /* lcrash, crash, elf-core etc */
118         struct dump_fmt_ops *ops;
119         struct list_head list;
120 };
121
122 /*
123  * Modules will be able add their own data capture schemes by
124  * registering their own dumpers. Typically they would use the
125  * primary dumper as a template and tune it with their routines.
126  * Still Todo.
127  */
128
129 /* The combined dumper profile (mechanism, scheme, dev, fmt) */
130 struct dumper {
131         char name[32]; /* singlestage, overlay (stg1), passthru(stg2), pull */
132         struct dump_scheme *scheme;
133         struct dump_fmt *fmt;
134         struct __dump_compress *compress;
135         struct dump_data_filter *filter;
136         struct dump_dev *dev;
137         /* state valid only for active dumper(s) - per instance */
138         /* run time state/context */
139         int curr_pass;
140         unsigned long count;
141         loff_t curr_offset; /* current logical offset into dump device */
142         loff_t curr_loc; /* current memory location */
143         void *curr_buf; /* current position in the dump buffer */
144         void *dump_buf; /* starting addr of dump buffer */
145         int header_dirty; /* whether the header needs to be written out */
146         int header_len;
147         struct list_head dumper_list; /* links to other dumpers */
148 };
149
150 /* Starting point to get to the current configured state */
151 struct dump_config {
152         ulong level;
153         int polling;
154         int reboot;
155         int comp_flag;
156         int comp_val;
157         struct dumper *dumper;
158         char *dump_device;
159         unsigned long dump_addr; /* relevant only for in-memory dumps */
160         struct list_head dump_dev_list;
161 };
162
163 extern struct dump_config dump_config;
164
165 /* Wrappers that invoke the methods for the current (active) dumper */
166
167 /* Scheme operations */
168
169 static inline int dump_sequencer(void)
170 {
171         return dump_config.dumper->scheme->ops->sequencer();
172 }
173
174 static inline int dump_iterator(int pass, int (*action)(unsigned long,
175         unsigned long), struct dump_data_filter *filter)
176 {
177         return dump_config.dumper->scheme->ops->iterator(pass, action, filter);
178 }
179
180 #define dump_save_data dump_config.dumper->scheme->ops->save_data
181 #define dump_skip_data dump_config.dumper->scheme->ops->skip_data
182
183 static inline int dump_write_buffer(void *buf, unsigned long len)
184 {
185         return dump_config.dumper->scheme->ops->write_buffer(buf, len);
186 }
187
188 static inline int dump_configure(const char *devid)
189 {
190         return dump_config.dumper->scheme->ops->configure(devid);
191 }
192
193 static inline int dump_unconfigure(void)
194 {
195         return dump_config.dumper->scheme->ops->unconfigure();
196 }
197
198 /* Format operations */
199
200 static inline int dump_configure_header(const char *panic_str,
201         const struct pt_regs *regs)
202 {
203         return dump_config.dumper->fmt->ops->configure_header(panic_str, regs);
204 }
205
206 static inline void dump_save_context(int cpu, const struct pt_regs *regs,
207                 struct task_struct *tsk)
208 {
209         dump_config.dumper->fmt->ops->save_context(cpu, regs, tsk);
210 }
211
212 static inline int dump_save_this_cpu(const struct pt_regs *regs)
213 {
214         int cpu = smp_processor_id();
215
216         dump_save_context(cpu, regs, current);
217         return 1;
218 }
219
220 static inline int dump_update_header(void)
221 {
222         return dump_config.dumper->fmt->ops->update_header();
223 }
224
225 static inline int dump_update_end_marker(void)
226 {
227         return dump_config.dumper->fmt->ops->update_end_marker();
228 }
229
230 static inline int dump_add_data(unsigned long loc, unsigned long sz)
231 {
232         return dump_config.dumper->fmt->ops->add_data(loc, sz);
233 }
234
235 /* Compression operation */
236 static inline int dump_compress_data(char *src, int slen, char *dst,
237                 unsigned long loc)
238 {
239         return dump_config.dumper->compress->compress_func(src, slen,
240                 dst, DUMP_DPC_PAGE_SIZE, loc);
241 }
242
243
244 /* Prototypes of some default implementations of dump methods */
245
246 extern struct __dump_compress dump_none_compression;
247
248 /* Default scheme methods (dump_scheme.c) */
249
250 extern int dump_generic_sequencer(void);
251 extern int dump_page_iterator(int pass, int (*action)(unsigned long, unsigned
252         long), struct dump_data_filter *filter);
253 extern int dump_generic_save_data(unsigned long loc, unsigned long sz);
254 extern int dump_generic_skip_data(unsigned long loc, unsigned long sz);
255 extern int dump_generic_write_buffer(void *buf, unsigned long len);
256 extern int dump_generic_configure(const char *);
257 extern int dump_generic_unconfigure(void);
258 #ifdef CONFIG_DISCONTIGMEM
259 extern void dump_reconfigure_mbanks(void);
260 #endif
261
262 /* Default scheme template */
263 extern struct dump_scheme dump_scheme_singlestage;
264
265 /* Default dump format methods */
266
267 extern int dump_lcrash_configure_header(const char *panic_str,
268         const struct pt_regs *regs);
269 extern void dump_lcrash_save_context(int  cpu, const struct pt_regs *regs,
270         struct task_struct *tsk);
271 extern int dump_generic_update_header(void);
272 extern int dump_lcrash_add_data(unsigned long loc, unsigned long sz);
273 extern int dump_lcrash_update_end_marker(void);
274
275 /* Default format (lcrash) template */
276 extern struct dump_fmt dump_fmt_lcrash;
277
278 /* Default dump selection filter table */
279
280 /*
281  * Entries listed in order of importance and correspond to passes
282  * The last entry (with a level_mask of zero) typically reflects data that
283  * won't be dumped  -- this may for example be used to identify data
284  * that will be skipped for certain so the corresponding memory areas can be
285  * utilized as scratch space.
286  */
287 extern struct dump_data_filter dump_filter_table[];
288
289 /* Some pre-defined dumpers */
290 extern struct dumper dumper_singlestage;
291 extern struct dumper dumper_stage1;
292 extern struct dumper dumper_stage2;
293
294 /* These are temporary */
295 #define DUMP_MASK_HEADER        DUMP_LEVEL_HEADER
296 #define DUMP_MASK_KERN          DUMP_LEVEL_KERN
297 #define DUMP_MASK_USED          DUMP_LEVEL_USED
298 #define DUMP_MASK_UNUSED        DUMP_LEVEL_ALL_RAM
299 #define DUMP_MASK_REST          0 /* dummy for now */
300
301 /* Helpers - move these to dump.h later ? */
302
303 int dump_generic_execute(const char *panic_str, const struct pt_regs *regs);
304 extern int dump_ll_write(void *buf, unsigned long len);
305
306 static inline void dumper_reset(void)
307 {
308         dump_config.dumper->curr_buf = dump_config.dumper->dump_buf;
309         dump_config.dumper->curr_loc = 0;
310         dump_config.dumper->curr_offset = 0;
311         dump_config.dumper->count = 0;
312         dump_config.dumper->curr_pass = 0;
313 }
314
315 /*
316  * May later be moulded to perform boot-time allocations so we can dump
317  * earlier during bootup
318  */
319 static inline void *dump_alloc_mem(unsigned long size)
320 {
321         return (void *) __get_free_pages(GFP_KERNEL, get_order(size));
322 }
323
324 static inline void dump_free_mem(void *buf)
325 {
326         struct page *page;
327
328         /* ignore reserved pages (e.g. post soft boot stage) */
329         if (buf && (page = virt_to_page(buf))) {
330                 if (PageReserved(page))
331                         return;
332         }
333         /*
334          * Allocated using __get_free_pages().
335          */
336         free_pages((unsigned long)buf,
337                 get_order(DUMP_BUFFER_SIZE + 3 * DUMP_PAGE_SIZE));
338 }
339
340
341 #endif /*  _LINUX_DUMP_METHODS_H */