16a7f76e7SChristian König /* 26a7f76e7SChristian König * Copyright 2016 Advanced Micro Devices, Inc. 36a7f76e7SChristian König * 46a7f76e7SChristian König * Permission is hereby granted, free of charge, to any person obtaining a 56a7f76e7SChristian König * copy of this software and associated documentation files (the "Software"), 66a7f76e7SChristian König * to deal in the Software without restriction, including without limitation 76a7f76e7SChristian König * the rights to use, copy, modify, merge, publish, distribute, sublicense, 86a7f76e7SChristian König * and/or sell copies of the Software, and to permit persons to whom the 96a7f76e7SChristian König * Software is furnished to do so, subject to the following conditions: 106a7f76e7SChristian König * 116a7f76e7SChristian König * The above copyright notice and this permission notice shall be included in 126a7f76e7SChristian König * all copies or substantial portions of the Software. 136a7f76e7SChristian König * 146a7f76e7SChristian König * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 156a7f76e7SChristian König * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 166a7f76e7SChristian König * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 176a7f76e7SChristian König * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 186a7f76e7SChristian König * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 196a7f76e7SChristian König * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 206a7f76e7SChristian König * OTHER DEALINGS IN THE SOFTWARE. 216a7f76e7SChristian König * 226a7f76e7SChristian König * Authors: Christian König 236a7f76e7SChristian König */ 246a7f76e7SChristian König 25f44ffd67SChristian König #include <linux/dma-mapping.h> 26267501ecSChristian König #include <drm/ttm/ttm_range_manager.h> 27267501ecSChristian König 286a7f76e7SChristian König #include "amdgpu.h" 299d1b3c78SChristian König #include "amdgpu_vm.h" 30ba5b662cSRamesh Errabolu #include "amdgpu_res_cursor.h" 31ad02e08eSOri Messinger #include "amdgpu_atomfirmware.h" 32ad02e08eSOri Messinger #include "atom.h" 336a7f76e7SChristian König 343b5d86fcSChristian König struct amdgpu_vram_reservation { 35c9cad937SArunpravin Paneer Selvam u64 start; 36c9cad937SArunpravin Paneer Selvam u64 size; 37c9cad937SArunpravin Paneer Selvam struct list_head allocated; 38c9cad937SArunpravin Paneer Selvam struct list_head blocks; 393b5d86fcSChristian König }; 403b5d86fcSChristian König 41589939d4SChristian König static inline struct amdgpu_vram_mgr * 42589939d4SChristian König to_vram_mgr(struct ttm_resource_manager *man) 430af135b8SDave Airlie { 440af135b8SDave Airlie return container_of(man, struct amdgpu_vram_mgr, manager); 450af135b8SDave Airlie } 460af135b8SDave Airlie 47589939d4SChristian König static inline struct amdgpu_device * 48589939d4SChristian König to_amdgpu_device(struct amdgpu_vram_mgr *mgr) 4937362793SDave Airlie { 5037362793SDave Airlie return container_of(mgr, struct amdgpu_device, mman.vram_mgr); 5137362793SDave Airlie } 526a7f76e7SChristian König 53708d19d9SChristian König static inline struct drm_buddy_block * 54708d19d9SChristian König amdgpu_vram_mgr_first_block(struct list_head *list) 55708d19d9SChristian König { 56708d19d9SChristian König return list_first_entry_or_null(list, struct drm_buddy_block, link); 57708d19d9SChristian König } 58708d19d9SChristian König 59708d19d9SChristian König static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head) 60708d19d9SChristian König { 61708d19d9SChristian König struct drm_buddy_block *block; 62708d19d9SChristian König u64 start, size; 63708d19d9SChristian König 64708d19d9SChristian König block = amdgpu_vram_mgr_first_block(head); 65708d19d9SChristian König if (!block) 66708d19d9SChristian König return false; 67708d19d9SChristian König 68708d19d9SChristian König while (head != block->link.next) { 69708d19d9SChristian König start = amdgpu_vram_mgr_block_start(block); 70708d19d9SChristian König size = amdgpu_vram_mgr_block_size(block); 71708d19d9SChristian König 72708d19d9SChristian König block = list_entry(block->link.next, struct drm_buddy_block, link); 73708d19d9SChristian König if (start + size != amdgpu_vram_mgr_block_start(block)) 74708d19d9SChristian König return false; 75708d19d9SChristian König } 76708d19d9SChristian König 77708d19d9SChristian König return true; 78708d19d9SChristian König } 79708d19d9SChristian König 80708d19d9SChristian König 81708d19d9SChristian König 826a7f76e7SChristian König /** 8355c374e9SKent Russell * DOC: mem_info_vram_total 8455c374e9SKent Russell * 8555c374e9SKent Russell * The amdgpu driver provides a sysfs API for reporting current total VRAM 8655c374e9SKent Russell * available on the device 8755c374e9SKent Russell * The file mem_info_vram_total is used for this and returns the total 8855c374e9SKent Russell * amount of VRAM in bytes 8955c374e9SKent Russell */ 9055c374e9SKent Russell static ssize_t amdgpu_mem_info_vram_total_show(struct device *dev, 9155c374e9SKent Russell struct device_attribute *attr, char *buf) 9255c374e9SKent Russell { 9355c374e9SKent Russell struct drm_device *ddev = dev_get_drvdata(dev); 941348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(ddev); 9555c374e9SKent Russell 9636000c7aSTian Tao return sysfs_emit(buf, "%llu\n", adev->gmc.real_vram_size); 9755c374e9SKent Russell } 9855c374e9SKent Russell 9955c374e9SKent Russell /** 10055c374e9SKent Russell * DOC: mem_info_vis_vram_total 10155c374e9SKent Russell * 10255c374e9SKent Russell * The amdgpu driver provides a sysfs API for reporting current total 10355c374e9SKent Russell * visible VRAM available on the device 10455c374e9SKent Russell * The file mem_info_vis_vram_total is used for this and returns the total 10555c374e9SKent Russell * amount of visible VRAM in bytes 10655c374e9SKent Russell */ 10755c374e9SKent Russell static ssize_t amdgpu_mem_info_vis_vram_total_show(struct device *dev, 10855c374e9SKent Russell struct device_attribute *attr, char *buf) 10955c374e9SKent Russell { 11055c374e9SKent Russell struct drm_device *ddev = dev_get_drvdata(dev); 1111348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(ddev); 11255c374e9SKent Russell 11336000c7aSTian Tao return sysfs_emit(buf, "%llu\n", adev->gmc.visible_vram_size); 11455c374e9SKent Russell } 11555c374e9SKent Russell 11655c374e9SKent Russell /** 11755c374e9SKent Russell * DOC: mem_info_vram_used 11855c374e9SKent Russell * 11955c374e9SKent Russell * The amdgpu driver provides a sysfs API for reporting current total VRAM 12055c374e9SKent Russell * available on the device 12155c374e9SKent Russell * The file mem_info_vram_used is used for this and returns the total 12255c374e9SKent Russell * amount of currently used VRAM in bytes 12355c374e9SKent Russell */ 12455c374e9SKent Russell static ssize_t amdgpu_mem_info_vram_used_show(struct device *dev, 125589939d4SChristian König struct device_attribute *attr, 126589939d4SChristian König char *buf) 12755c374e9SKent Russell { 12855c374e9SKent Russell struct drm_device *ddev = dev_get_drvdata(dev); 1291348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(ddev); 1307db47b83SChristian König struct ttm_resource_manager *man = &adev->mman.vram_mgr.manager; 13155c374e9SKent Russell 1327db47b83SChristian König return sysfs_emit(buf, "%llu\n", ttm_resource_manager_usage(man)); 13355c374e9SKent Russell } 13455c374e9SKent Russell 13555c374e9SKent Russell /** 13655c374e9SKent Russell * DOC: mem_info_vis_vram_used 13755c374e9SKent Russell * 13855c374e9SKent Russell * The amdgpu driver provides a sysfs API for reporting current total of 13955c374e9SKent Russell * used visible VRAM 14055c374e9SKent Russell * The file mem_info_vis_vram_used is used for this and returns the total 14155c374e9SKent Russell * amount of currently used visible VRAM in bytes 14255c374e9SKent Russell */ 14355c374e9SKent Russell static ssize_t amdgpu_mem_info_vis_vram_used_show(struct device *dev, 144589939d4SChristian König struct device_attribute *attr, 145589939d4SChristian König char *buf) 14655c374e9SKent Russell { 14755c374e9SKent Russell struct drm_device *ddev = dev_get_drvdata(dev); 1481348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(ddev); 14955c374e9SKent Russell 150ec6aae97SNirmoy Das return sysfs_emit(buf, "%llu\n", 151ec6aae97SNirmoy Das amdgpu_vram_mgr_vis_usage(&adev->mman.vram_mgr)); 15255c374e9SKent Russell } 15355c374e9SKent Russell 154589939d4SChristian König /** 155589939d4SChristian König * DOC: mem_info_vram_vendor 156589939d4SChristian König * 157589939d4SChristian König * The amdgpu driver provides a sysfs API for reporting the vendor of the 158589939d4SChristian König * installed VRAM 159589939d4SChristian König * The file mem_info_vram_vendor is used for this and returns the name of the 160589939d4SChristian König * vendor. 161589939d4SChristian König */ 162ad02e08eSOri Messinger static ssize_t amdgpu_mem_info_vram_vendor(struct device *dev, 163ad02e08eSOri Messinger struct device_attribute *attr, 164ad02e08eSOri Messinger char *buf) 165ad02e08eSOri Messinger { 166ad02e08eSOri Messinger struct drm_device *ddev = dev_get_drvdata(dev); 1671348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(ddev); 168ad02e08eSOri Messinger 169ad02e08eSOri Messinger switch (adev->gmc.vram_vendor) { 170ad02e08eSOri Messinger case SAMSUNG: 17136000c7aSTian Tao return sysfs_emit(buf, "samsung\n"); 172ad02e08eSOri Messinger case INFINEON: 17336000c7aSTian Tao return sysfs_emit(buf, "infineon\n"); 174ad02e08eSOri Messinger case ELPIDA: 17536000c7aSTian Tao return sysfs_emit(buf, "elpida\n"); 176ad02e08eSOri Messinger case ETRON: 17736000c7aSTian Tao return sysfs_emit(buf, "etron\n"); 178ad02e08eSOri Messinger case NANYA: 17936000c7aSTian Tao return sysfs_emit(buf, "nanya\n"); 180ad02e08eSOri Messinger case HYNIX: 18136000c7aSTian Tao return sysfs_emit(buf, "hynix\n"); 182ad02e08eSOri Messinger case MOSEL: 18336000c7aSTian Tao return sysfs_emit(buf, "mosel\n"); 184ad02e08eSOri Messinger case WINBOND: 18536000c7aSTian Tao return sysfs_emit(buf, "winbond\n"); 186ad02e08eSOri Messinger case ESMT: 18736000c7aSTian Tao return sysfs_emit(buf, "esmt\n"); 188ad02e08eSOri Messinger case MICRON: 18936000c7aSTian Tao return sysfs_emit(buf, "micron\n"); 190ad02e08eSOri Messinger default: 19136000c7aSTian Tao return sysfs_emit(buf, "unknown\n"); 192ad02e08eSOri Messinger } 193ad02e08eSOri Messinger } 194ad02e08eSOri Messinger 19555c374e9SKent Russell static DEVICE_ATTR(mem_info_vram_total, S_IRUGO, 19655c374e9SKent Russell amdgpu_mem_info_vram_total_show, NULL); 19755c374e9SKent Russell static DEVICE_ATTR(mem_info_vis_vram_total, S_IRUGO, 19855c374e9SKent Russell amdgpu_mem_info_vis_vram_total_show,NULL); 19955c374e9SKent Russell static DEVICE_ATTR(mem_info_vram_used, S_IRUGO, 20055c374e9SKent Russell amdgpu_mem_info_vram_used_show, NULL); 20155c374e9SKent Russell static DEVICE_ATTR(mem_info_vis_vram_used, S_IRUGO, 20255c374e9SKent Russell amdgpu_mem_info_vis_vram_used_show, NULL); 203ad02e08eSOri Messinger static DEVICE_ATTR(mem_info_vram_vendor, S_IRUGO, 204ad02e08eSOri Messinger amdgpu_mem_info_vram_vendor, NULL); 20555c374e9SKent Russell 20635bba831SAndrey Grodzovsky static struct attribute *amdgpu_vram_mgr_attributes[] = { 207ecc8c2e1SBernard Zhao &dev_attr_mem_info_vram_total.attr, 208ecc8c2e1SBernard Zhao &dev_attr_mem_info_vis_vram_total.attr, 209ecc8c2e1SBernard Zhao &dev_attr_mem_info_vram_used.attr, 210ecc8c2e1SBernard Zhao &dev_attr_mem_info_vis_vram_used.attr, 211ecc8c2e1SBernard Zhao &dev_attr_mem_info_vram_vendor.attr, 212ecc8c2e1SBernard Zhao NULL 213ecc8c2e1SBernard Zhao }; 214ecc8c2e1SBernard Zhao 21535bba831SAndrey Grodzovsky const struct attribute_group amdgpu_vram_mgr_attr_group = { 21635bba831SAndrey Grodzovsky .attrs = amdgpu_vram_mgr_attributes 21735bba831SAndrey Grodzovsky }; 21835bba831SAndrey Grodzovsky 2196a7f76e7SChristian König /** 220c9cad937SArunpravin Paneer Selvam * amdgpu_vram_mgr_vis_size - Calculate visible block size 2213c848bb3SChristian König * 222982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer 223c9cad937SArunpravin Paneer Selvam * @block: DRM BUDDY block structure 2243c848bb3SChristian König * 225c9cad937SArunpravin Paneer Selvam * Calculate how many bytes of the DRM BUDDY block are inside visible VRAM 2263c848bb3SChristian König */ 2273c848bb3SChristian König static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev, 228c9cad937SArunpravin Paneer Selvam struct drm_buddy_block *block) 2293c848bb3SChristian König { 230c9cad937SArunpravin Paneer Selvam u64 start = amdgpu_vram_mgr_block_start(block); 231c9cad937SArunpravin Paneer Selvam u64 end = start + amdgpu_vram_mgr_block_size(block); 2323c848bb3SChristian König 233770d13b1SChristian König if (start >= adev->gmc.visible_vram_size) 2343c848bb3SChristian König return 0; 2353c848bb3SChristian König 236770d13b1SChristian König return (end > adev->gmc.visible_vram_size ? 237770d13b1SChristian König adev->gmc.visible_vram_size : end) - start; 2383c848bb3SChristian König } 2393c848bb3SChristian König 2403c848bb3SChristian König /** 241ddc21af4SMichel Dänzer * amdgpu_vram_mgr_bo_visible_size - CPU visible BO size 2425e9244ffSMichel Dänzer * 2435e9244ffSMichel Dänzer * @bo: &amdgpu_bo buffer object (must be in VRAM) 2445e9244ffSMichel Dänzer * 2455e9244ffSMichel Dänzer * Returns: 246ddc21af4SMichel Dänzer * How much of the given &amdgpu_bo buffer object lies in CPU visible VRAM. 2475e9244ffSMichel Dänzer */ 248ddc21af4SMichel Dänzer u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo) 2495e9244ffSMichel Dänzer { 2507303b39eSMichel Dänzer struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); 251cb1c8146SChristian König struct ttm_resource *res = bo->tbo.resource; 252c9cad937SArunpravin Paneer Selvam struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res); 253c9cad937SArunpravin Paneer Selvam struct drm_buddy_block *block; 254c9cad937SArunpravin Paneer Selvam u64 usage = 0; 2557303b39eSMichel Dänzer 2569735bf19SMichel Dänzer if (amdgpu_gmc_vram_full_visible(&adev->gmc)) 2575e9244ffSMichel Dänzer return amdgpu_bo_size(bo); 2585e9244ffSMichel Dänzer 259cb1c8146SChristian König if (res->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT) 260ddc21af4SMichel Dänzer return 0; 261ddc21af4SMichel Dänzer 262c9cad937SArunpravin Paneer Selvam list_for_each_entry(block, &vres->blocks, link) 263c9cad937SArunpravin Paneer Selvam usage += amdgpu_vram_mgr_vis_size(adev, block); 2647303b39eSMichel Dänzer 2657303b39eSMichel Dänzer return usage; 2665e9244ffSMichel Dänzer } 2675e9244ffSMichel Dänzer 268589939d4SChristian König /* Commit the reservation of VRAM pages */ 269676deb38SDennis Li static void amdgpu_vram_mgr_do_reserve(struct ttm_resource_manager *man) 270676deb38SDennis Li { 271676deb38SDennis Li struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); 272676deb38SDennis Li struct amdgpu_device *adev = to_amdgpu_device(mgr); 273c9cad937SArunpravin Paneer Selvam struct drm_buddy *mm = &mgr->mm; 274676deb38SDennis Li struct amdgpu_vram_reservation *rsv, *temp; 275c9cad937SArunpravin Paneer Selvam struct drm_buddy_block *block; 276676deb38SDennis Li uint64_t vis_usage; 277676deb38SDennis Li 278c9cad937SArunpravin Paneer Selvam list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks) { 279c9cad937SArunpravin Paneer Selvam if (drm_buddy_alloc_blocks(mm, rsv->start, rsv->start + rsv->size, 280c9cad937SArunpravin Paneer Selvam rsv->size, mm->chunk_size, &rsv->allocated, 281c9cad937SArunpravin Paneer Selvam DRM_BUDDY_RANGE_ALLOCATION)) 282c9cad937SArunpravin Paneer Selvam continue; 283c9cad937SArunpravin Paneer Selvam 284c9cad937SArunpravin Paneer Selvam block = amdgpu_vram_mgr_first_block(&rsv->allocated); 285c9cad937SArunpravin Paneer Selvam if (!block) 286676deb38SDennis Li continue; 287676deb38SDennis Li 2887dee4d51SColin Ian King dev_dbg(adev->dev, "Reservation 0x%llx - %lld, Succeeded\n", 289c9cad937SArunpravin Paneer Selvam rsv->start, rsv->size); 290676deb38SDennis Li 291c9cad937SArunpravin Paneer Selvam vis_usage = amdgpu_vram_mgr_vis_size(adev, block); 292676deb38SDennis Li atomic64_add(vis_usage, &mgr->vis_usage); 2937db47b83SChristian König spin_lock(&man->bdev->lru_lock); 294c9cad937SArunpravin Paneer Selvam man->usage += rsv->size; 2957db47b83SChristian König spin_unlock(&man->bdev->lru_lock); 296c9cad937SArunpravin Paneer Selvam list_move(&rsv->blocks, &mgr->reserved_pages); 297676deb38SDennis Li } 298676deb38SDennis Li } 299676deb38SDennis Li 300676deb38SDennis Li /** 301676deb38SDennis Li * amdgpu_vram_mgr_reserve_range - Reserve a range from VRAM 302676deb38SDennis Li * 303ec6aae97SNirmoy Das * @mgr: amdgpu_vram_mgr pointer 304676deb38SDennis Li * @start: start address of the range in VRAM 305676deb38SDennis Li * @size: size of the range 306676deb38SDennis Li * 307ec6aae97SNirmoy Das * Reserve memory from start address with the specified size in VRAM 308676deb38SDennis Li */ 309ec6aae97SNirmoy Das int amdgpu_vram_mgr_reserve_range(struct amdgpu_vram_mgr *mgr, 310676deb38SDennis Li uint64_t start, uint64_t size) 311676deb38SDennis Li { 312676deb38SDennis Li struct amdgpu_vram_reservation *rsv; 313676deb38SDennis Li 314676deb38SDennis Li rsv = kzalloc(sizeof(*rsv), GFP_KERNEL); 315676deb38SDennis Li if (!rsv) 316676deb38SDennis Li return -ENOMEM; 317676deb38SDennis Li 318c9cad937SArunpravin Paneer Selvam INIT_LIST_HEAD(&rsv->allocated); 319c9cad937SArunpravin Paneer Selvam INIT_LIST_HEAD(&rsv->blocks); 320676deb38SDennis Li 321c9cad937SArunpravin Paneer Selvam rsv->start = start; 322c9cad937SArunpravin Paneer Selvam rsv->size = size; 323c9cad937SArunpravin Paneer Selvam 324c9cad937SArunpravin Paneer Selvam mutex_lock(&mgr->lock); 325c9cad937SArunpravin Paneer Selvam list_add_tail(&rsv->blocks, &mgr->reservations_pending); 326ec6aae97SNirmoy Das amdgpu_vram_mgr_do_reserve(&mgr->manager); 327c9cad937SArunpravin Paneer Selvam mutex_unlock(&mgr->lock); 328676deb38SDennis Li 329676deb38SDennis Li return 0; 330676deb38SDennis Li } 331676deb38SDennis Li 332676deb38SDennis Li /** 333676deb38SDennis Li * amdgpu_vram_mgr_query_page_status - query the reservation status 334676deb38SDennis Li * 335ec6aae97SNirmoy Das * @mgr: amdgpu_vram_mgr pointer 336676deb38SDennis Li * @start: start address of a page in VRAM 337676deb38SDennis Li * 338676deb38SDennis Li * Returns: 339676deb38SDennis Li * -EBUSY: the page is still hold and in pending list 340676deb38SDennis Li * 0: the page has been reserved 341676deb38SDennis Li * -ENOENT: the input page is not a reservation 342676deb38SDennis Li */ 343ec6aae97SNirmoy Das int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr, 344676deb38SDennis Li uint64_t start) 345676deb38SDennis Li { 346676deb38SDennis Li struct amdgpu_vram_reservation *rsv; 347676deb38SDennis Li int ret; 348676deb38SDennis Li 349c9cad937SArunpravin Paneer Selvam mutex_lock(&mgr->lock); 350676deb38SDennis Li 351c9cad937SArunpravin Paneer Selvam list_for_each_entry(rsv, &mgr->reservations_pending, blocks) { 352c9cad937SArunpravin Paneer Selvam if (rsv->start <= start && 353c9cad937SArunpravin Paneer Selvam (start < (rsv->start + rsv->size))) { 354676deb38SDennis Li ret = -EBUSY; 355676deb38SDennis Li goto out; 356676deb38SDennis Li } 357676deb38SDennis Li } 358676deb38SDennis Li 359c9cad937SArunpravin Paneer Selvam list_for_each_entry(rsv, &mgr->reserved_pages, blocks) { 360c9cad937SArunpravin Paneer Selvam if (rsv->start <= start && 361c9cad937SArunpravin Paneer Selvam (start < (rsv->start + rsv->size))) { 362676deb38SDennis Li ret = 0; 363676deb38SDennis Li goto out; 364676deb38SDennis Li } 365676deb38SDennis Li } 366676deb38SDennis Li 367676deb38SDennis Li ret = -ENOENT; 368676deb38SDennis Li out: 369c9cad937SArunpravin Paneer Selvam mutex_unlock(&mgr->lock); 370676deb38SDennis Li return ret; 371676deb38SDennis Li } 372676deb38SDennis Li 3735e9244ffSMichel Dänzer /** 3746a7f76e7SChristian König * amdgpu_vram_mgr_new - allocate new ranges 3756a7f76e7SChristian König * 3766a7f76e7SChristian König * @man: TTM memory type manager 3776a7f76e7SChristian König * @tbo: TTM BO we need this range for 3786a7f76e7SChristian König * @place: placement flags and restrictions 3796333a495SYifan Zhang * @res: the resulting mem object 3806a7f76e7SChristian König * 3816a7f76e7SChristian König * Allocate VRAM for the given BO. 3826a7f76e7SChristian König */ 3839de59bc2SDave Airlie static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, 3846a7f76e7SChristian König struct ttm_buffer_object *tbo, 3856a7f76e7SChristian König const struct ttm_place *place, 386cb1c8146SChristian König struct ttm_resource **res) 3876a7f76e7SChristian König { 388c9cad937SArunpravin Paneer Selvam u64 vis_usage = 0, max_bytes, cur_size, min_block_size; 3890af135b8SDave Airlie struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); 39037362793SDave Airlie struct amdgpu_device *adev = to_amdgpu_device(mgr); 391c9cad937SArunpravin Paneer Selvam struct amdgpu_vram_mgr_resource *vres; 392c9cad937SArunpravin Paneer Selvam u64 size, remaining_size, lpfn, fpfn; 393c9cad937SArunpravin Paneer Selvam struct drm_buddy *mm = &mgr->mm; 394c9cad937SArunpravin Paneer Selvam struct drm_buddy_block *block; 395c9cad937SArunpravin Paneer Selvam unsigned long pages_per_block; 3966a7f76e7SChristian König int r; 3976a7f76e7SChristian König 3986f2c8d5fSArunpravin Paneer Selvam lpfn = (u64)place->lpfn << PAGE_SHIFT; 3996a7f76e7SChristian König if (!lpfn) 400c9cad937SArunpravin Paneer Selvam lpfn = man->size; 401c9cad937SArunpravin Paneer Selvam 4026f2c8d5fSArunpravin Paneer Selvam fpfn = (u64)place->fpfn << PAGE_SHIFT; 4036a7f76e7SChristian König 4049d1b3c78SChristian König max_bytes = adev->gmc.mc_vram_size; 4059d1b3c78SChristian König if (tbo->type != ttm_bo_type_kernel) 4069d1b3c78SChristian König max_bytes -= AMDGPU_VM_RESERVED_VRAM; 4079d1b3c78SChristian König 408b4559a16STom St Denis if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { 409c9cad937SArunpravin Paneer Selvam pages_per_block = ~0ul; 4106a7f76e7SChristian König } else { 411b4559a16STom St Denis #ifdef CONFIG_TRANSPARENT_HUGEPAGE 412c9cad937SArunpravin Paneer Selvam pages_per_block = HPAGE_PMD_NR; 413b4559a16STom St Denis #else 414b4559a16STom St Denis /* default to 2MB */ 415c9cad937SArunpravin Paneer Selvam pages_per_block = 2UL << (20UL - PAGE_SHIFT); 416b4559a16STom St Denis #endif 417c9cad937SArunpravin Paneer Selvam pages_per_block = max_t(uint32_t, pages_per_block, 418c777dc9eSChristian König tbo->page_alignment); 4196a7f76e7SChristian König } 4206a7f76e7SChristian König 421c9cad937SArunpravin Paneer Selvam vres = kzalloc(sizeof(*vres), GFP_KERNEL); 422c9cad937SArunpravin Paneer Selvam if (!vres) 4237db47b83SChristian König return -ENOMEM; 4246a7f76e7SChristian König 425c9cad937SArunpravin Paneer Selvam ttm_resource_init(tbo, place, &vres->base); 426267501ecSChristian König 4277db47b83SChristian König /* bail out quickly if there's likely not enough VRAM for this BO */ 4287db47b83SChristian König if (ttm_resource_manager_usage(man) > max_bytes) { 4297db47b83SChristian König r = -ENOSPC; 4307db47b83SChristian König goto error_fini; 4317db47b83SChristian König } 4327db47b83SChristian König 433c9cad937SArunpravin Paneer Selvam INIT_LIST_HEAD(&vres->blocks); 434c9cad937SArunpravin Paneer Selvam 4354e64e553SChris Wilson if (place->flags & TTM_PL_FLAG_TOPDOWN) 436c9cad937SArunpravin Paneer Selvam vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION; 4376a7f76e7SChristian König 438*e0b26b94SMa Jun if (fpfn || lpfn != mgr->mm.size) 439c9cad937SArunpravin Paneer Selvam /* Allocate blocks in desired range */ 440c9cad937SArunpravin Paneer Selvam vres->flags |= DRM_BUDDY_RANGE_ALLOCATION; 4416a7f76e7SChristian König 4426f2c8d5fSArunpravin Paneer Selvam remaining_size = (u64)vres->base.num_pages << PAGE_SHIFT; 443b131c363SRamesh Errabolu 444c9cad937SArunpravin Paneer Selvam mutex_lock(&mgr->lock); 445c9cad937SArunpravin Paneer Selvam while (remaining_size) { 446c9cad937SArunpravin Paneer Selvam if (tbo->page_alignment) 4476f2c8d5fSArunpravin Paneer Selvam min_block_size = (u64)tbo->page_alignment << PAGE_SHIFT; 448dd03daecSChristian König else 449c9cad937SArunpravin Paneer Selvam min_block_size = mgr->default_page_size; 450c9cad937SArunpravin Paneer Selvam 451c9cad937SArunpravin Paneer Selvam BUG_ON(min_block_size < mm->chunk_size); 452c9cad937SArunpravin Paneer Selvam 453c9cad937SArunpravin Paneer Selvam /* Limit maximum size to 2GiB due to SG table limitations */ 454c9cad937SArunpravin Paneer Selvam size = min(remaining_size, 2ULL << 30); 455c9cad937SArunpravin Paneer Selvam 4566f2c8d5fSArunpravin Paneer Selvam if (size >= (u64)pages_per_block << PAGE_SHIFT) 4576f2c8d5fSArunpravin Paneer Selvam min_block_size = (u64)pages_per_block << PAGE_SHIFT; 458c9cad937SArunpravin Paneer Selvam 459c9cad937SArunpravin Paneer Selvam cur_size = size; 460c9cad937SArunpravin Paneer Selvam 4616f2c8d5fSArunpravin Paneer Selvam if (fpfn + size != (u64)place->lpfn << PAGE_SHIFT) { 462c9cad937SArunpravin Paneer Selvam /* 463c9cad937SArunpravin Paneer Selvam * Except for actual range allocation, modify the size and 464c9cad937SArunpravin Paneer Selvam * min_block_size conforming to continuous flag enablement 465c9cad937SArunpravin Paneer Selvam */ 466c9cad937SArunpravin Paneer Selvam if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { 467c9cad937SArunpravin Paneer Selvam size = roundup_pow_of_two(size); 468c9cad937SArunpravin Paneer Selvam min_block_size = size; 469c9cad937SArunpravin Paneer Selvam /* 470c9cad937SArunpravin Paneer Selvam * Modify the size value if size is not 471c9cad937SArunpravin Paneer Selvam * aligned with min_block_size 472c9cad937SArunpravin Paneer Selvam */ 473c9cad937SArunpravin Paneer Selvam } else if (!IS_ALIGNED(size, min_block_size)) { 474c9cad937SArunpravin Paneer Selvam size = round_up(size, min_block_size); 475dd03daecSChristian König } 476dd03daecSChristian König } 4776a7f76e7SChristian König 478c9cad937SArunpravin Paneer Selvam r = drm_buddy_alloc_blocks(mm, fpfn, 479c9cad937SArunpravin Paneer Selvam lpfn, 480c9cad937SArunpravin Paneer Selvam size, 481c9cad937SArunpravin Paneer Selvam min_block_size, 482c9cad937SArunpravin Paneer Selvam &vres->blocks, 483c9cad937SArunpravin Paneer Selvam vres->flags); 484c9cad937SArunpravin Paneer Selvam if (unlikely(r)) 485c9cad937SArunpravin Paneer Selvam goto error_free_blocks; 486dd03daecSChristian König 487c9cad937SArunpravin Paneer Selvam if (size > remaining_size) 488c9cad937SArunpravin Paneer Selvam remaining_size = 0; 489c9cad937SArunpravin Paneer Selvam else 490c9cad937SArunpravin Paneer Selvam remaining_size -= size; 4916a7f76e7SChristian König } 492c9cad937SArunpravin Paneer Selvam mutex_unlock(&mgr->lock); 4936a7f76e7SChristian König 494c9cad937SArunpravin Paneer Selvam if (cur_size != size) { 495c9cad937SArunpravin Paneer Selvam struct drm_buddy_block *block; 496c9cad937SArunpravin Paneer Selvam struct list_head *trim_list; 497c9cad937SArunpravin Paneer Selvam u64 original_size; 498c9cad937SArunpravin Paneer Selvam LIST_HEAD(temp); 499c9cad937SArunpravin Paneer Selvam 500c9cad937SArunpravin Paneer Selvam trim_list = &vres->blocks; 5016f2c8d5fSArunpravin Paneer Selvam original_size = (u64)vres->base.num_pages << PAGE_SHIFT; 502c9cad937SArunpravin Paneer Selvam 503c9cad937SArunpravin Paneer Selvam /* 504c9cad937SArunpravin Paneer Selvam * If size value is rounded up to min_block_size, trim the last 505c9cad937SArunpravin Paneer Selvam * block to the required size 506c9cad937SArunpravin Paneer Selvam */ 507c9cad937SArunpravin Paneer Selvam if (!list_is_singular(&vres->blocks)) { 508c9cad937SArunpravin Paneer Selvam block = list_last_entry(&vres->blocks, typeof(*block), link); 509c9cad937SArunpravin Paneer Selvam list_move_tail(&block->link, &temp); 510c9cad937SArunpravin Paneer Selvam trim_list = &temp; 511c9cad937SArunpravin Paneer Selvam /* 512c9cad937SArunpravin Paneer Selvam * Compute the original_size value by subtracting the 513c9cad937SArunpravin Paneer Selvam * last block size with (aligned size - original size) 514c9cad937SArunpravin Paneer Selvam */ 515c9cad937SArunpravin Paneer Selvam original_size = amdgpu_vram_mgr_block_size(block) - (size - cur_size); 516c9cad937SArunpravin Paneer Selvam } 517c9cad937SArunpravin Paneer Selvam 518c9cad937SArunpravin Paneer Selvam mutex_lock(&mgr->lock); 519c9cad937SArunpravin Paneer Selvam drm_buddy_block_trim(mm, 520c9cad937SArunpravin Paneer Selvam original_size, 521c9cad937SArunpravin Paneer Selvam trim_list); 522c9cad937SArunpravin Paneer Selvam mutex_unlock(&mgr->lock); 523c9cad937SArunpravin Paneer Selvam 524c9cad937SArunpravin Paneer Selvam if (!list_empty(&temp)) 525c9cad937SArunpravin Paneer Selvam list_splice_tail(trim_list, &vres->blocks); 526c9cad937SArunpravin Paneer Selvam } 527c9cad937SArunpravin Paneer Selvam 5285e3f1e77SChristian König vres->base.start = 0; 5295e3f1e77SChristian König list_for_each_entry(block, &vres->blocks, link) { 5305e3f1e77SChristian König unsigned long start; 5315e3f1e77SChristian König 5325e3f1e77SChristian König start = amdgpu_vram_mgr_block_start(block) + 5335e3f1e77SChristian König amdgpu_vram_mgr_block_size(block); 5345e3f1e77SChristian König start >>= PAGE_SHIFT; 5355e3f1e77SChristian König 5365e3f1e77SChristian König if (start > vres->base.num_pages) 5375e3f1e77SChristian König start -= vres->base.num_pages; 5385e3f1e77SChristian König else 5395e3f1e77SChristian König start = 0; 5405e3f1e77SChristian König vres->base.start = max(vres->base.start, start); 5415e3f1e77SChristian König 542c9cad937SArunpravin Paneer Selvam vis_usage += amdgpu_vram_mgr_vis_size(adev, block); 543c9cad937SArunpravin Paneer Selvam } 544c9cad937SArunpravin Paneer Selvam 545c9cad937SArunpravin Paneer Selvam if (amdgpu_is_vram_mgr_blocks_contiguous(&vres->blocks)) 546c9cad937SArunpravin Paneer Selvam vres->base.placement |= TTM_PL_FLAG_CONTIGUOUS; 547abf91e0dSChristian König 5488dbe43e9SOak Zeng if (adev->gmc.xgmi.connected_to_cpu) 549c9cad937SArunpravin Paneer Selvam vres->base.bus.caching = ttm_cached; 5508dbe43e9SOak Zeng else 551c9cad937SArunpravin Paneer Selvam vres->base.bus.caching = ttm_write_combined; 5528dbe43e9SOak Zeng 5533c848bb3SChristian König atomic64_add(vis_usage, &mgr->vis_usage); 554c9cad937SArunpravin Paneer Selvam *res = &vres->base; 5556a7f76e7SChristian König return 0; 5566a7f76e7SChristian König 557c9cad937SArunpravin Paneer Selvam error_free_blocks: 558c9cad937SArunpravin Paneer Selvam drm_buddy_free_list(mm, &vres->blocks); 559c9cad937SArunpravin Paneer Selvam mutex_unlock(&mgr->lock); 5607db47b83SChristian König error_fini: 561c9cad937SArunpravin Paneer Selvam ttm_resource_fini(man, &vres->base); 562c9cad937SArunpravin Paneer Selvam kfree(vres); 5636a7f76e7SChristian König 56458e4d686SChristian König return r; 5656a7f76e7SChristian König } 5666a7f76e7SChristian König 5676a7f76e7SChristian König /** 5686a7f76e7SChristian König * amdgpu_vram_mgr_del - free ranges 5696a7f76e7SChristian König * 5706a7f76e7SChristian König * @man: TTM memory type manager 5716333a495SYifan Zhang * @res: TTM memory object 5726a7f76e7SChristian König * 5736a7f76e7SChristian König * Free the allocated VRAM again. 5746a7f76e7SChristian König */ 5759de59bc2SDave Airlie static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, 576cb1c8146SChristian König struct ttm_resource *res) 5776a7f76e7SChristian König { 578c9cad937SArunpravin Paneer Selvam struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res); 5790af135b8SDave Airlie struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); 58037362793SDave Airlie struct amdgpu_device *adev = to_amdgpu_device(mgr); 581c9cad937SArunpravin Paneer Selvam struct drm_buddy *mm = &mgr->mm; 582c9cad937SArunpravin Paneer Selvam struct drm_buddy_block *block; 5837db47b83SChristian König uint64_t vis_usage = 0; 584267501ecSChristian König 585c9cad937SArunpravin Paneer Selvam mutex_lock(&mgr->lock); 586c9cad937SArunpravin Paneer Selvam list_for_each_entry(block, &vres->blocks, link) 587c9cad937SArunpravin Paneer Selvam vis_usage += amdgpu_vram_mgr_vis_size(adev, block); 588cb1c8146SChristian König 589676deb38SDennis Li amdgpu_vram_mgr_do_reserve(man); 590c9cad937SArunpravin Paneer Selvam 591c9cad937SArunpravin Paneer Selvam drm_buddy_free_list(mm, &vres->blocks); 592c9cad937SArunpravin Paneer Selvam mutex_unlock(&mgr->lock); 5936a7f76e7SChristian König 5943c848bb3SChristian König atomic64_sub(vis_usage, &mgr->vis_usage); 5953c848bb3SChristian König 596de3688e4SChristian König ttm_resource_fini(man, res); 597c9cad937SArunpravin Paneer Selvam kfree(vres); 5986a7f76e7SChristian König } 5996a7f76e7SChristian König 6006a7f76e7SChristian König /** 601f44ffd67SChristian König * amdgpu_vram_mgr_alloc_sgt - allocate and fill a sg table 602f44ffd67SChristian König * 603f44ffd67SChristian König * @adev: amdgpu device pointer 6046333a495SYifan Zhang * @res: TTM memory object 605ba5b662cSRamesh Errabolu * @offset: byte offset from the base of VRAM BO 606ba5b662cSRamesh Errabolu * @length: number of bytes to export in sg_table 607f44ffd67SChristian König * @dev: the other device 608f44ffd67SChristian König * @dir: dma direction 609f44ffd67SChristian König * @sgt: resulting sg table 610f44ffd67SChristian König * 611f44ffd67SChristian König * Allocate and fill a sg table from a VRAM allocation. 612f44ffd67SChristian König */ 613f44ffd67SChristian König int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev, 614cb1c8146SChristian König struct ttm_resource *res, 615ba5b662cSRamesh Errabolu u64 offset, u64 length, 616f44ffd67SChristian König struct device *dev, 617f44ffd67SChristian König enum dma_data_direction dir, 618f44ffd67SChristian König struct sg_table **sgt) 619f44ffd67SChristian König { 620ba5b662cSRamesh Errabolu struct amdgpu_res_cursor cursor; 621f44ffd67SChristian König struct scatterlist *sg; 622f44ffd67SChristian König int num_entries = 0; 623f44ffd67SChristian König int i, r; 624f44ffd67SChristian König 62578484d7cSChristophe JAILLET *sgt = kmalloc(sizeof(**sgt), GFP_KERNEL); 626f44ffd67SChristian König if (!*sgt) 627f44ffd67SChristian König return -ENOMEM; 628f44ffd67SChristian König 629c9cad937SArunpravin Paneer Selvam /* Determine the number of DRM_BUDDY blocks to export */ 630cb1c8146SChristian König amdgpu_res_first(res, offset, length, &cursor); 631ba5b662cSRamesh Errabolu while (cursor.remaining) { 632ba5b662cSRamesh Errabolu num_entries++; 633ba5b662cSRamesh Errabolu amdgpu_res_next(&cursor, cursor.size); 634ba5b662cSRamesh Errabolu } 635f44ffd67SChristian König 636f44ffd67SChristian König r = sg_alloc_table(*sgt, num_entries, GFP_KERNEL); 637f44ffd67SChristian König if (r) 638f44ffd67SChristian König goto error_free; 639f44ffd67SChristian König 640ba5b662cSRamesh Errabolu /* Initialize scatterlist nodes of sg_table */ 64139913934SMarek Szyprowski for_each_sgtable_sg((*sgt), sg, i) 642f44ffd67SChristian König sg->length = 0; 643f44ffd67SChristian König 644ba5b662cSRamesh Errabolu /* 645c9cad937SArunpravin Paneer Selvam * Walk down DRM_BUDDY blocks to populate scatterlist nodes 646c9cad937SArunpravin Paneer Selvam * @note: Use iterator api to get first the DRM_BUDDY block 647ba5b662cSRamesh Errabolu * and the number of bytes from it. Access the following 648c9cad937SArunpravin Paneer Selvam * DRM_BUDDY block(s) if more buffer needs to exported 649ba5b662cSRamesh Errabolu */ 650cb1c8146SChristian König amdgpu_res_first(res, offset, length, &cursor); 65139913934SMarek Szyprowski for_each_sgtable_sg((*sgt), sg, i) { 652ba5b662cSRamesh Errabolu phys_addr_t phys = cursor.start + adev->gmc.aper_base; 653ba5b662cSRamesh Errabolu size_t size = cursor.size; 654f44ffd67SChristian König dma_addr_t addr; 655f44ffd67SChristian König 656f44ffd67SChristian König addr = dma_map_resource(dev, phys, size, dir, 657f44ffd67SChristian König DMA_ATTR_SKIP_CPU_SYNC); 658f44ffd67SChristian König r = dma_mapping_error(dev, addr); 659f44ffd67SChristian König if (r) 660f44ffd67SChristian König goto error_unmap; 661f44ffd67SChristian König 662f44ffd67SChristian König sg_set_page(sg, NULL, size, 0); 663f44ffd67SChristian König sg_dma_address(sg) = addr; 664f44ffd67SChristian König sg_dma_len(sg) = size; 665ba5b662cSRamesh Errabolu 666ba5b662cSRamesh Errabolu amdgpu_res_next(&cursor, cursor.size); 667f44ffd67SChristian König } 668ba5b662cSRamesh Errabolu 669f44ffd67SChristian König return 0; 670f44ffd67SChristian König 671f44ffd67SChristian König error_unmap: 67239913934SMarek Szyprowski for_each_sgtable_sg((*sgt), sg, i) { 673f44ffd67SChristian König if (!sg->length) 674f44ffd67SChristian König continue; 675f44ffd67SChristian König 676f44ffd67SChristian König dma_unmap_resource(dev, sg->dma_address, 677f44ffd67SChristian König sg->length, dir, 678f44ffd67SChristian König DMA_ATTR_SKIP_CPU_SYNC); 679f44ffd67SChristian König } 680f44ffd67SChristian König sg_free_table(*sgt); 681f44ffd67SChristian König 682f44ffd67SChristian König error_free: 683f44ffd67SChristian König kfree(*sgt); 684f44ffd67SChristian König return r; 685f44ffd67SChristian König } 686f44ffd67SChristian König 687f44ffd67SChristian König /** 688c45dd3bdSMauro Carvalho Chehab * amdgpu_vram_mgr_free_sgt - allocate and fill a sg table 689f44ffd67SChristian König * 6902c8645b7SLee Jones * @dev: device pointer 6912c8645b7SLee Jones * @dir: data direction of resource to unmap 692f44ffd67SChristian König * @sgt: sg table to free 693f44ffd67SChristian König * 694f44ffd67SChristian König * Free a previously allocate sg table. 695f44ffd67SChristian König */ 6965392b2afSRamesh Errabolu void amdgpu_vram_mgr_free_sgt(struct device *dev, 697f44ffd67SChristian König enum dma_data_direction dir, 698f44ffd67SChristian König struct sg_table *sgt) 699f44ffd67SChristian König { 700f44ffd67SChristian König struct scatterlist *sg; 701f44ffd67SChristian König int i; 702f44ffd67SChristian König 70339913934SMarek Szyprowski for_each_sgtable_sg(sgt, sg, i) 704f44ffd67SChristian König dma_unmap_resource(dev, sg->dma_address, 705f44ffd67SChristian König sg->length, dir, 706f44ffd67SChristian König DMA_ATTR_SKIP_CPU_SYNC); 707f44ffd67SChristian König sg_free_table(sgt); 708f44ffd67SChristian König kfree(sgt); 709f44ffd67SChristian König } 710f44ffd67SChristian König 711f44ffd67SChristian König /** 7123c848bb3SChristian König * amdgpu_vram_mgr_vis_usage - how many bytes are used in the visible part 7133c848bb3SChristian König * 714ec6aae97SNirmoy Das * @mgr: amdgpu_vram_mgr pointer 7153c848bb3SChristian König * 7163c848bb3SChristian König * Returns how many bytes are used in the visible part of VRAM 7173c848bb3SChristian König */ 718ec6aae97SNirmoy Das uint64_t amdgpu_vram_mgr_vis_usage(struct amdgpu_vram_mgr *mgr) 7193c848bb3SChristian König { 7203c848bb3SChristian König return atomic64_read(&mgr->vis_usage); 7213c848bb3SChristian König } 7223c848bb3SChristian König 7233c848bb3SChristian König /** 724ded910f3SArunpravin Paneer Selvam * amdgpu_vram_mgr_intersects - test each drm buddy block for intersection 725ded910f3SArunpravin Paneer Selvam * 726ded910f3SArunpravin Paneer Selvam * @man: TTM memory type manager 727ded910f3SArunpravin Paneer Selvam * @res: The resource to test 728ded910f3SArunpravin Paneer Selvam * @place: The place to test against 729ded910f3SArunpravin Paneer Selvam * @size: Size of the new allocation 730ded910f3SArunpravin Paneer Selvam * 731ded910f3SArunpravin Paneer Selvam * Test each drm buddy block for intersection for eviction decision. 732ded910f3SArunpravin Paneer Selvam */ 733ded910f3SArunpravin Paneer Selvam static bool amdgpu_vram_mgr_intersects(struct ttm_resource_manager *man, 734ded910f3SArunpravin Paneer Selvam struct ttm_resource *res, 735ded910f3SArunpravin Paneer Selvam const struct ttm_place *place, 736ded910f3SArunpravin Paneer Selvam size_t size) 737ded910f3SArunpravin Paneer Selvam { 738ded910f3SArunpravin Paneer Selvam struct amdgpu_vram_mgr_resource *mgr = to_amdgpu_vram_mgr_resource(res); 739ded910f3SArunpravin Paneer Selvam struct drm_buddy_block *block; 740ded910f3SArunpravin Paneer Selvam 741ded910f3SArunpravin Paneer Selvam /* Check each drm buddy block individually */ 742ded910f3SArunpravin Paneer Selvam list_for_each_entry(block, &mgr->blocks, link) { 743ded910f3SArunpravin Paneer Selvam unsigned long fpfn = 744ded910f3SArunpravin Paneer Selvam amdgpu_vram_mgr_block_start(block) >> PAGE_SHIFT; 745ded910f3SArunpravin Paneer Selvam unsigned long lpfn = fpfn + 746ded910f3SArunpravin Paneer Selvam (amdgpu_vram_mgr_block_size(block) >> PAGE_SHIFT); 747ded910f3SArunpravin Paneer Selvam 748ded910f3SArunpravin Paneer Selvam if (place->fpfn < lpfn && 74939dd0cc2SArunpravin Paneer Selvam (!place->lpfn || place->lpfn > fpfn)) 750ded910f3SArunpravin Paneer Selvam return true; 751ded910f3SArunpravin Paneer Selvam } 752ded910f3SArunpravin Paneer Selvam 753ded910f3SArunpravin Paneer Selvam return false; 754ded910f3SArunpravin Paneer Selvam } 755ded910f3SArunpravin Paneer Selvam 756ded910f3SArunpravin Paneer Selvam /** 757ded910f3SArunpravin Paneer Selvam * amdgpu_vram_mgr_compatible - test each drm buddy block for compatibility 758ded910f3SArunpravin Paneer Selvam * 759ded910f3SArunpravin Paneer Selvam * @man: TTM memory type manager 760ded910f3SArunpravin Paneer Selvam * @res: The resource to test 761ded910f3SArunpravin Paneer Selvam * @place: The place to test against 762ded910f3SArunpravin Paneer Selvam * @size: Size of the new allocation 763ded910f3SArunpravin Paneer Selvam * 764ded910f3SArunpravin Paneer Selvam * Test each drm buddy block for placement compatibility. 765ded910f3SArunpravin Paneer Selvam */ 766ded910f3SArunpravin Paneer Selvam static bool amdgpu_vram_mgr_compatible(struct ttm_resource_manager *man, 767ded910f3SArunpravin Paneer Selvam struct ttm_resource *res, 768ded910f3SArunpravin Paneer Selvam const struct ttm_place *place, 769ded910f3SArunpravin Paneer Selvam size_t size) 770ded910f3SArunpravin Paneer Selvam { 771ded910f3SArunpravin Paneer Selvam struct amdgpu_vram_mgr_resource *mgr = to_amdgpu_vram_mgr_resource(res); 772ded910f3SArunpravin Paneer Selvam struct drm_buddy_block *block; 773ded910f3SArunpravin Paneer Selvam 774ded910f3SArunpravin Paneer Selvam /* Check each drm buddy block individually */ 775ded910f3SArunpravin Paneer Selvam list_for_each_entry(block, &mgr->blocks, link) { 776ded910f3SArunpravin Paneer Selvam unsigned long fpfn = 777ded910f3SArunpravin Paneer Selvam amdgpu_vram_mgr_block_start(block) >> PAGE_SHIFT; 778ded910f3SArunpravin Paneer Selvam unsigned long lpfn = fpfn + 779ded910f3SArunpravin Paneer Selvam (amdgpu_vram_mgr_block_size(block) >> PAGE_SHIFT); 780ded910f3SArunpravin Paneer Selvam 781ded910f3SArunpravin Paneer Selvam if (fpfn < place->fpfn || 782ded910f3SArunpravin Paneer Selvam (place->lpfn && lpfn > place->lpfn)) 783ded910f3SArunpravin Paneer Selvam return false; 784ded910f3SArunpravin Paneer Selvam } 785ded910f3SArunpravin Paneer Selvam 786ded910f3SArunpravin Paneer Selvam return true; 787ded910f3SArunpravin Paneer Selvam } 788ded910f3SArunpravin Paneer Selvam 789ded910f3SArunpravin Paneer Selvam /** 7906a7f76e7SChristian König * amdgpu_vram_mgr_debug - dump VRAM table 7916a7f76e7SChristian König * 7926a7f76e7SChristian König * @man: TTM memory type manager 793373533f8SChristian König * @printer: DRM printer to use 7946a7f76e7SChristian König * 7956a7f76e7SChristian König * Dump the table content using printk. 7966a7f76e7SChristian König */ 7979de59bc2SDave Airlie static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man, 798373533f8SChristian König struct drm_printer *printer) 7996a7f76e7SChristian König { 8000af135b8SDave Airlie struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); 801c9cad937SArunpravin Paneer Selvam struct drm_buddy *mm = &mgr->mm; 802c9cad937SArunpravin Paneer Selvam struct drm_buddy_block *block; 8036a7f76e7SChristian König 8047db47b83SChristian König drm_printf(printer, " vis usage:%llu\n", 8057db47b83SChristian König amdgpu_vram_mgr_vis_usage(mgr)); 8067db47b83SChristian König 807c9cad937SArunpravin Paneer Selvam mutex_lock(&mgr->lock); 808c9cad937SArunpravin Paneer Selvam drm_printf(printer, "default_page_size: %lluKiB\n", 809c9cad937SArunpravin Paneer Selvam mgr->default_page_size >> 10); 810c9cad937SArunpravin Paneer Selvam 811c9cad937SArunpravin Paneer Selvam drm_buddy_print(mm, printer); 812c9cad937SArunpravin Paneer Selvam 813c9cad937SArunpravin Paneer Selvam drm_printf(printer, "reserved:\n"); 814c9cad937SArunpravin Paneer Selvam list_for_each_entry(block, &mgr->reserved_pages, link) 815c9cad937SArunpravin Paneer Selvam drm_buddy_block_print(mm, block, printer); 816c9cad937SArunpravin Paneer Selvam mutex_unlock(&mgr->lock); 8176a7f76e7SChristian König } 8186a7f76e7SChristian König 8199de59bc2SDave Airlie static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = { 820e92ae67dSChristian König .alloc = amdgpu_vram_mgr_new, 821e92ae67dSChristian König .free = amdgpu_vram_mgr_del, 822ded910f3SArunpravin Paneer Selvam .intersects = amdgpu_vram_mgr_intersects, 823ded910f3SArunpravin Paneer Selvam .compatible = amdgpu_vram_mgr_compatible, 8242a9d6d26SKees Cook .debug = amdgpu_vram_mgr_debug 8256a7f76e7SChristian König }; 826589939d4SChristian König 827589939d4SChristian König /** 828589939d4SChristian König * amdgpu_vram_mgr_init - init VRAM manager and DRM MM 829589939d4SChristian König * 830589939d4SChristian König * @adev: amdgpu_device pointer 831589939d4SChristian König * 832589939d4SChristian König * Allocate and initialize the VRAM manager. 833589939d4SChristian König */ 834589939d4SChristian König int amdgpu_vram_mgr_init(struct amdgpu_device *adev) 835589939d4SChristian König { 836589939d4SChristian König struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; 837589939d4SChristian König struct ttm_resource_manager *man = &mgr->manager; 838c9cad937SArunpravin Paneer Selvam int err; 839589939d4SChristian König 8403f268ef0SChristian König ttm_resource_manager_init(man, &adev->mman.bdev, 8417db47b83SChristian König adev->gmc.real_vram_size); 842589939d4SChristian König 843589939d4SChristian König man->func = &amdgpu_vram_mgr_func; 844589939d4SChristian König 845c9cad937SArunpravin Paneer Selvam err = drm_buddy_init(&mgr->mm, man->size, PAGE_SIZE); 846c9cad937SArunpravin Paneer Selvam if (err) 847c9cad937SArunpravin Paneer Selvam return err; 848c9cad937SArunpravin Paneer Selvam 849c9cad937SArunpravin Paneer Selvam mutex_init(&mgr->lock); 850589939d4SChristian König INIT_LIST_HEAD(&mgr->reservations_pending); 851589939d4SChristian König INIT_LIST_HEAD(&mgr->reserved_pages); 852c9cad937SArunpravin Paneer Selvam mgr->default_page_size = PAGE_SIZE; 853589939d4SChristian König 854589939d4SChristian König ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager); 855589939d4SChristian König ttm_resource_manager_set_used(man, true); 856589939d4SChristian König return 0; 857589939d4SChristian König } 858589939d4SChristian König 859589939d4SChristian König /** 860589939d4SChristian König * amdgpu_vram_mgr_fini - free and destroy VRAM manager 861589939d4SChristian König * 862589939d4SChristian König * @adev: amdgpu_device pointer 863589939d4SChristian König * 864589939d4SChristian König * Destroy and free the VRAM manager, returns -EBUSY if ranges are still 865589939d4SChristian König * allocated inside it. 866589939d4SChristian König */ 867589939d4SChristian König void amdgpu_vram_mgr_fini(struct amdgpu_device *adev) 868589939d4SChristian König { 869589939d4SChristian König struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; 870589939d4SChristian König struct ttm_resource_manager *man = &mgr->manager; 871589939d4SChristian König int ret; 872589939d4SChristian König struct amdgpu_vram_reservation *rsv, *temp; 873589939d4SChristian König 874589939d4SChristian König ttm_resource_manager_set_used(man, false); 875589939d4SChristian König 876589939d4SChristian König ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man); 877589939d4SChristian König if (ret) 878589939d4SChristian König return; 879589939d4SChristian König 880c9cad937SArunpravin Paneer Selvam mutex_lock(&mgr->lock); 881c9cad937SArunpravin Paneer Selvam list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks) 882589939d4SChristian König kfree(rsv); 883589939d4SChristian König 884c9cad937SArunpravin Paneer Selvam list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) { 885c9cad937SArunpravin Paneer Selvam drm_buddy_free_list(&mgr->mm, &rsv->blocks); 886589939d4SChristian König kfree(rsv); 887589939d4SChristian König } 888c9cad937SArunpravin Paneer Selvam drm_buddy_fini(&mgr->mm); 889c9cad937SArunpravin Paneer Selvam mutex_unlock(&mgr->lock); 890589939d4SChristian König 891589939d4SChristian König ttm_resource_manager_cleanup(man); 892589939d4SChristian König ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, NULL); 893589939d4SChristian König } 894