@@ -143,7 +143,7 @@ int is_fadump_memory_area(u64 addr, unsigned long size)
143143 if (((addr + size ) > d_start ) && (addr <= d_end ))
144144 return 1 ;
145145
146- return (addr <= fw_dump .boot_memory_size );
146+ return (addr <= fw_dump .boot_mem_top );
147147}
148148
149149int should_fadump_crash (void )
@@ -194,7 +194,20 @@ static bool is_fadump_mem_area_contiguous(u64 d_start, u64 d_end)
194194 */
195195bool is_fadump_boot_mem_contiguous (void )
196196{
197- return is_fadump_mem_area_contiguous (0 , fw_dump .boot_memory_size );
197+ unsigned long d_start , d_end ;
198+ bool ret = false;
199+ int i ;
200+
201+ for (i = 0 ; i < fw_dump .boot_mem_regs_cnt ; i ++ ) {
202+ d_start = fw_dump .boot_mem_addr [i ];
203+ d_end = d_start + fw_dump .boot_mem_sz [i ];
204+
205+ ret = is_fadump_mem_area_contiguous (d_start , d_end );
206+ if (!ret )
207+ break ;
208+ }
209+
210+ return ret ;
198211}
199212
200213/*
@@ -213,6 +226,8 @@ bool is_fadump_reserved_mem_contiguous(void)
213226/* Print firmware assisted dump configurations for debugging purpose. */
214227static void fadump_show_config (void )
215228{
229+ int i ;
230+
216231 pr_debug ("Support for firmware-assisted dump (fadump): %s\n" ,
217232 (fw_dump .fadump_supported ? "present" : "no support" ));
218233
@@ -226,7 +241,13 @@ static void fadump_show_config(void)
226241 pr_debug ("Dump section sizes:\n" );
227242 pr_debug (" CPU state data size: %lx\n" , fw_dump .cpu_state_data_size );
228243 pr_debug (" HPTE region size : %lx\n" , fw_dump .hpte_region_size );
229- pr_debug ("Boot memory size : %lx\n" , fw_dump .boot_memory_size );
244+ pr_debug (" Boot memory size : %lx\n" , fw_dump .boot_memory_size );
245+ pr_debug (" Boot memory top : %llx\n" , fw_dump .boot_mem_top );
246+ pr_debug ("Boot memory regions cnt: %llx\n" , fw_dump .boot_mem_regs_cnt );
247+ for (i = 0 ; i < fw_dump .boot_mem_regs_cnt ; i ++ ) {
248+ pr_debug ("[%03d] base = %llx, size = %llx\n" , i ,
249+ fw_dump .boot_mem_addr [i ], fw_dump .boot_mem_sz [i ]);
250+ }
230251}
231252
232253/**
@@ -326,6 +347,88 @@ static unsigned long get_fadump_area_size(void)
326347 return size ;
327348}
328349
350+ static int __init add_boot_mem_region (unsigned long rstart ,
351+ unsigned long rsize )
352+ {
353+ int i = fw_dump .boot_mem_regs_cnt ++ ;
354+
355+ if (fw_dump .boot_mem_regs_cnt > FADUMP_MAX_MEM_REGS ) {
356+ fw_dump .boot_mem_regs_cnt = FADUMP_MAX_MEM_REGS ;
357+ return 0 ;
358+ }
359+
360+ pr_debug ("Added boot memory range[%d] [%#016lx-%#016lx)\n" ,
361+ i , rstart , (rstart + rsize ));
362+ fw_dump .boot_mem_addr [i ] = rstart ;
363+ fw_dump .boot_mem_sz [i ] = rsize ;
364+ return 1 ;
365+ }
366+
367+ /*
368+ * Firmware usually has a hard limit on the data it can copy per region.
369+ * Honour that by splitting a memory range into multiple regions.
370+ */
371+ static int __init add_boot_mem_regions (unsigned long mstart ,
372+ unsigned long msize )
373+ {
374+ unsigned long rstart , rsize , max_size ;
375+ int ret = 1 ;
376+
377+ rstart = mstart ;
378+ max_size = fw_dump .max_copy_size ? fw_dump .max_copy_size : msize ;
379+ while (msize ) {
380+ if (msize > max_size )
381+ rsize = max_size ;
382+ else
383+ rsize = msize ;
384+
385+ ret = add_boot_mem_region (rstart , rsize );
386+ if (!ret )
387+ break ;
388+
389+ msize -= rsize ;
390+ rstart += rsize ;
391+ }
392+
393+ return ret ;
394+ }
395+
396+ static int __init fadump_get_boot_mem_regions (void )
397+ {
398+ unsigned long base , size , cur_size , hole_size , last_end ;
399+ unsigned long mem_size = fw_dump .boot_memory_size ;
400+ struct memblock_region * reg ;
401+ int ret = 1 ;
402+
403+ fw_dump .boot_mem_regs_cnt = 0 ;
404+
405+ last_end = 0 ;
406+ hole_size = 0 ;
407+ cur_size = 0 ;
408+ for_each_memblock (memory , reg ) {
409+ base = reg -> base ;
410+ size = reg -> size ;
411+ hole_size += (base - last_end );
412+
413+ if ((cur_size + size ) >= mem_size ) {
414+ size = (mem_size - cur_size );
415+ ret = add_boot_mem_regions (base , size );
416+ break ;
417+ }
418+
419+ mem_size -= size ;
420+ cur_size += size ;
421+ ret = add_boot_mem_regions (base , size );
422+ if (!ret )
423+ break ;
424+
425+ last_end = base + size ;
426+ }
427+ fw_dump .boot_mem_top = PAGE_ALIGN (fw_dump .boot_memory_size + hole_size );
428+
429+ return ret ;
430+ }
431+
329432int __init fadump_reserve_mem (void )
330433{
331434 u64 base , size , mem_boundary , bootmem_min , align = PAGE_SIZE ;
@@ -362,6 +465,11 @@ int __init fadump_reserve_mem(void)
362465 fw_dump .boot_memory_size , bootmem_min );
363466 goto error_out ;
364467 }
468+
469+ if (!fadump_get_boot_mem_regions ()) {
470+ pr_err ("Too many holes in boot memory area to enable fadump\n" );
471+ goto error_out ;
472+ }
365473 }
366474
367475 /*
@@ -385,7 +493,7 @@ int __init fadump_reserve_mem(void)
385493 else
386494 mem_boundary = memblock_end_of_DRAM ();
387495
388- base = fw_dump .boot_memory_size ;
496+ base = fw_dump .boot_mem_top ;
389497 size = get_fadump_area_size ();
390498 fw_dump .reserve_dump_area_size = size ;
391499 if (fw_dump .dump_active ) {
@@ -769,34 +877,35 @@ static int fadump_setup_crash_memory_ranges(void)
769877{
770878 struct memblock_region * reg ;
771879 u64 start , end ;
772- int ret ;
880+ int i , ret ;
773881
774882 pr_debug ("Setup crash memory ranges.\n" );
775883 crash_mrange_info .mem_range_cnt = 0 ;
776884
777885 /*
778- * add the first memory chunk (0 through boot_memory_size) as
779- * a separate memory chunk. The reason is, at the time crash firmware
780- * will move the content of this memory chunk to different location
781- * specified during fadump registration. We need to create a separate
782- * program header for this chunk with the correct offset.
886+ * Boot memory region(s) registered with firmware are moved to
887+ * different location at the time of crash. Create separate program
888+ * header(s) for this memory chunk(s) with the correct offset.
783889 */
784- ret = fadump_add_mem_range (& crash_mrange_info ,
785- 0 , fw_dump .boot_memory_size );
786- if (ret )
787- return ret ;
890+ for (i = 0 ; i < fw_dump .boot_mem_regs_cnt ; i ++ ) {
891+ start = fw_dump .boot_mem_addr [i ];
892+ end = start + fw_dump .boot_mem_sz [i ];
893+ ret = fadump_add_mem_range (& crash_mrange_info , start , end );
894+ if (ret )
895+ return ret ;
896+ }
788897
789898 for_each_memblock (memory , reg ) {
790899 start = (u64 )reg -> base ;
791900 end = start + (u64 )reg -> size ;
792901
793902 /*
794- * skip the first memory chunk that is already added
795- * (0 through boot_memory_size ).
903+ * skip the memory chunk that is already added
904+ * (0 through boot_memory_top ).
796905 */
797- if (start < fw_dump .boot_memory_size ) {
798- if (end > fw_dump .boot_memory_size )
799- start = fw_dump .boot_memory_size ;
906+ if (start < fw_dump .boot_mem_top ) {
907+ if (end > fw_dump .boot_mem_top )
908+ start = fw_dump .boot_mem_top ;
800909 else
801910 continue ;
802911 }
@@ -817,17 +926,35 @@ static int fadump_setup_crash_memory_ranges(void)
817926 */
818927static inline unsigned long fadump_relocate (unsigned long paddr )
819928{
820- if ((paddr > 0 ) && (paddr < fw_dump .boot_memory_size ))
821- return fw_dump .boot_mem_dest_addr + paddr ;
822- else
823- return paddr ;
929+ unsigned long raddr , rstart , rend , rlast , hole_size ;
930+ int i ;
931+
932+ hole_size = 0 ;
933+ rlast = 0 ;
934+ raddr = paddr ;
935+ for (i = 0 ; i < fw_dump .boot_mem_regs_cnt ; i ++ ) {
936+ rstart = fw_dump .boot_mem_addr [i ];
937+ rend = rstart + fw_dump .boot_mem_sz [i ];
938+ hole_size += (rstart - rlast );
939+
940+ if (paddr >= rstart && paddr < rend ) {
941+ raddr += fw_dump .boot_mem_dest_addr - hole_size ;
942+ break ;
943+ }
944+
945+ rlast = rend ;
946+ }
947+
948+ pr_debug ("vmcoreinfo: paddr = 0x%lx, raddr = 0x%lx\n" , paddr , raddr );
949+ return raddr ;
824950}
825951
826952static int fadump_create_elfcore_headers (char * bufp )
827953{
828- struct elfhdr * elf ;
954+ unsigned long long raddr , offset ;
829955 struct elf_phdr * phdr ;
830- int i ;
956+ struct elfhdr * elf ;
957+ int i , j ;
831958
832959 fadump_init_elfcore_header (bufp );
833960 elf = (struct elfhdr * )bufp ;
@@ -870,7 +997,9 @@ static int fadump_create_elfcore_headers(char *bufp)
870997 (elf -> e_phnum )++ ;
871998
872999 /* setup PT_LOAD sections. */
873-
1000+ j = 0 ;
1001+ offset = 0 ;
1002+ raddr = fw_dump .boot_mem_addr [0 ];
8741003 for (i = 0 ; i < crash_mrange_info .mem_range_cnt ; i ++ ) {
8751004 u64 mbase , msize ;
8761005
@@ -885,13 +1014,17 @@ static int fadump_create_elfcore_headers(char *bufp)
8851014 phdr -> p_flags = PF_R |PF_W |PF_X ;
8861015 phdr -> p_offset = mbase ;
8871016
888- if (mbase == 0 ) {
1017+ if (mbase == raddr ) {
8891018 /*
8901019 * The entire real memory region will be moved by
8911020 * firmware to the specified destination_address.
8921021 * Hence set the correct offset.
8931022 */
894- phdr -> p_offset = fw_dump .boot_mem_dest_addr ;
1023+ phdr -> p_offset = fw_dump .boot_mem_dest_addr + offset ;
1024+ if (j < (fw_dump .boot_mem_regs_cnt - 1 )) {
1025+ offset += fw_dump .boot_mem_sz [j ];
1026+ raddr = fw_dump .boot_mem_addr [++ j ];
1027+ }
8951028 }
8961029
8971030 phdr -> p_paddr = mbase ;
@@ -1177,7 +1310,7 @@ static void fadump_invalidate_release_mem(void)
11771310 fadump_cleanup ();
11781311 mutex_unlock (& fadump_mutex );
11791312
1180- fadump_release_memory (fw_dump .boot_memory_size , memblock_end_of_DRAM ());
1313+ fadump_release_memory (fw_dump .boot_mem_top , memblock_end_of_DRAM ());
11811314 fadump_free_cpu_notes_buf ();
11821315
11831316 /*
0 commit comments