amdgpu_gmc.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. * Copyright 2018 Advanced Micro Devices, Inc.
  3. * All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a
  6. * copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sub license, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  16. * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  17. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  18. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  19. * USE OR OTHER DEALINGS IN THE SOFTWARE.
  20. *
  21. * The above copyright notice and this permission notice (including the
  22. * next paragraph) shall be included in all copies or substantial portions
  23. * of the Software.
  24. *
  25. */
  26. #include "amdgpu.h"
  27. /**
  28. * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
  29. *
  30. * @bo: the BO to get the PDE for
  31. * @level: the level in the PD hirarchy
  32. * @addr: resulting addr
  33. * @flags: resulting flags
  34. *
  35. * Get the address and flags to be used for a PDE (Page Directory Entry).
  36. */
  37. void amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level,
  38. uint64_t *addr, uint64_t *flags)
  39. {
  40. struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
  41. struct ttm_dma_tt *ttm;
  42. switch (bo->tbo.mem.mem_type) {
  43. case TTM_PL_TT:
  44. ttm = container_of(bo->tbo.ttm, struct ttm_dma_tt, ttm);
  45. *addr = ttm->dma_address[0];
  46. break;
  47. case TTM_PL_VRAM:
  48. *addr = amdgpu_bo_gpu_offset(bo);
  49. break;
  50. default:
  51. *addr = 0;
  52. break;
  53. }
  54. *flags = amdgpu_ttm_tt_pde_flags(bo->tbo.ttm, &bo->tbo.mem);
  55. amdgpu_gmc_get_vm_pde(adev, level, addr, flags);
  56. }
  57. /**
  58. * amdgpu_gmc_pd_addr - return the address of the root directory
  59. *
  60. */
  61. uint64_t amdgpu_gmc_pd_addr(struct amdgpu_bo *bo)
  62. {
  63. struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
  64. uint64_t pd_addr;
  65. /* TODO: move that into ASIC specific code */
  66. if (adev->asic_type >= CHIP_VEGA10) {
  67. uint64_t flags = AMDGPU_PTE_VALID;
  68. amdgpu_gmc_get_pde_for_bo(bo, -1, &pd_addr, &flags);
  69. pd_addr |= flags;
  70. } else {
  71. pd_addr = amdgpu_bo_gpu_offset(bo);
  72. }
  73. return pd_addr;
  74. }
  75. /**
  76. * amdgpu_gmc_agp_addr - return the address in the AGP address space
  77. *
  78. * @tbo: TTM BO which needs the address, must be in GTT domain
  79. *
  80. * Tries to figure out how to access the BO through the AGP aperture. Returns
  81. * AMDGPU_BO_INVALID_OFFSET if that is not possible.
  82. */
  83. uint64_t amdgpu_gmc_agp_addr(struct ttm_buffer_object *bo)
  84. {
  85. struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
  86. struct ttm_dma_tt *ttm;
  87. if (bo->num_pages != 1 || bo->ttm->caching_state == tt_cached)
  88. return AMDGPU_BO_INVALID_OFFSET;
  89. ttm = container_of(bo->ttm, struct ttm_dma_tt, ttm);
  90. if (ttm->dma_address[0] + PAGE_SIZE >= adev->gmc.agp_size)
  91. return AMDGPU_BO_INVALID_OFFSET;
  92. return adev->gmc.agp_start + ttm->dma_address[0];
  93. }
  94. /**
  95. * amdgpu_gmc_vram_location - try to find VRAM location
  96. *
  97. * @adev: amdgpu device structure holding all necessary informations
  98. * @mc: memory controller structure holding memory informations
  99. * @base: base address at which to put VRAM
  100. *
  101. * Function will try to place VRAM at base address provided
  102. * as parameter.
  103. */
  104. void amdgpu_gmc_vram_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc,
  105. u64 base)
  106. {
  107. uint64_t limit = (uint64_t)amdgpu_vram_limit << 20;
  108. mc->vram_start = base;
  109. mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
  110. if (limit && limit < mc->real_vram_size)
  111. mc->real_vram_size = limit;
  112. if (mc->xgmi.num_physical_nodes == 0) {
  113. mc->fb_start = mc->vram_start;
  114. mc->fb_end = mc->vram_end;
  115. }
  116. dev_info(adev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
  117. mc->mc_vram_size >> 20, mc->vram_start,
  118. mc->vram_end, mc->real_vram_size >> 20);
  119. }
  120. /**
  121. * amdgpu_gmc_gart_location - try to find GART location
  122. *
  123. * @adev: amdgpu device structure holding all necessary informations
  124. * @mc: memory controller structure holding memory informations
  125. *
  126. * Function will place try to place GART before or after VRAM.
  127. *
  128. * If GART size is bigger than space left then we ajust GART size.
  129. * Thus function will never fails.
  130. */
  131. void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc)
  132. {
  133. const uint64_t four_gb = 0x100000000ULL;
  134. u64 size_af, size_bf;
  135. /*To avoid the hole, limit the max mc address to AMDGPU_GMC_HOLE_START*/
  136. u64 max_mc_address = min(adev->gmc.mc_mask, AMDGPU_GMC_HOLE_START - 1);
  137. mc->gart_size += adev->pm.smu_prv_buffer_size;
  138. /* VCE doesn't like it when BOs cross a 4GB segment, so align
  139. * the GART base on a 4GB boundary as well.
  140. */
  141. size_bf = mc->fb_start;
  142. size_af = max_mc_address + 1 - ALIGN(mc->fb_end + 1, four_gb);
  143. if (mc->gart_size > max(size_bf, size_af)) {
  144. dev_warn(adev->dev, "limiting GART\n");
  145. mc->gart_size = max(size_bf, size_af);
  146. }
  147. if ((size_bf >= mc->gart_size && size_bf < size_af) ||
  148. (size_af < mc->gart_size))
  149. mc->gart_start = 0;
  150. else
  151. mc->gart_start = max_mc_address - mc->gart_size + 1;
  152. mc->gart_start &= ~(four_gb - 1);
  153. mc->gart_end = mc->gart_start + mc->gart_size - 1;
  154. dev_info(adev->dev, "GART: %lluM 0x%016llX - 0x%016llX\n",
  155. mc->gart_size >> 20, mc->gart_start, mc->gart_end);
  156. }
  157. /**
  158. * amdgpu_gmc_agp_location - try to find AGP location
  159. * @adev: amdgpu device structure holding all necessary informations
  160. * @mc: memory controller structure holding memory informations
  161. *
  162. * Function will place try to find a place for the AGP BAR in the MC address
  163. * space.
  164. *
  165. * AGP BAR will be assigned the largest available hole in the address space.
  166. * Should be called after VRAM and GART locations are setup.
  167. */
  168. void amdgpu_gmc_agp_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc)
  169. {
  170. const uint64_t sixteen_gb = 1ULL << 34;
  171. const uint64_t sixteen_gb_mask = ~(sixteen_gb - 1);
  172. u64 size_af, size_bf;
  173. if (mc->fb_start > mc->gart_start) {
  174. size_bf = (mc->fb_start & sixteen_gb_mask) -
  175. ALIGN(mc->gart_end + 1, sixteen_gb);
  176. size_af = mc->mc_mask + 1 - ALIGN(mc->fb_end + 1, sixteen_gb);
  177. } else {
  178. size_bf = mc->fb_start & sixteen_gb_mask;
  179. size_af = (mc->gart_start & sixteen_gb_mask) -
  180. ALIGN(mc->fb_end + 1, sixteen_gb);
  181. }
  182. if (size_bf > size_af) {
  183. mc->agp_start = (mc->fb_start - size_bf) & sixteen_gb_mask;
  184. mc->agp_size = size_bf;
  185. } else {
  186. mc->agp_start = ALIGN(mc->fb_end + 1, sixteen_gb);
  187. mc->agp_size = size_af;
  188. }
  189. mc->agp_end = mc->agp_start + mc->agp_size - 1;
  190. dev_info(adev->dev, "AGP: %lluM 0x%016llX - 0x%016llX\n",
  191. mc->agp_size >> 20, mc->agp_start, mc->agp_end);
  192. }