pgd.c 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * PGD allocation/freeing
  4. *
  5. * Copyright (C) 2012 ARM Ltd.
  6. * Author: Catalin Marinas <catalin.marinas@arm.com>
  7. */
  8. #include <linux/mm.h>
  9. #include <linux/gfp.h>
  10. #include <linux/highmem.h>
  11. #include <linux/slab.h>
  12. #include <asm/pgalloc.h>
  13. #include <asm/page.h>
  14. #include <asm/tlbflush.h>
  15. static struct kmem_cache *pgd_cache __ro_after_init;
  16. static bool pgdir_is_page_size(void)
  17. {
  18. if (PGD_SIZE == PAGE_SIZE)
  19. return true;
  20. if (CONFIG_PGTABLE_LEVELS == 4)
  21. return !pgtable_l4_enabled();
  22. if (CONFIG_PGTABLE_LEVELS == 5)
  23. return !pgtable_l5_enabled();
  24. return false;
  25. }
  26. pgd_t *pgd_alloc(struct mm_struct *mm)
  27. {
  28. gfp_t gfp = GFP_PGTABLE_USER;
  29. if (pgdir_is_page_size())
  30. return (pgd_t *)__get_free_page(gfp);
  31. else
  32. return kmem_cache_alloc(pgd_cache, gfp);
  33. }
  34. void pgd_free(struct mm_struct *mm, pgd_t *pgd)
  35. {
  36. if (pgdir_is_page_size())
  37. free_page((unsigned long)pgd);
  38. else
  39. kmem_cache_free(pgd_cache, pgd);
  40. }
  41. void __init pgtable_cache_init(void)
  42. {
  43. if (pgdir_is_page_size())
  44. return;
  45. #ifdef CONFIG_ARM64_PA_BITS_52
  46. /*
  47. * With 52-bit physical addresses, the architecture requires the
  48. * top-level table to be aligned to at least 64 bytes.
  49. */
  50. BUILD_BUG_ON(PGD_SIZE < 64);
  51. #endif
  52. /*
  53. * Naturally aligned pgds required by the architecture.
  54. */
  55. pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
  56. SLAB_PANIC, NULL);
  57. }