suspend.c 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. #include <linux/init.h>
  2. #include <asm/pgalloc.h>
  3. #include <asm/pgtable.h>
  4. #include <asm/memory.h>
  5. #include <asm/suspend.h>
  6. #include <asm/tlbflush.h>
  7. static pgd_t *suspend_pgd;
  8. extern int __cpu_suspend(int, long, unsigned long, int (*)(unsigned long));
  9. extern void cpu_resume_turn_mmu_on(void);
  10. /*
  11. * Hide the first two arguments to __cpu_suspend - these are an implementation
  12. * detail which platform code shouldn't have to know about.
  13. */
  14. int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
  15. {
  16. struct mm_struct *mm = current->active_mm;
  17. int ret;
  18. if (!suspend_pgd)
  19. return -EINVAL;
  20. /*
  21. * Temporarily switch the page tables to our suspend page
  22. * tables, which contain the temporary identity mapping
  23. * required for resuming.
  24. */
  25. cpu_switch_mm(suspend_pgd, mm);
  26. ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn);
  27. cpu_switch_mm(mm->pgd, mm);
  28. local_flush_tlb_all();
  29. return ret;
  30. }
  31. static int __init cpu_suspend_init(void)
  32. {
  33. suspend_pgd = pgd_alloc(&init_mm);
  34. if (suspend_pgd) {
  35. unsigned long addr = virt_to_phys(cpu_resume_turn_mmu_on);
  36. identity_mapping_add(suspend_pgd, addr, addr + SECTION_SIZE);
  37. }
  38. return suspend_pgd ? 0 : -ENOMEM;
  39. }
  40. core_initcall(cpu_suspend_init);