^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/ftrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/mm_types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/pgtable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <asm/bugs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <asm/idmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/memory.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/smp_plat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/suspend.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/tlbflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) extern int __cpu_suspend(unsigned long, int (*)(unsigned long), u32 cpuid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) extern void cpu_resume_mmu(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #ifdef CONFIG_MMU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct mm_struct *mm = current->active_mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) u32 __mpidr = cpu_logical_map(smp_processor_id());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) if (!idmap_pgd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * Function graph tracer state gets incosistent when the kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * calls functions that never return (aka suspend finishers) hence
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * disable graph tracing during their execution.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) pause_graph_tracing();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * Provide a temporary page table with an identity mapping for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * the MMU-enable code, required for resuming. On successful
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * resume (indicated by a zero return code), we need to switch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * back to the correct page tables.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) ret = __cpu_suspend(arg, fn, __mpidr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unpause_graph_tracing();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) cpu_switch_mm(mm->pgd, mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) local_flush_bp_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) local_flush_tlb_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) check_other_bugs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u32 __mpidr = cpu_logical_map(smp_processor_id());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) pause_graph_tracing();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) ret = __cpu_suspend(arg, fn, __mpidr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unpause_graph_tracing();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define idmap_pgd NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * This is called by __cpu_suspend() to save the state, and do whatever
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * flushing is required to ensure that when the CPU goes to sleep we have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * the necessary data available when the caches are not searched.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) u32 *ctx = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) *save_ptr = virt_to_phys(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* This must correspond to the LDM in cpu_resume() assembly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) *ptr++ = virt_to_phys(idmap_pgd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) *ptr++ = sp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) *ptr++ = virt_to_phys(cpu_do_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) cpu_do_suspend(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) flush_cache_louis();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * flush_cache_louis does not guarantee that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * save_ptr and ptr are cleaned to main memory,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * just up to the Level of Unification Inner Shareable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * Since the context pointer and context itself
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * are to be retrieved with the MMU off that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * data must be cleaned from all cache levels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * to main memory using "area" cache primitives.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) __cpuc_flush_dcache_area(ctx, ptrsz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) __cpuc_flush_dcache_area(save_ptr, sizeof(*save_ptr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) outer_clean_range(*save_ptr, *save_ptr + ptrsz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) outer_clean_range(virt_to_phys(save_ptr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) virt_to_phys(save_ptr) + sizeof(*save_ptr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) extern struct sleep_save_sp sleep_save_sp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static int cpu_suspend_alloc_sp(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) void *ctx_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /* ctx_ptr is an array of physical addresses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) ctx_ptr = kcalloc(mpidr_hash_size(), sizeof(u32), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (WARN_ON(!ctx_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) sleep_save_sp.save_ptr_stash = ctx_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) sleep_save_sp.save_ptr_stash_phys = virt_to_phys(ctx_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) sync_cache_w(&sleep_save_sp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) early_initcall(cpu_suspend_alloc_sp);