Blame view

arch/ia64/kernel/efi.c 36.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * Extensible Firmware Interface
   *
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
4
5
   * Based on Extensible Firmware Interface Specification version 0.9
   * April 30, 1999
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
   *
   * Copyright (C) 1999 VA Linux Systems
   * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
   * Copyright (C) 1999-2003 Hewlett-Packard Co.
   *	David Mosberger-Tang <davidm@hpl.hp.com>
   *	Stephane Eranian <eranian@hpl.hp.com>
32e62c636   Bjorn Helgaas   [IA64] rework mem...
12
13
   * (c) Copyright 2006 Hewlett-Packard Development Company, L.P.
   *	Bjorn Helgaas <bjorn.helgaas@hp.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
22
23
   *
   * All EFI Runtime Services are not implemented yet as EFI only
   * supports physical mode addressing on SoftSDV. This is to be fixed
   * in a future version.  --drummond 1999-07-20
   *
   * Implemented EFI runtime services and virtual mode calls.  --davidm
   *
   * Goutham Rao: <goutham.rao@intel.com>
   *	Skip non-WB memory and ignore empty memory ranges.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <linux/module.h>
f4a570997   Horms   [IA64] point save...
25
  #include <linux/bootmem.h>
93a72052b   Olaf Hering   crash_dump: expor...
26
  #include <linux/crash_dump.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/types.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
30
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  #include <linux/time.h>
  #include <linux/efi.h>
a79561134   Zou Nan hai   [IA64] IA64 Kexec...
33
  #include <linux/kexec.h>
ed7ed3651   Mel Gorman   handle kernelcore...
34
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
  
  #include <asm/io.h>
  #include <asm/kregs.h>
  #include <asm/meminit.h>
  #include <asm/pgtable.h>
  #include <asm/processor.h>
  #include <asm/mca.h>
2046b94e7   Fenghua Yu   [IA64] Multiple o...
42
  #include <asm/tlbflush.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
49
50
  
  #define EFI_DEBUG	0
  
  extern efi_status_t efi_call_phys (void *, ...);
  
  struct efi efi;
  EXPORT_SYMBOL(efi);
  static efi_runtime_services_t *runtime;
e088a4ad7   Matthew Wilcox   [IA64] Convert ia...
51
  static u64 mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
  
  #define efi_call_virt(f, args...)	(*(f))(args)
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  #define STUB_GET_TIME(prefix, adjust_arg)				       \
  static efi_status_t							       \
  prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc)			       \
  {									       \
  	struct ia64_fpreg fr[6];					       \
  	efi_time_cap_t *atc = NULL;					       \
  	efi_status_t ret;						       \
  									       \
  	if (tc)								       \
  		atc = adjust_arg(tc);					       \
  	ia64_save_scratch_fpregs(fr);					       \
  	ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time),    \
  				adjust_arg(tm), atc);			       \
  	ia64_load_scratch_fpregs(fr);					       \
  	return ret;							       \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  }
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
70
71
72
73
74
75
76
77
78
79
80
81
  #define STUB_SET_TIME(prefix, adjust_arg)				       \
  static efi_status_t							       \
  prefix##_set_time (efi_time_t *tm)					       \
  {									       \
  	struct ia64_fpreg fr[6];					       \
  	efi_status_t ret;						       \
  									       \
  	ia64_save_scratch_fpregs(fr);					       \
  	ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time),    \
  				adjust_arg(tm));			       \
  	ia64_load_scratch_fpregs(fr);					       \
  	return ret;							       \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  }
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  #define STUB_GET_WAKEUP_TIME(prefix, adjust_arg)			       \
  static efi_status_t							       \
  prefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending,	       \
  			  efi_time_t *tm)				       \
  {									       \
  	struct ia64_fpreg fr[6];					       \
  	efi_status_t ret;						       \
  									       \
  	ia64_save_scratch_fpregs(fr);					       \
  	ret = efi_call_##prefix(					       \
  		(efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time),      \
  		adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm));     \
  	ia64_load_scratch_fpregs(fr);					       \
  	return ret;							       \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  }
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  #define STUB_SET_WAKEUP_TIME(prefix, adjust_arg)			       \
  static efi_status_t							       \
  prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)		       \
  {									       \
  	struct ia64_fpreg fr[6];					       \
  	efi_time_t *atm = NULL;						       \
  	efi_status_t ret;						       \
  									       \
  	if (tm)								       \
  		atm = adjust_arg(tm);					       \
  	ia64_save_scratch_fpregs(fr);					       \
  	ret = efi_call_##prefix(					       \
  		(efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time),      \
  		enabled, atm);						       \
  	ia64_load_scratch_fpregs(fr);					       \
  	return ret;							       \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  }
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  #define STUB_GET_VARIABLE(prefix, adjust_arg)				       \
  static efi_status_t							       \
  prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,      \
  		       unsigned long *data_size, void *data)		       \
  {									       \
  	struct ia64_fpreg fr[6];					       \
  	u32 *aattr = NULL;						       \
  	efi_status_t ret;						       \
  									       \
  	if (attr)							       \
  		aattr = adjust_arg(attr);				       \
  	ia64_save_scratch_fpregs(fr);					       \
  	ret = efi_call_##prefix(					       \
  		(efi_get_variable_t *) __va(runtime->get_variable),	       \
  		adjust_arg(name), adjust_arg(vendor), aattr,		       \
  		adjust_arg(data_size), adjust_arg(data));		       \
  	ia64_load_scratch_fpregs(fr);					       \
  	return ret;							       \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  }
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  #define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg)			       \
  static efi_status_t							       \
  prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name,      \
  			    efi_guid_t *vendor)				       \
  {									       \
  	struct ia64_fpreg fr[6];					       \
  	efi_status_t ret;						       \
  									       \
  	ia64_save_scratch_fpregs(fr);					       \
  	ret = efi_call_##prefix(					       \
  		(efi_get_next_variable_t *) __va(runtime->get_next_variable),  \
  		adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor));  \
  	ia64_load_scratch_fpregs(fr);					       \
  	return ret;							       \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  }
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
149
150
151
  #define STUB_SET_VARIABLE(prefix, adjust_arg)				       \
  static efi_status_t							       \
  prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor,		       \
1eb9a4b8a   Matthew Garrett   efi: Fix argument...
152
  		       u32 attr, unsigned long data_size,		       \
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
153
154
155
156
157
158
159
160
161
162
163
164
  		       void *data)					       \
  {									       \
  	struct ia64_fpreg fr[6];					       \
  	efi_status_t ret;						       \
  									       \
  	ia64_save_scratch_fpregs(fr);					       \
  	ret = efi_call_##prefix(					       \
  		(efi_set_variable_t *) __va(runtime->set_variable),	       \
  		adjust_arg(name), adjust_arg(vendor), attr, data_size,	       \
  		adjust_arg(data));					       \
  	ia64_load_scratch_fpregs(fr);					       \
  	return ret;							       \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  }
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
166
167
168
169
170
171
172
173
174
175
176
177
178
  #define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg)		       \
  static efi_status_t							       \
  prefix##_get_next_high_mono_count (u32 *count)				       \
  {									       \
  	struct ia64_fpreg fr[6];					       \
  	efi_status_t ret;						       \
  									       \
  	ia64_save_scratch_fpregs(fr);					       \
  	ret = efi_call_##prefix((efi_get_next_high_mono_count_t *)	       \
  				__va(runtime->get_next_high_mono_count),       \
  				adjust_arg(count));			       \
  	ia64_load_scratch_fpregs(fr);					       \
  	return ret;							       \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  }
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  #define STUB_RESET_SYSTEM(prefix, adjust_arg)				       \
  static void								       \
  prefix##_reset_system (int reset_type, efi_status_t status,		       \
  		       unsigned long data_size, efi_char16_t *data)	       \
  {									       \
  	struct ia64_fpreg fr[6];					       \
  	efi_char16_t *adata = NULL;					       \
  									       \
  	if (data)							       \
  		adata = adjust_arg(data);				       \
  									       \
  	ia64_save_scratch_fpregs(fr);					       \
  	efi_call_##prefix(						       \
  		(efi_reset_system_t *) __va(runtime->reset_system),	       \
  		reset_type, status, data_size, adata);			       \
  	/* should not return, but just in case... */			       \
  	ia64_load_scratch_fpregs(fr);					       \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  }
  
  #define phys_ptr(arg)	((__typeof__(arg)) ia64_tpa(arg))
  
  STUB_GET_TIME(phys, phys_ptr)
  STUB_SET_TIME(phys, phys_ptr)
  STUB_GET_WAKEUP_TIME(phys, phys_ptr)
  STUB_SET_WAKEUP_TIME(phys, phys_ptr)
  STUB_GET_VARIABLE(phys, phys_ptr)
  STUB_GET_NEXT_VARIABLE(phys, phys_ptr)
  STUB_SET_VARIABLE(phys, phys_ptr)
  STUB_GET_NEXT_HIGH_MONO_COUNT(phys, phys_ptr)
  STUB_RESET_SYSTEM(phys, phys_ptr)
  
  #define id(arg)	arg
  
  STUB_GET_TIME(virt, id)
  STUB_SET_TIME(virt, id)
  STUB_GET_WAKEUP_TIME(virt, id)
  STUB_SET_WAKEUP_TIME(virt, id)
  STUB_GET_VARIABLE(virt, id)
  STUB_GET_NEXT_VARIABLE(virt, id)
  STUB_SET_VARIABLE(virt, id)
  STUB_GET_NEXT_HIGH_MONO_COUNT(virt, id)
  STUB_RESET_SYSTEM(virt, id)
  
  void
  efi_gettimeofday (struct timespec *ts)
  {
  	efi_time_t tm;
4b07ae9b9   Li Zefan   [IA64] Wrong args...
227
228
  	if ((*efi.get_time)(&tm, NULL) != EFI_SUCCESS) {
  		memset(ts, 0, sizeof(*ts));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  		return;
4b07ae9b9   Li Zefan   [IA64] Wrong args...
230
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231

7d9aed26e   Aron Griffis   [IA64] Make efi.c...
232
233
  	ts->tv_sec = mktime(tm.year, tm.month, tm.day,
  			    tm.hour, tm.minute, tm.second);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
237
  	ts->tv_nsec = tm.nanosecond;
  }
  
  static int
66888a6e5   Christoph Lameter   [IA64] resolve na...
238
  is_memory_available (efi_memory_desc_t *md)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  {
  	if (!(md->attribute & EFI_MEMORY_WB))
  		return 0;
  
  	switch (md->type) {
  	      case EFI_LOADER_CODE:
  	      case EFI_LOADER_DATA:
  	      case EFI_BOOT_SERVICES_CODE:
  	      case EFI_BOOT_SERVICES_DATA:
  	      case EFI_CONVENTIONAL_MEMORY:
  		return 1;
  	}
  	return 0;
  }
d8c97d5f3   Tony Luck   [IA64] simplified...
253
254
255
256
257
  typedef struct kern_memdesc {
  	u64 attribute;
  	u64 start;
  	u64 num_pages;
  } kern_memdesc_t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258

d8c97d5f3   Tony Luck   [IA64] simplified...
259
  static kern_memdesc_t *kern_memmap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260

80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  #define efi_md_size(md)	(md->num_pages << EFI_PAGE_SHIFT)
  
  static inline u64
  kmd_end(kern_memdesc_t *kmd)
  {
  	return (kmd->start + (kmd->num_pages << EFI_PAGE_SHIFT));
  }
  
  static inline u64
  efi_md_end(efi_memory_desc_t *md)
  {
  	return (md->phys_addr + efi_md_size(md));
  }
  
  static inline int
  efi_wb(efi_memory_desc_t *md)
  {
  	return (md->attribute & EFI_MEMORY_WB);
  }
  
  static inline int
  efi_uc(efi_memory_desc_t *md)
  {
  	return (md->attribute & EFI_MEMORY_UC);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
  static void
d8c97d5f3   Tony Luck   [IA64] simplified...
287
  walk (efi_freemem_callback_t callback, void *arg, u64 attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  {
d8c97d5f3   Tony Luck   [IA64] simplified...
289
290
  	kern_memdesc_t *k;
  	u64 start, end, voff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291

d8c97d5f3   Tony Luck   [IA64] simplified...
292
293
294
295
296
297
298
299
300
301
  	voff = (attr == EFI_MEMORY_WB) ? PAGE_OFFSET : __IA64_UNCACHED_OFFSET;
  	for (k = kern_memmap; k->start != ~0UL; k++) {
  		if (k->attribute != attr)
  			continue;
  		start = PAGE_ALIGN(k->start);
  		end = (k->start + (k->num_pages << EFI_PAGE_SHIFT)) & PAGE_MASK;
  		if (start < end)
  			if ((*callback)(start + voff, end + voff, arg) < 0)
  				return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
  }
  
  /*
965e7c8af   Aron Griffis   [IA64] efi.c Spel...
305
   * Walk the EFI memory map and call CALLBACK once for each EFI memory
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
306
   * descriptor that has memory that is available for OS use.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
   */
  void
  efi_memmap_walk (efi_freemem_callback_t callback, void *arg)
  {
d8c97d5f3   Tony Luck   [IA64] simplified...
311
  	walk(callback, arg, EFI_MEMORY_WB);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
  }
  
  /*
965e7c8af   Aron Griffis   [IA64] efi.c Spel...
315
   * Walk the EFI memory map and call CALLBACK once for each EFI memory
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
316
   * descriptor that has memory that is available for uncached allocator.
f14f75b81   Jes Sorensen   [PATCH] ia64 unca...
317
   */
d8c97d5f3   Tony Luck   [IA64] simplified...
318
319
  void
  efi_memmap_walk_uc (efi_freemem_callback_t callback, void *arg)
f14f75b81   Jes Sorensen   [PATCH] ia64 unca...
320
  {
d8c97d5f3   Tony Luck   [IA64] simplified...
321
  	walk(callback, arg, EFI_MEMORY_UC);
f14f75b81   Jes Sorensen   [PATCH] ia64 unca...
322
  }
f14f75b81   Jes Sorensen   [PATCH] ia64 unca...
323
  /*
965e7c8af   Aron Griffis   [IA64] efi.c Spel...
324
   * Look for the PAL_CODE region reported by EFI and map it using an
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
327
   * ITR to enable safe PAL calls in virtual mode.  See IA-64 Processor
   * Abstraction Layer chapter 11 in ADAG
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  void *
  efi_get_pal_addr (void)
  {
  	void *efi_map_start, *efi_map_end, *p;
  	efi_memory_desc_t *md;
  	u64 efi_desc_size;
  	int pal_code_count = 0;
  	u64 vaddr, mask;
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
  		md = p;
  		if (md->type != EFI_PAL_CODE)
  			continue;
  
  		if (++pal_code_count > 1) {
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
347
  			printk(KERN_ERR "Too many EFI Pal Code memory ranges, "
e088a4ad7   Matthew Wilcox   [IA64] Convert ia...
348
349
  			       "dropped @ %llx
  ", md->phys_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
  			continue;
  		}
  		/*
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
353
354
  		 * The only ITLB entry in region 7 that is used is the one
  		 * installed by __start().  That entry covers a 64MB range.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
359
  		 */
  		mask  = ~((1 << KERNEL_TR_PAGE_SHIFT) - 1);
  		vaddr = PAGE_OFFSET + md->phys_addr;
  
  		/*
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
360
361
  		 * We must check that the PAL mapping won't overlap with the
  		 * kernel mapping.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  		 *
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
363
364
365
366
367
368
369
370
  		 * PAL code is guaranteed to be aligned on a power of 2 between
  		 * 4k and 256KB and that only one ITR is needed to map it. This
  		 * implies that the PAL code is always aligned on its size,
  		 * i.e., the closest matching page size supported by the TLB.
  		 * Therefore PAL code is guaranteed never to cross a 64MB unless
  		 * it is bigger than 64MB (very unlikely!).  So for now the
  		 * following test is enough to determine whether or not we need
  		 * a dedicated ITR for the PAL code.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
  		 */
  		if ((vaddr & mask) == (KERNEL_START & mask)) {
d4ed80841   Harvey Harrison   [IA64] remove rem...
373
374
375
  			printk(KERN_INFO "%s: no need to install ITR for PAL code
  ",
  			       __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
  			continue;
  		}
685c7f5d3   Li Zefan   [IA64] make full ...
378
  		if (efi_md_size(md) > IA64_GRANULE_SIZE)
965e7c8af   Aron Griffis   [IA64] efi.c Spel...
379
  			panic("Whoa!  PAL code size bigger than a granule!");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
  
  #if EFI_DEBUG
  		mask  = ~((1 << IA64_GRANULE_SHIFT) - 1);
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
383
384
385
386
387
388
  		printk(KERN_INFO "CPU %d: mapping PAL code "
                         "[0x%lx-0x%lx) into [0x%lx-0x%lx)
  ",
                         smp_processor_id(), md->phys_addr,
                         md->phys_addr + efi_md_size(md),
                         vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
  #endif
  		return __va(md->phys_addr);
  	}
9473252f2   Horms   [IA64] add newlin...
392
393
  	printk(KERN_WARNING "%s: no PAL-code memory-descriptor found
  ",
d4ed80841   Harvey Harrison   [IA64] remove rem...
394
  	       __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
  	return NULL;
  }
2046b94e7   Fenghua Yu   [IA64] Multiple o...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  
  static u8 __init palo_checksum(u8 *buffer, u32 length)
  {
  	u8 sum = 0;
  	u8 *end = buffer + length;
  
  	while (buffer < end)
  		sum = (u8) (sum + *(buffer++));
  
  	return sum;
  }
  
  /*
   * Parse and handle PALO table which is published at:
   * http://www.dig64.org/home/DIG64_PALO_R1_0.pdf
   */
  static void __init handle_palo(unsigned long palo_phys)
  {
  	struct palo_table *palo = __va(palo_phys);
  	u8  checksum;
  
  	if (strncmp(palo->signature, PALO_SIG, sizeof(PALO_SIG) - 1)) {
  		printk(KERN_INFO "PALO signature incorrect.
  ");
  		return;
  	}
  
  	checksum = palo_checksum((u8 *)palo, palo->length);
  	if (checksum) {
  		printk(KERN_INFO "PALO checksum incorrect.
  ");
  		return;
  	}
a6c75b86c   Fenghua Yu   [IA64] Kernel par...
430
  	setup_ptcg_sem(palo->max_tlb_purges, NPTCG_FROM_PALO);
2046b94e7   Fenghua Yu   [IA64] Multiple o...
431
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
435
436
437
438
439
440
441
442
443
444
  void
  efi_map_pal_code (void)
  {
  	void *pal_vaddr = efi_get_pal_addr ();
  	u64 psr;
  
  	if (!pal_vaddr)
  		return;
  
  	/*
  	 * Cannot write to CRx with PSR.ic=1
  	 */
  	psr = ia64_clear_ic();
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
445
446
  	ia64_itr(0x1, IA64_TR_PALCODE,
  		 GRANULEROUNDDOWN((unsigned long) pal_vaddr),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
448
  		 pte_val(pfn_pte(__pa(pal_vaddr) >> PAGE_SHIFT, PAGE_KERNEL)),
  		 IA64_GRANULE_SHIFT);
dae17da60   Isaku Yamahata   ia64/pv_ops/binar...
449
  	paravirt_dv_serialize_data();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  	ia64_set_psr(psr);		/* restore psr */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
454
455
456
457
458
459
  }
  
  void __init
  efi_init (void)
  {
  	void *efi_map_start, *efi_map_end;
  	efi_config_table_t *config_tables;
  	efi_char16_t *c16;
  	u64 efi_desc_size;
9d78f43d1   Zou Nan hai   [IA64] Fix wrong ...
460
  	char *cp, vendor[100] = "unknown";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  	int i;
2046b94e7   Fenghua Yu   [IA64] Multiple o...
462
  	unsigned long palo_phys;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463

7d9aed26e   Aron Griffis   [IA64] Make efi.c...
464
  	/*
965e7c8af   Aron Griffis   [IA64] efi.c Spel...
465
  	 * It's too early to be able to use the standard kernel command line
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
466
467
  	 * support...
  	 */
a8d91b847   Alon Bar-Lev   [PATCH] Dynamic k...
468
  	for (cp = boot_command_line; *cp; ) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  		if (memcmp(cp, "mem=", 4) == 0) {
9d78f43d1   Zou Nan hai   [IA64] Fix wrong ...
470
  			mem_limit = memparse(cp + 4, &cp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  		} else if (memcmp(cp, "max_addr=", 9) == 0) {
9d78f43d1   Zou Nan hai   [IA64] Fix wrong ...
472
  			max_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp));
a79561134   Zou Nan hai   [IA64] IA64 Kexec...
473
474
  		} else if (memcmp(cp, "min_addr=", 9) == 0) {
  			min_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
479
480
481
  		} else {
  			while (*cp != ' ' && *cp)
  				++cp;
  			while (*cp == ' ')
  				++cp;
  		}
  	}
a79561134   Zou Nan hai   [IA64] IA64 Kexec...
482
  	if (min_addr != 0UL)
e088a4ad7   Matthew Wilcox   [IA64] Convert ia...
483
484
  		printk(KERN_INFO "Ignoring memory below %lluMB
  ",
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
485
  		       min_addr >> 20);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
  	if (max_addr != ~0UL)
e088a4ad7   Matthew Wilcox   [IA64] Convert ia...
487
488
  		printk(KERN_INFO "Ignoring memory above %lluMB
  ",
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
489
  		       max_addr >> 20);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
493
494
495
496
  
  	efi.systab = __va(ia64_boot_param->efi_systab);
  
  	/*
  	 * Verify the EFI Table
  	 */
  	if (efi.systab == NULL)
965e7c8af   Aron Griffis   [IA64] efi.c Spel...
497
498
  		panic("Whoa! Can't find EFI system table.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
  	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
965e7c8af   Aron Griffis   [IA64] efi.c Spel...
500
501
  		panic("Whoa! EFI system table signature incorrect
  ");
873ec7461   Bjorn Helgaas   EFI: warn only fo...
502
503
504
505
506
507
  	if ((efi.systab->hdr.revision >> 16) == 0)
  		printk(KERN_WARNING "Warning: EFI system table version "
  		       "%d.%02d, expected 1.00 or greater
  ",
  		       efi.systab->hdr.revision >> 16,
  		       efi.systab->hdr.revision & 0xffff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
  
  	config_tables = __va(efi.systab->tables);
  
  	/* Show what we know for posterity */
  	c16 = __va(efi.systab->fw_vendor);
  	if (c16) {
ecdd5dabd   Zou Nan hai   [IA64] Fix a poss...
514
  		for (i = 0;i < (int) sizeof(vendor) - 1 && *c16; ++i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
  			vendor[i] = *c16++;
  		vendor[i] = '\0';
  	}
  
  	printk(KERN_INFO "EFI v%u.%.02u by %s:",
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
520
521
  	       efi.systab->hdr.revision >> 16,
  	       efi.systab->hdr.revision & 0xffff, vendor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522

b2c99e3c7   Bjorn Helgaas   [PATCH] EFI: keep...
523
524
525
526
527
528
529
530
  	efi.mps        = EFI_INVALID_TABLE_ADDR;
  	efi.acpi       = EFI_INVALID_TABLE_ADDR;
  	efi.acpi20     = EFI_INVALID_TABLE_ADDR;
  	efi.smbios     = EFI_INVALID_TABLE_ADDR;
  	efi.sal_systab = EFI_INVALID_TABLE_ADDR;
  	efi.boot_info  = EFI_INVALID_TABLE_ADDR;
  	efi.hcdp       = EFI_INVALID_TABLE_ADDR;
  	efi.uga        = EFI_INVALID_TABLE_ADDR;
2046b94e7   Fenghua Yu   [IA64] Multiple o...
531
  	palo_phys      = EFI_INVALID_TABLE_ADDR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  	for (i = 0; i < (int) efi.systab->nr_tables; i++) {
  		if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
b2c99e3c7   Bjorn Helgaas   [PATCH] EFI: keep...
534
  			efi.mps = config_tables[i].table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
  			printk(" MPS=0x%lx", config_tables[i].table);
  		} else if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) {
b2c99e3c7   Bjorn Helgaas   [PATCH] EFI: keep...
537
  			efi.acpi20 = config_tables[i].table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
  			printk(" ACPI 2.0=0x%lx", config_tables[i].table);
  		} else if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) {
b2c99e3c7   Bjorn Helgaas   [PATCH] EFI: keep...
540
  			efi.acpi = config_tables[i].table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
  			printk(" ACPI=0x%lx", config_tables[i].table);
  		} else if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
b2c99e3c7   Bjorn Helgaas   [PATCH] EFI: keep...
543
  			efi.smbios = config_tables[i].table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
  			printk(" SMBIOS=0x%lx", config_tables[i].table);
  		} else if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) {
b2c99e3c7   Bjorn Helgaas   [PATCH] EFI: keep...
546
  			efi.sal_systab = config_tables[i].table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
  			printk(" SALsystab=0x%lx", config_tables[i].table);
  		} else if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
b2c99e3c7   Bjorn Helgaas   [PATCH] EFI: keep...
549
  			efi.hcdp = config_tables[i].table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  			printk(" HCDP=0x%lx", config_tables[i].table);
2046b94e7   Fenghua Yu   [IA64] Multiple o...
551
552
553
554
  		} else if (efi_guidcmp(config_tables[i].guid,
  			 PROCESSOR_ABSTRACTION_LAYER_OVERWRITE_GUID) == 0) {
  			palo_phys = config_tables[i].table;
  			printk(" PALO=0x%lx", config_tables[i].table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
558
  		}
  	}
  	printk("
  ");
2046b94e7   Fenghua Yu   [IA64] Multiple o...
559
560
  	if (palo_phys != EFI_INVALID_TABLE_ADDR)
  		handle_palo(palo_phys);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  	runtime = __va(efi.systab->runtime);
  	efi.get_time = phys_get_time;
  	efi.set_time = phys_set_time;
  	efi.get_wakeup_time = phys_get_wakeup_time;
  	efi.set_wakeup_time = phys_set_wakeup_time;
  	efi.get_variable = phys_get_variable;
  	efi.get_next_variable = phys_get_next_variable;
  	efi.set_variable = phys_set_variable;
  	efi.get_next_high_mono_count = phys_get_next_high_mono_count;
  	efi.reset_system = phys_reset_system;
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  #if EFI_DEBUG
  	/* print EFI memory map: */
  	{
  		efi_memory_desc_t *md;
  		void *p;
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
581
582
583
  		for (i = 0, p = efi_map_start; p < efi_map_end;
  		     ++i, p += efi_desc_size)
  		{
818c7e866   Simon Horman   [IA64] update efi...
584
585
  			const char *unit;
  			unsigned long size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
  			md = p;
818c7e866   Simon Horman   [IA64] update efi...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  			size = md->num_pages << EFI_PAGE_SHIFT;
  
  			if ((size >> 40) > 0) {
  				size >>= 40;
  				unit = "TB";
  			} else if ((size >> 30) > 0) {
  				size >>= 30;
  				unit = "GB";
  			} else if ((size >> 20) > 0) {
  				size >>= 20;
  				unit = "MB";
  			} else {
  				size >>= 10;
  				unit = "KB";
  			}
  
  			printk("mem%02d: type=%2u, attr=0x%016lx, "
  			       "range=[0x%016lx-0x%016lx) (%4lu%s)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
  			       i, md->type, md->attribute, md->phys_addr,
818c7e866   Simon Horman   [IA64] update efi...
607
  			       md->phys_addr + efi_md_size(md), size, unit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
  		}
  	}
  #endif
  
  	efi_map_pal_code();
  	efi_enter_virtual_mode();
  }
  
  void
  efi_enter_virtual_mode (void)
  {
  	void *efi_map_start, *efi_map_end, *p;
  	efi_memory_desc_t *md;
  	efi_status_t status;
  	u64 efi_desc_size;
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
  		md = p;
  		if (md->attribute & EFI_MEMORY_RUNTIME) {
  			/*
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
632
633
  			 * Some descriptors have multiple bits set, so the
  			 * order of the tests is relevant.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
637
638
639
640
  			 */
  			if (md->attribute & EFI_MEMORY_WB) {
  				md->virt_addr = (u64) __va(md->phys_addr);
  			} else if (md->attribute & EFI_MEMORY_UC) {
  				md->virt_addr = (u64) ioremap(md->phys_addr, 0);
  			} else if (md->attribute & EFI_MEMORY_WC) {
  #if 0
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
641
642
643
644
645
646
647
  				md->virt_addr = ia64_remap(md->phys_addr,
  							   (_PAGE_A |
  							    _PAGE_P |
  							    _PAGE_D |
  							    _PAGE_MA_WC |
  							    _PAGE_PL_0 |
  							    _PAGE_AR_RW));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
652
653
654
  #else
  				printk(KERN_INFO "EFI_MEMORY_WC mapping
  ");
  				md->virt_addr = (u64) ioremap(md->phys_addr, 0);
  #endif
  			} else if (md->attribute & EFI_MEMORY_WT) {
  #if 0
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
655
656
657
658
659
660
661
  				md->virt_addr = ia64_remap(md->phys_addr,
  							   (_PAGE_A |
  							    _PAGE_P |
  							    _PAGE_D |
  							    _PAGE_MA_WT |
  							    _PAGE_PL_0 |
  							    _PAGE_AR_RW));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
665
666
667
668
669
670
671
672
  #else
  				printk(KERN_INFO "EFI_MEMORY_WT mapping
  ");
  				md->virt_addr = (u64) ioremap(md->phys_addr, 0);
  #endif
  			}
  		}
  	}
  
  	status = efi_call_phys(__va(runtime->set_virtual_address_map),
  			       ia64_boot_param->efi_memmap_size,
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
673
674
  			       efi_desc_size,
  			       ia64_boot_param->efi_memdesc_version,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
  			       ia64_boot_param->efi_memmap);
  	if (status != EFI_SUCCESS) {
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
677
678
679
  		printk(KERN_WARNING "warning: unable to switch EFI into "
  		       "virtual mode (status=%lu)
  ", status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
682
683
  		return;
  	}
  
  	/*
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
684
685
  	 * Now that EFI is in virtual mode, we call the EFI functions more
  	 * efficiently:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
690
691
692
693
694
695
696
697
698
  	 */
  	efi.get_time = virt_get_time;
  	efi.set_time = virt_set_time;
  	efi.get_wakeup_time = virt_get_wakeup_time;
  	efi.set_wakeup_time = virt_set_wakeup_time;
  	efi.get_variable = virt_get_variable;
  	efi.get_next_variable = virt_get_next_variable;
  	efi.set_variable = virt_set_variable;
  	efi.get_next_high_mono_count = virt_get_next_high_mono_count;
  	efi.reset_system = virt_reset_system;
  }
  
  /*
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
699
700
   * Walk the EFI memory map looking for the I/O port range.  There can only be
   * one entry of this type, other I/O port ranges should be described via ACPI.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
   */
  u64
  efi_get_iobase (void)
  {
  	void *efi_map_start, *efi_map_end, *p;
  	efi_memory_desc_t *md;
  	u64 efi_desc_size;
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
  		md = p;
  		if (md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) {
  			if (md->attribute & EFI_MEMORY_UC)
  				return md->phys_addr;
  		}
  	}
  	return 0;
  }
32e62c636   Bjorn Helgaas   [IA64] rework mem...
722
723
  static struct kern_memdesc *
  kern_memory_descriptor (unsigned long phys_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
  {
32e62c636   Bjorn Helgaas   [IA64] rework mem...
725
  	struct kern_memdesc *md;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726

32e62c636   Bjorn Helgaas   [IA64] rework mem...
727
728
  	for (md = kern_memmap; md->start != ~0UL; md++) {
  		if (phys_addr - md->start < (md->num_pages << EFI_PAGE_SHIFT))
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
729
  			 return md;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  	}
e037cda55   Keith Owens   [IA64] sparse cle...
731
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
  }
32e62c636   Bjorn Helgaas   [IA64] rework mem...
733
734
  static efi_memory_desc_t *
  efi_memory_descriptor (unsigned long phys_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
738
739
740
741
742
743
744
745
  {
  	void *efi_map_start, *efi_map_end, *p;
  	efi_memory_desc_t *md;
  	u64 efi_desc_size;
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
  		md = p;
685c7f5d3   Li Zefan   [IA64] make full ...
746
  		if (phys_addr - md->phys_addr < efi_md_size(md))
32e62c636   Bjorn Helgaas   [IA64] rework mem...
747
  			 return md;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  	}
e037cda55   Keith Owens   [IA64] sparse cle...
749
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  }
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
751

6d40fc514   Bjorn Helgaas   [IA64] fail mmaps...
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
  static int
  efi_memmap_intersects (unsigned long phys_addr, unsigned long size)
  {
  	void *efi_map_start, *efi_map_end, *p;
  	efi_memory_desc_t *md;
  	u64 efi_desc_size;
  	unsigned long end;
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  	end = phys_addr + size;
  
  	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
  		md = p;
6d40fc514   Bjorn Helgaas   [IA64] fail mmaps...
768
769
770
771
772
  		if (md->phys_addr < end && efi_md_end(md) > phys_addr)
  			return 1;
  	}
  	return 0;
  }
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
  u32
  efi_mem_type (unsigned long phys_addr)
  {
  	efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
  
  	if (md)
  		return md->type;
  	return 0;
  }
  
  u64
  efi_mem_attributes (unsigned long phys_addr)
  {
  	efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
  
  	if (md)
  		return md->attribute;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
  EXPORT_SYMBOL(efi_mem_attributes);
32e62c636   Bjorn Helgaas   [IA64] rework mem...
793
794
  u64
  efi_mem_attribute (unsigned long phys_addr, unsigned long size)
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
795
  {
136939a2b   Bjorn Helgaas   [PATCH] EFI, /dev...
796
  	unsigned long end = phys_addr + size;
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
797
  	efi_memory_desc_t *md = efi_memory_descriptor(phys_addr);
32e62c636   Bjorn Helgaas   [IA64] rework mem...
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
  	u64 attr;
  
  	if (!md)
  		return 0;
  
  	/*
  	 * EFI_MEMORY_RUNTIME is not a memory attribute; it just tells
  	 * the kernel that firmware needs this region mapped.
  	 */
  	attr = md->attribute & ~EFI_MEMORY_RUNTIME;
  	do {
  		unsigned long md_end = efi_md_end(md);
  
  		if (end <= md_end)
  			return attr;
  
  		md = efi_memory_descriptor(md_end);
  		if (!md || (md->attribute & ~EFI_MEMORY_RUNTIME) != attr)
  			return 0;
  	} while (md);
410ab512e   Aron Griffis   [IA64] efi.c Add ...
818
  	return 0;	/* never reached */
32e62c636   Bjorn Helgaas   [IA64] rework mem...
819
820
821
822
823
824
825
826
  }
  
  u64
  kern_mem_attribute (unsigned long phys_addr, unsigned long size)
  {
  	unsigned long end = phys_addr + size;
  	struct kern_memdesc *md;
  	u64 attr;
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
827

136939a2b   Bjorn Helgaas   [PATCH] EFI, /dev...
828
  	/*
32e62c636   Bjorn Helgaas   [IA64] rework mem...
829
830
  	 * This is a hack for ioremap calls before we set up kern_memmap.
  	 * Maybe we should do efi_memmap_init() earlier instead.
136939a2b   Bjorn Helgaas   [PATCH] EFI, /dev...
831
  	 */
32e62c636   Bjorn Helgaas   [IA64] rework mem...
832
833
834
835
  	if (!kern_memmap) {
  		attr = efi_mem_attribute(phys_addr, size);
  		if (attr & EFI_MEMORY_WB)
  			return EFI_MEMORY_WB;
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
836
  		return 0;
136939a2b   Bjorn Helgaas   [PATCH] EFI, /dev...
837
  	}
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
838

32e62c636   Bjorn Helgaas   [IA64] rework mem...
839
840
841
842
843
  	md = kern_memory_descriptor(phys_addr);
  	if (!md)
  		return 0;
  
  	attr = md->attribute;
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
844
  	do {
32e62c636   Bjorn Helgaas   [IA64] rework mem...
845
  		unsigned long md_end = kmd_end(md);
136939a2b   Bjorn Helgaas   [PATCH] EFI, /dev...
846
847
  
  		if (end <= md_end)
32e62c636   Bjorn Helgaas   [IA64] rework mem...
848
  			return attr;
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
849

32e62c636   Bjorn Helgaas   [IA64] rework mem...
850
851
  		md = kern_memory_descriptor(md_end);
  		if (!md || md->attribute != attr)
136939a2b   Bjorn Helgaas   [PATCH] EFI, /dev...
852
  			return 0;
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
853
  	} while (md);
410ab512e   Aron Griffis   [IA64] efi.c Add ...
854
  	return 0;	/* never reached */
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
855
  }
32e62c636   Bjorn Helgaas   [IA64] rework mem...
856
  EXPORT_SYMBOL(kern_mem_attribute);
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
857

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
  int
136939a2b   Bjorn Helgaas   [PATCH] EFI, /dev...
859
  valid_phys_addr_range (unsigned long phys_addr, unsigned long size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
  {
32e62c636   Bjorn Helgaas   [IA64] rework mem...
861
862
863
864
865
866
867
868
869
870
871
872
  	u64 attr;
  
  	/*
  	 * /dev/mem reads and writes use copy_to_user(), which implicitly
  	 * uses a granule-sized kernel identity mapping.  It's really
  	 * only safe to do this for regions in kern_memmap.  For more
  	 * details, see Documentation/ia64/aliasing.txt.
  	 */
  	attr = kern_mem_attribute(phys_addr, size);
  	if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
  		return 1;
  	return 0;
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
873
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874

80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
875
  int
06c67befe   Lennert Buytenhek   [PATCH] make vali...
876
  valid_mmap_phys_addr_range (unsigned long pfn, unsigned long size)
80851ef2a   Bjorn Helgaas   [PATCH] /dev/mem:...
877
  {
6d40fc514   Bjorn Helgaas   [IA64] fail mmaps...
878
879
880
881
  	unsigned long phys_addr = pfn << PAGE_SHIFT;
  	u64 attr;
  
  	attr = efi_mem_attribute(phys_addr, size);
32e62c636   Bjorn Helgaas   [IA64] rework mem...
882
  	/*
6d40fc514   Bjorn Helgaas   [IA64] fail mmaps...
883
884
885
  	 * /dev/mem mmap uses normal user pages, so we don't need the entire
  	 * granule, but the entire region we're mapping must support the same
  	 * attribute.
32e62c636   Bjorn Helgaas   [IA64] rework mem...
886
  	 */
6d40fc514   Bjorn Helgaas   [IA64] fail mmaps...
887
888
889
890
891
892
893
894
895
896
897
  	if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
  		return 1;
  
  	/*
  	 * Intel firmware doesn't tell us about all the MMIO regions, so
  	 * in general we have to allow mmap requests.  But if EFI *does*
  	 * tell us about anything inside this region, we should deny it.
  	 * The user can always map a smaller region to avoid the overlap.
  	 */
  	if (efi_memmap_intersects(phys_addr, size))
  		return 0;
32e62c636   Bjorn Helgaas   [IA64] rework mem...
898
899
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900

32e62c636   Bjorn Helgaas   [IA64] rework mem...
901
902
903
904
905
906
  pgprot_t
  phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size,
  		     pgprot_t vma_prot)
  {
  	unsigned long phys_addr = pfn << PAGE_SHIFT;
  	u64 attr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907

32e62c636   Bjorn Helgaas   [IA64] rework mem...
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
  	/*
  	 * For /dev/mem mmap, we use user mappings, but if the region is
  	 * in kern_memmap (and hence may be covered by a kernel mapping),
  	 * we must use the same attribute as the kernel mapping.
  	 */
  	attr = kern_mem_attribute(phys_addr, size);
  	if (attr & EFI_MEMORY_WB)
  		return pgprot_cacheable(vma_prot);
  	else if (attr & EFI_MEMORY_UC)
  		return pgprot_noncached(vma_prot);
  
  	/*
  	 * Some chipsets don't support UC access to memory.  If
  	 * WB is supported, we prefer that.
  	 */
  	if (efi_mem_attribute(phys_addr, size) & EFI_MEMORY_WB)
  		return pgprot_cacheable(vma_prot);
  
  	return pgprot_noncached(vma_prot);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
  }
  
  int __init
  efi_uart_console_only(void)
  {
  	efi_status_t status;
  	char *s, name[] = "ConOut";
  	efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID;
  	efi_char16_t *utf16, name_utf16[32];
  	unsigned char data[1024];
  	unsigned long size = sizeof(data);
  	struct efi_generic_dev_path *hdr, *end_addr;
  	int uart = 0;
  
  	/* Convert to UTF-16 */
  	utf16 = name_utf16;
  	s = name;
  	while (*s)
  		*utf16++ = *s++ & 0x7f;
  	*utf16 = 0;
  
  	status = efi.get_variable(name_utf16, &guid, NULL, &size, data);
  	if (status != EFI_SUCCESS) {
  		printk(KERN_ERR "No EFI %s variable?
  ", name);
  		return 0;
  	}
  
  	hdr = (struct efi_generic_dev_path *) data;
  	end_addr = (struct efi_generic_dev_path *) ((u8 *) data + size);
  	while (hdr < end_addr) {
  		if (hdr->type == EFI_DEV_MSG &&
  		    hdr->sub_type == EFI_DEV_MSG_UART)
  			uart = 1;
  		else if (hdr->type == EFI_DEV_END_PATH ||
  			  hdr->type == EFI_DEV_END_PATH2) {
  			if (!uart)
  				return 0;
  			if (hdr->sub_type == EFI_DEV_END_ENTIRE)
  				return 1;
  			uart = 0;
  		}
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
969
  		hdr = (struct efi_generic_dev_path *)((u8 *) hdr + hdr->length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
971
972
973
974
  	}
  	printk(KERN_ERR "Malformed %s value
  ", name);
  	return 0;
  }
d8c97d5f3   Tony Luck   [IA64] simplified...
975

d8c97d5f3   Tony Luck   [IA64] simplified...
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
  /*
   * Look for the first granule aligned memory descriptor memory
   * that is big enough to hold EFI memory map. Make sure this
   * descriptor is atleast granule sized so it does not get trimmed
   */
  struct kern_memdesc *
  find_memmap_space (void)
  {
  	u64	contig_low=0, contig_high=0;
  	u64	as = 0, ae;
  	void *efi_map_start, *efi_map_end, *p, *q;
  	efi_memory_desc_t *md, *pmd = NULL, *check_md;
  	u64	space_needed, efi_desc_size;
  	unsigned long total_mem = 0;
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  	/*
  	 * Worst case: we need 3 kernel descriptors for each efi descriptor
  	 * (if every entry has a WB part in the middle, and UC head and tail),
  	 * plus one for the end marker.
  	 */
  	space_needed = sizeof(kern_memdesc_t) *
  		(3 * (ia64_boot_param->efi_memmap_size/efi_desc_size) + 1);
  
  	for (p = efi_map_start; p < efi_map_end; pmd = md, p += efi_desc_size) {
  		md = p;
  		if (!efi_wb(md)) {
  			continue;
  		}
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1008
1009
  		if (pmd == NULL || !efi_wb(pmd) ||
  		    efi_md_end(pmd) != md->phys_addr) {
d8c97d5f3   Tony Luck   [IA64] simplified...
1010
1011
  			contig_low = GRANULEROUNDUP(md->phys_addr);
  			contig_high = efi_md_end(md);
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1012
1013
  			for (q = p + efi_desc_size; q < efi_map_end;
  			     q += efi_desc_size) {
d8c97d5f3   Tony Luck   [IA64] simplified...
1014
1015
1016
1017
1018
1019
1020
1021
1022
  				check_md = q;
  				if (!efi_wb(check_md))
  					break;
  				if (contig_high != check_md->phys_addr)
  					break;
  				contig_high = efi_md_end(check_md);
  			}
  			contig_high = GRANULEROUNDDOWN(contig_high);
  		}
66888a6e5   Christoph Lameter   [IA64] resolve na...
1023
  		if (!is_memory_available(md) || md->type == EFI_LOADER_DATA)
d8c97d5f3   Tony Luck   [IA64] simplified...
1024
1025
1026
1027
1028
  			continue;
  
  		/* Round ends inward to granule boundaries */
  		as = max(contig_low, md->phys_addr);
  		ae = min(contig_high, efi_md_end(md));
a79561134   Zou Nan hai   [IA64] IA64 Kexec...
1029
1030
  		/* keep within max_addr= and min_addr= command line arg */
  		as = max(as, min_addr);
d8c97d5f3   Tony Luck   [IA64] simplified...
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
  		ae = min(ae, max_addr);
  		if (ae <= as)
  			continue;
  
  		/* avoid going over mem= command line arg */
  		if (total_mem + (ae - as) > mem_limit)
  			ae -= total_mem + (ae - as) - mem_limit;
  
  		if (ae <= as)
  			continue;
  
  		if (ae - as > space_needed)
  			break;
  	}
  	if (p >= efi_map_end)
  		panic("Can't allocate space for kernel memory descriptors");
  
  	return __va(as);
  }
  
  /*
   * Walk the EFI memory map and gather all memory available for kernel
   * to use.  We can allocate partial granules only if the unavailable
   * parts exist, and are WB.
   */
cb3808532   Bernhard Walle   Use extended cras...
1056
  unsigned long
e088a4ad7   Matthew Wilcox   [IA64] Convert ia...
1057
  efi_memmap_init(u64 *s, u64 *e)
d8c97d5f3   Tony Luck   [IA64] simplified...
1058
  {
e037cda55   Keith Owens   [IA64] sparse cle...
1059
  	struct kern_memdesc *k, *prev = NULL;
d8c97d5f3   Tony Luck   [IA64] simplified...
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
  	u64	contig_low=0, contig_high=0;
  	u64	as, ae, lim;
  	void *efi_map_start, *efi_map_end, *p, *q;
  	efi_memory_desc_t *md, *pmd = NULL, *check_md;
  	u64	efi_desc_size;
  	unsigned long total_mem = 0;
  
  	k = kern_memmap = find_memmap_space();
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  	for (p = efi_map_start; p < efi_map_end; pmd = md, p += efi_desc_size) {
  		md = p;
  		if (!efi_wb(md)) {
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1076
1077
1078
  			if (efi_uc(md) &&
  			    (md->type == EFI_CONVENTIONAL_MEMORY ||
  			     md->type == EFI_BOOT_SERVICES_DATA)) {
d8c97d5f3   Tony Luck   [IA64] simplified...
1079
1080
1081
1082
1083
1084
1085
  				k->attribute = EFI_MEMORY_UC;
  				k->start = md->phys_addr;
  				k->num_pages = md->num_pages;
  				k++;
  			}
  			continue;
  		}
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1086
1087
  		if (pmd == NULL || !efi_wb(pmd) ||
  		    efi_md_end(pmd) != md->phys_addr) {
d8c97d5f3   Tony Luck   [IA64] simplified...
1088
1089
  			contig_low = GRANULEROUNDUP(md->phys_addr);
  			contig_high = efi_md_end(md);
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1090
1091
  			for (q = p + efi_desc_size; q < efi_map_end;
  			     q += efi_desc_size) {
d8c97d5f3   Tony Luck   [IA64] simplified...
1092
1093
1094
1095
1096
1097
1098
1099
1100
  				check_md = q;
  				if (!efi_wb(check_md))
  					break;
  				if (contig_high != check_md->phys_addr)
  					break;
  				contig_high = efi_md_end(check_md);
  			}
  			contig_high = GRANULEROUNDDOWN(contig_high);
  		}
66888a6e5   Christoph Lameter   [IA64] resolve na...
1101
  		if (!is_memory_available(md))
d8c97d5f3   Tony Luck   [IA64] simplified...
1102
  			continue;
e55fdf11f   Tony Luck   [IA64] Pick highe...
1103
1104
1105
1106
1107
  #ifdef CONFIG_CRASH_DUMP
  		/* saved_max_pfn should ignore max_addr= command line arg */
  		if (saved_max_pfn < (efi_md_end(md) >> PAGE_SHIFT))
  			saved_max_pfn = (efi_md_end(md) >> PAGE_SHIFT);
  #endif
d8c97d5f3   Tony Luck   [IA64] simplified...
1108
1109
1110
1111
1112
1113
1114
  		/*
  		 * Round ends inward to granule boundaries
  		 * Give trimmings to uncached allocator
  		 */
  		if (md->phys_addr < contig_low) {
  			lim = min(efi_md_end(md), contig_low);
  			if (efi_uc(md)) {
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1115
1116
  				if (k > kern_memmap &&
  				    (k-1)->attribute == EFI_MEMORY_UC &&
d8c97d5f3   Tony Luck   [IA64] simplified...
1117
  				    kmd_end(k-1) == md->phys_addr) {
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1118
1119
1120
  					(k-1)->num_pages +=
  						(lim - md->phys_addr)
  						>> EFI_PAGE_SHIFT;
d8c97d5f3   Tony Luck   [IA64] simplified...
1121
1122
1123
  				} else {
  					k->attribute = EFI_MEMORY_UC;
  					k->start = md->phys_addr;
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1124
1125
  					k->num_pages = (lim - md->phys_addr)
  						>> EFI_PAGE_SHIFT;
d8c97d5f3   Tony Luck   [IA64] simplified...
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
  					k++;
  				}
  			}
  			as = contig_low;
  		} else
  			as = md->phys_addr;
  
  		if (efi_md_end(md) > contig_high) {
  			lim = max(md->phys_addr, contig_high);
  			if (efi_uc(md)) {
  				if (lim == md->phys_addr && k > kern_memmap &&
  				    (k-1)->attribute == EFI_MEMORY_UC &&
  				    kmd_end(k-1) == md->phys_addr) {
  					(k-1)->num_pages += md->num_pages;
  				} else {
  					k->attribute = EFI_MEMORY_UC;
  					k->start = lim;
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1143
1144
  					k->num_pages = (efi_md_end(md) - lim)
  						>> EFI_PAGE_SHIFT;
d8c97d5f3   Tony Luck   [IA64] simplified...
1145
1146
1147
1148
1149
1150
  					k++;
  				}
  			}
  			ae = contig_high;
  		} else
  			ae = efi_md_end(md);
a79561134   Zou Nan hai   [IA64] IA64 Kexec...
1151
1152
  		/* keep within max_addr= and min_addr= command line arg */
  		as = max(as, min_addr);
d8c97d5f3   Tony Luck   [IA64] simplified...
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
  		ae = min(ae, max_addr);
  		if (ae <= as)
  			continue;
  
  		/* avoid going over mem= command line arg */
  		if (total_mem + (ae - as) > mem_limit)
  			ae -= total_mem + (ae - as) - mem_limit;
  
  		if (ae <= as)
  			continue;
  		if (prev && kmd_end(prev) == md->phys_addr) {
  			prev->num_pages += (ae - as) >> EFI_PAGE_SHIFT;
  			total_mem += ae - as;
  			continue;
  		}
  		k->attribute = EFI_MEMORY_WB;
  		k->start = as;
  		k->num_pages = (ae - as) >> EFI_PAGE_SHIFT;
  		total_mem += ae - as;
  		prev = k++;
  	}
  	k->start = ~0L; /* end-marker */
  
  	/* reserve the memory we are using for kern_memmap */
  	*s = (u64)kern_memmap;
  	*e = (u64)++k;
cb3808532   Bernhard Walle   Use extended cras...
1179
1180
  
  	return total_mem;
d8c97d5f3   Tony Luck   [IA64] simplified...
1181
  }
be379124c   Khalid Aziz   [IA64] include EF...
1182
1183
1184
  
  void
  efi_initialize_iomem_resources(struct resource *code_resource,
00bf4098b   Bernhard Walle   kexec: add BSS to...
1185
1186
  			       struct resource *data_resource,
  			       struct resource *bss_resource)
be379124c   Khalid Aziz   [IA64] include EF...
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
  {
  	struct resource *res;
  	void *efi_map_start, *efi_map_end, *p;
  	efi_memory_desc_t *md;
  	u64 efi_desc_size;
  	char *name;
  	unsigned long flags;
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  	res = NULL;
  
  	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
  		md = p;
  
  		if (md->num_pages == 0) /* should not happen */
  			continue;
887c3cb18   Yasunori Goto   Add IORESOUCE_BUS...
1206
  		flags = IORESOURCE_MEM | IORESOURCE_BUSY;
be379124c   Khalid Aziz   [IA64] include EF...
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
  		switch (md->type) {
  
  			case EFI_MEMORY_MAPPED_IO:
  			case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
  				continue;
  
  			case EFI_LOADER_CODE:
  			case EFI_LOADER_DATA:
  			case EFI_BOOT_SERVICES_DATA:
  			case EFI_BOOT_SERVICES_CODE:
  			case EFI_CONVENTIONAL_MEMORY:
  				if (md->attribute & EFI_MEMORY_WP) {
  					name = "System ROM";
  					flags |= IORESOURCE_READONLY;
d3758f87f   Jay Lan   [IA64] kexec fail...
1221
1222
1223
  				} else if (md->attribute == EFI_MEMORY_UC)
  					name = "Uncached RAM";
  				else
be379124c   Khalid Aziz   [IA64] include EF...
1224
  					name = "System RAM";
be379124c   Khalid Aziz   [IA64] include EF...
1225
1226
1227
1228
  				break;
  
  			case EFI_ACPI_MEMORY_NVS:
  				name = "ACPI Non-volatile Storage";
be379124c   Khalid Aziz   [IA64] include EF...
1229
1230
1231
1232
  				break;
  
  			case EFI_UNUSABLE_MEMORY:
  				name = "reserved";
887c3cb18   Yasunori Goto   Add IORESOUCE_BUS...
1233
  				flags |= IORESOURCE_DISABLED;
be379124c   Khalid Aziz   [IA64] include EF...
1234
1235
1236
1237
1238
1239
1240
1241
  				break;
  
  			case EFI_RESERVED_TYPE:
  			case EFI_RUNTIME_SERVICES_CODE:
  			case EFI_RUNTIME_SERVICES_DATA:
  			case EFI_ACPI_RECLAIM_MEMORY:
  			default:
  				name = "reserved";
be379124c   Khalid Aziz   [IA64] include EF...
1242
1243
  				break;
  		}
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1244
1245
1246
  		if ((res = kzalloc(sizeof(struct resource),
  				   GFP_KERNEL)) == NULL) {
  			printk(KERN_ERR
965e7c8af   Aron Griffis   [IA64] efi.c Spel...
1247
1248
  			       "failed to allocate resource for iomem
  ");
be379124c   Khalid Aziz   [IA64] include EF...
1249
1250
1251
1252
1253
  			return;
  		}
  
  		res->name = name;
  		res->start = md->phys_addr;
685c7f5d3   Li Zefan   [IA64] make full ...
1254
  		res->end = md->phys_addr + efi_md_size(md) - 1;
be379124c   Khalid Aziz   [IA64] include EF...
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
  		res->flags = flags;
  
  		if (insert_resource(&iomem_resource, res) < 0)
  			kfree(res);
  		else {
  			/*
  			 * We don't know which region contains
  			 * kernel data so we try it repeatedly and
  			 * let the resource manager test it.
  			 */
  			insert_resource(res, code_resource);
  			insert_resource(res, data_resource);
00bf4098b   Bernhard Walle   kexec: add BSS to...
1267
  			insert_resource(res, bss_resource);
a79561134   Zou Nan hai   [IA64] IA64 Kexec...
1268
1269
1270
1271
1272
1273
  #ifdef CONFIG_KEXEC
                          insert_resource(res, &efi_memmap_res);
                          insert_resource(res, &boot_param_res);
  			if (crashk_res.end > crashk_res.start)
  				insert_resource(res, &crashk_res);
  #endif
be379124c   Khalid Aziz   [IA64] include EF...
1274
1275
1276
  		}
  	}
  }
a79561134   Zou Nan hai   [IA64] IA64 Kexec...
1277
1278
1279
1280
1281
  
  #ifdef CONFIG_KEXEC
  /* find a block of memory aligned to 64M exclude reserved regions
     rsvd_regions are sorted
   */
2a3a2827c   Horms   [IA64] put kdump_...
1282
  unsigned long __init
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1283
  kdump_find_rsvd_region (unsigned long size, struct rsvd_region *r, int n)
a79561134   Zou Nan hai   [IA64] IA64 Kexec...
1284
  {
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
  	int i;
  	u64 start, end;
  	u64 alignment = 1UL << _PAGE_SIZE_64M;
  	void *efi_map_start, *efi_map_end, *p;
  	efi_memory_desc_t *md;
  	u64 efi_desc_size;
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
  		md = p;
  		if (!efi_wb(md))
  			continue;
  		start = ALIGN(md->phys_addr, alignment);
  		end = efi_md_end(md);
  		for (i = 0; i < n; i++) {
  			if (__pa(r[i].start) >= start && __pa(r[i].end) < end) {
  				if (__pa(r[i].start) > start + size)
  					return start;
  				start = ALIGN(__pa(r[i].end), alignment);
  				if (i < n-1 &&
  				    __pa(r[i+1].start) < start + size)
  					continue;
  				else
  					break;
  			}
a79561134   Zou Nan hai   [IA64] IA64 Kexec...
1313
  		}
7d9aed26e   Aron Griffis   [IA64] Make efi.c...
1314
1315
1316
1317
1318
1319
1320
1321
  		if (end > start + size)
  			return start;
  	}
  
  	printk(KERN_WARNING
  	       "Cannot reserve 0x%lx byte of memory for crashdump
  ", size);
  	return ~0UL;
a79561134   Zou Nan hai   [IA64] IA64 Kexec...
1322
1323
  }
  #endif
cee87af2a   Magnus Damm   [IA64] kexec: Use...
1324

d9a9855d0   Simon Horman   always reserve el...
1325
  #ifdef CONFIG_CRASH_DUMP
cee87af2a   Magnus Damm   [IA64] kexec: Use...
1326
  /* locate the size find a the descriptor at a certain address */
1775fe851   Simon Horman   [IA64] vmcore_fin...
1327
  unsigned long __init
cee87af2a   Magnus Damm   [IA64] kexec: Use...
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
  vmcore_find_descriptor_size (unsigned long address)
  {
  	void *efi_map_start, *efi_map_end, *p;
  	efi_memory_desc_t *md;
  	u64 efi_desc_size;
  	unsigned long ret = 0;
  
  	efi_map_start = __va(ia64_boot_param->efi_memmap);
  	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
  	efi_desc_size = ia64_boot_param->efi_memdesc_size;
  
  	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
  		md = p;
  		if (efi_wb(md) && md->type == EFI_LOADER_DATA
  		    && md->phys_addr == address) {
  			ret = efi_md_size(md);
  			break;
  		}
  	}
  
  	if (ret == 0)
  		printk(KERN_WARNING "Cannot locate EFI vmcore descriptor
  ");
  
  	return ret;
  }
  #endif