new drivers: - panthor: ARM Mali/Immortalis CSF-based GPU driver core: - add a CONFIG_DRM_WERROR option - make more headers self-contained - grab resv lock in pin/unpin - fix vmap resv locking - EDID/eDP panel matching - Kconfig cleanups - DT sound bindings - Add SIZE_HINTS property for cursor planes - Add struct drm_edid_product_id and helpers. - Use drm device based logging in more drm functions. - drop seq_file.h from a bunch of places - use drm_edid driver conversions dp: - DP Tunnel documentation - MST read sideband cap - Adaptive sync SDP prep work ttm: - improve placement for TTM BOs in idle/busy handling panic: - Fixes for drm-panic, and option to test it. - Add drm panic to simpledrm, mgag200, imx, ast bridge: - improve init ordering - adv7511: allow GPIO pin sharing - tc358775: add tc358675 support panel: - AUO B120XAN01.0 - Samsung s6e3fa7 - BOE NT116WHM-N44 - CMN N116BCA-EA1, - CrystalClear CMT430B19N00 - Startek KD050HDFIA020-C020A - powertip PH128800T006-ZHC01 - Innolux G121X1-L03 - LG sw43408 - Khadas TS050 V2 - EDO RM69380 OLED - CSOT MNB601LS1-1 amdgpu: - HDCP/ODM/RAS fixes - Devcoredump improvements - Expose VCN activity via sysfs - SMY 13.0.x updates - Enable fast updates on DCN 3.1.4 - Add dclk and vclk reporting on additional devices - Add ACA RAS infrastructure - Implement TLB flush fence - EEPROM handling fixes - SMUIO 14.0.2 support - SMU 14.0.1 Updates - SMU 14.0.2 support - Sync page table freeing with TLB flushes - DML2 refactor - DC debug improvements - DCN 3.5.x Updates - GPU reset fixes - HDP fix for second GFX pipe on GC 10.x - Enable secondary GFX pipe on GC 10.3 - Refactor and clean up BACO/BOCO/BAMACO handling - Remove invalid TTM resource start check - UAF fix in VA IOCTL - GPUVM page fault redirection to secondary IH rings for IH 6.x - Initial support for mapping kernel queues via MES - Fix VRAM memory accounting amdkfd: - MQD handling cleanup - Preemption handling fixes for XCDs - TLB flush fix for GC 9.4.2 - Properly clean up workqueue during module unload - Fix memory leak process create failure - Range check CP bad op exception targets to avoid reporting invalid exceptions to userspace - Fix eviction fence handling - Fix leak in GPU memory allocation failure case - DMABuf import handling fix - Enable SQ watchpoint for gfx10 i915: - Adding new DG2 PCI ID - add context hints for GT frequency - enable only one CCS for compute workloads - new workarounds - Fix UAF on destroy against retire race and remove two earlier partial fixes - Limit the reserved VM space to only the platforms that need it - Fix gt reset with GuC submission is disable - Add and use gt_to_guc() wrapper i915/xe display: - Lunar Lake display enabling, including cdclk and other refactors - BIOS/VBT/opregion related refactor - Digital port related refactor/clean-up - Fix 2s boot time regression on DP panel replay init - Remove duplication on audio enable/disable on SDVO and g4x+ DP - Disable AuxCCS framebuffers if built for Xe - Make crtc disable more atomic - Increase DP idle pattern wait timeout to 2ms - Start using container_of_const() for some extra const safety - Fix Jasper Lake boot freeze - Enable MST mode for 128b/132b single-stream sideband - Enable Adaptive Sync SDP Support for DP - Fix MTL supported DP rates - removal of UHBR13.5 - PLL refactoring - Limit eDP MSO pipe only for display version 20 - More display refactor towards independence from i915 dev_priv - Convert i915/xe fbdev to DRM client - More initial work to make display code more independent from i915 xe: - improved error capture - clean up some uAPI leftovers - devcoredump update - Add BMG mocs table - Handle GSCCS ER interrupt - Implement xe2- and GuC workarounds - struct xe_device cleanup - Hwmon updates - Add LRC parsing for more GPU instruction - Increase VM_BIND number of per-ioctl Ops - drm/xe: Add XE_BO_GGTT_INVALIDATE flag - Initial development for SR-IOV support - Add new PCI IDs to DG2 platform - Move userptr over to start using hmm_range_fault msm: - Switched to generating register header files during build process instead of shipping pre-generated headers - Merged DPU and MDP4 format databases. - DP: - Stop using compat string to distinguish DP and eDP cases - Added support for X Elite platform (X1E80100) - Reworked DP aux/audio support - Added SM6350 DP to the bindings - GPU: - a7xx perfcntr reg fixes - MAINTAINERS updates - a750 devcoredump support radeon: - Silence UBSAN warnings related to flexible arrays nouveau: - move some uAPI objects to uapi headers omapdrm: - console fix ast: - add i2c polling qaic: - add debugfs entries exynos: - fix platform_driver .owner - drop cleanup code mediatek: - Use devm_platform_get_and_ioremap_resource() in mtk_hdmi_ddc_probe() - Add GAMMA 12-bit LUT support for MT8188 - Rename mtk_drm_* to mtk_* - Drop driver owner initialization - Correct calculation formula of PHY Timing -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmZEUU0ACgkQDHTzWXnE hr5qMBAAjUFF0w3YOQMsn0LEAm628kMRHpoVeSXmIfO9z9lTyad30EtiS4ggFgj7 Q/oQ6hHCd5jdsvGSJDgtTTAsTQX+aCkXrgf/18ENbqR5mM3MdefUAPR/zawZ7HR4 8+b2h6p7gHBw8wDjuIvQ5e9InHcnIkKWJc82qnJG5Urgxa05SDh3mu3cosPTJiBw a851vlWaYcxC0yAUwJlWaXDdN8yzdFaSQNboZBS/CMLXF/WE6Ht257uxJmaouc0Y Z0kBybok5x0TPQEXF9IV+kuSW3EYpYcwRi0BFFM9sJjkEBdH3rYRZwuYP1LR+7VZ HKsmIkie8YzCm2VwTquYzUvHgF+swZX4RRch9XJlGz7UvBLc0eBO/2n4X6fNd8Kl QGNNqEfsnUQrAHKvGsOUgoGjSCmEo8voGcMZ3JPIAdJ/GcnJwpMvNxtF6XB08hEu rDxuU6o7WkM4dJbtiaFEHNh0Fmjj6aXdBL23UD9pcqPT1fc9cT3xnUd5RJIRuRwV /tpb2WfkFAoxCkKFiunaC4rE8oG6ME6wr/trYjvoYuhCI5hCVaXRBGzJEtC30IP6 lG2YZ8r0jHjktbgjZ0Cz/hY424H4sxSN9SJAnXXFDzcfjBJ/nOgo5nMD1jKajAD5 SYfqWaD5Y+YygtyLJPMfZQI2XMOpCzteXD8uaNXXFJfpV7Apeyg= =ocVM -----END PGP SIGNATURE----- Merge tag 'drm-next-2024-05-15' of https://gitlab.freedesktop.org/drm/kernel Pull drm updates from Dave Airlie: "This is the main pull request for the drm subsystems for 6.10. In drivers the main thing is a new driver for ARM Mali firmware based GPUs, otherwise there are a lot of changes to amdgpu/xe/i915/msm and scattered changes to everything else. In the core a bunch of headers and Kconfig was refactored, along with the addition of a new panic handler which is meant to provide a user friendly message when a panic happens and graphical display is enabled. New drivers: - panthor: ARM Mali/Immortalis CSF-based GPU driver Core: - add a CONFIG_DRM_WERROR option - make more headers self-contained - grab resv lock in pin/unpin - fix vmap resv locking - EDID/eDP panel matching - Kconfig cleanups - DT sound bindings - Add SIZE_HINTS property for cursor planes - Add struct drm_edid_product_id and helpers. - Use drm device based logging in more drm functions. - drop seq_file.h from a bunch of places - use drm_edid driver conversions dp: - DP Tunnel documentation - MST read sideband cap - Adaptive sync SDP prep work ttm: - improve placement for TTM BOs in idle/busy handling panic: - Fixes for drm-panic, and option to test it. - Add drm panic to simpledrm, mgag200, imx, ast bridge: - improve init ordering - adv7511: allow GPIO pin sharing - tc358775: add tc358675 support panel: - AUO B120XAN01.0 - Samsung s6e3fa7 - BOE NT116WHM-N44 - CMN N116BCA-EA1, - CrystalClear CMT430B19N00 - Startek KD050HDFIA020-C020A - powertip PH128800T006-ZHC01 - Innolux G121X1-L03 - LG sw43408 - Khadas TS050 V2 - EDO RM69380 OLED - CSOT MNB601LS1-1 amdgpu: - HDCP/ODM/RAS fixes - Devcoredump improvements - Expose VCN activity via sysfs - SMY 13.0.x updates - Enable fast updates on DCN 3.1.4 - Add dclk and vclk reporting on additional devices - Add ACA RAS infrastructure - Implement TLB flush fence - EEPROM handling fixes - SMUIO 14.0.2 support - SMU 14.0.1 Updates - SMU 14.0.2 support - Sync page table freeing with TLB flushes - DML2 refactor - DC debug improvements - DCN 3.5.x Updates - GPU reset fixes - HDP fix for second GFX pipe on GC 10.x - Enable secondary GFX pipe on GC 10.3 - Refactor and clean up BACO/BOCO/BAMACO handling - Remove invalid TTM resource start check - UAF fix in VA IOCTL - GPUVM page fault redirection to secondary IH rings for IH 6.x - Initial support for mapping kernel queues via MES - Fix VRAM memory accounting amdkfd: - MQD handling cleanup - Preemption handling fixes for XCDs - TLB flush fix for GC 9.4.2 - Properly clean up workqueue during module unload - Fix memory leak process create failure - Range check CP bad op exception targets to avoid reporting invalid exceptions to userspace - Fix eviction fence handling - Fix leak in GPU memory allocation failure case - DMABuf import handling fix - Enable SQ watchpoint for gfx10 i915: - Adding new DG2 PCI ID - add context hints for GT frequency - enable only one CCS for compute workloads - new workarounds - Fix UAF on destroy against retire race and remove two earlier partial fixes - Limit the reserved VM space to only the platforms that need it - Fix gt reset with GuC submission is disable - Add and use gt_to_guc() wrapper i915/xe display: - Lunar Lake display enabling, including cdclk and other refactors - BIOS/VBT/opregion related refactor - Digital port related refactor/clean-up - Fix 2s boot time regression on DP panel replay init - Remove duplication on audio enable/disable on SDVO and g4x+ DP - Disable AuxCCS framebuffers if built for Xe - Make crtc disable more atomic - Increase DP idle pattern wait timeout to 2ms - Start using container_of_const() for some extra const safety - Fix Jasper Lake boot freeze - Enable MST mode for 128b/132b single-stream sideband - Enable Adaptive Sync SDP Support for DP - Fix MTL supported DP rates - removal of UHBR13.5 - PLL refactoring - Limit eDP MSO pipe only for display version 20 - More display refactor towards independence from i915 dev_priv - Convert i915/xe fbdev to DRM client - More initial work to make display code more independent from i915 xe: - improved error capture - clean up some uAPI leftovers - devcoredump update - Add BMG mocs table - Handle GSCCS ER interrupt - Implement xe2- and GuC workarounds - struct xe_device cleanup - Hwmon updates - Add LRC parsing for more GPU instruction - Increase VM_BIND number of per-ioctl Ops - drm/xe: Add XE_BO_GGTT_INVALIDATE flag - Initial development for SR-IOV support - Add new PCI IDs to DG2 platform - Move userptr over to start using hmm_range_fault msm: - Switched to generating register header files during build process instead of shipping pre-generated headers - Merged DPU and MDP4 format databases. - DP: - Stop using compat string to distinguish DP and eDP cases - Added support for X Elite platform (X1E80100) - Reworked DP aux/audio support - Added SM6350 DP to the bindings - GPU: - a7xx perfcntr reg fixes - MAINTAINERS updates - a750 devcoredump support radeon: - Silence UBSAN warnings related to flexible arrays nouveau: - move some uAPI objects to uapi headers omapdrm: - console fix ast: - add i2c polling qaic: - add debugfs entries exynos: - fix platform_driver .owner - drop cleanup code mediatek: - Use devm_platform_get_and_ioremap_resource() in mtk_hdmi_ddc_probe() - Add GAMMA 12-bit LUT support for MT8188 - Rename mtk_drm_* to mtk_* - Drop driver owner initialization - Correct calculation formula of PHY Timing" * tag 'drm-next-2024-05-15' of https://gitlab.freedesktop.org/drm/kernel: (1477 commits) drm/xe/ads: Use flexible-array drm/xe: Use ordered WQ for G2H handler drm/msm/gen_header: allow skipping the validation drm/msm/a6xx: Cleanup indexed regs const'ness drm/msm: Add devcoredump support for a750 drm/msm: Adjust a7xx GBIF debugbus dumping drm/msm: Update a6xx registers XML drm/msm: Fix imported a750 snapshot header for upstream drm/msm: Import a750 snapshot registers from kgsl MAINTAINERS: Add Konrad Dybcio as a reviewer for the Adreno driver MAINTAINERS: Add a separate entry for Qualcomm Adreno GPU drivers drm/msm/a6xx: Avoid a nullptr dereference when speedbin setting fails drm/msm/adreno: fix CP cycles stat retrieval on a7xx drm/msm/a7xx: allow writing to CP_BV counter selection registers drm: zynqmp_dpsub: Always register bridge Revert "drm/bridge: ti-sn65dsi83: Fix enable error path" drm/fb_dma: Add checks in drm_fb_dma_get_scanout_buffer() drm/fbdev-generic: Do not set physical framebuffer address drm/panthor: Fix the FW reset logic drm/panthor: Make sure we handle 'unknown group state' case properly ...
473 lines
12 KiB
C
473 lines
12 KiB
C
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
|
/**************************************************************************
|
|
*
|
|
* Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
|
|
* All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sub license, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the
|
|
* next paragraph) shall be included in all copies or substantial portions
|
|
* of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
|
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
**************************************************************************/
|
|
/*
|
|
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "[TTM] " fmt
|
|
|
|
#include <linux/cc_platform.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/file.h>
|
|
#include <linux/module.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/shmem_fs.h>
|
|
#include <drm/drm_cache.h>
|
|
#include <drm/drm_device.h>
|
|
#include <drm/drm_util.h>
|
|
#include <drm/ttm/ttm_bo.h>
|
|
#include <drm/ttm/ttm_tt.h>
|
|
|
|
#include "ttm_module.h"
|
|
|
|
static unsigned long ttm_pages_limit;
|
|
|
|
MODULE_PARM_DESC(pages_limit, "Limit for the allocated pages");
|
|
module_param_named(pages_limit, ttm_pages_limit, ulong, 0644);
|
|
|
|
static unsigned long ttm_dma32_pages_limit;
|
|
|
|
MODULE_PARM_DESC(dma32_pages_limit, "Limit for the allocated DMA32 pages");
|
|
module_param_named(dma32_pages_limit, ttm_dma32_pages_limit, ulong, 0644);
|
|
|
|
static atomic_long_t ttm_pages_allocated;
|
|
static atomic_long_t ttm_dma32_pages_allocated;
|
|
|
|
/*
|
|
* Allocates a ttm structure for the given BO.
|
|
*/
|
|
int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc)
|
|
{
|
|
struct ttm_device *bdev = bo->bdev;
|
|
struct drm_device *ddev = bo->base.dev;
|
|
uint32_t page_flags = 0;
|
|
|
|
dma_resv_assert_held(bo->base.resv);
|
|
|
|
if (bo->ttm)
|
|
return 0;
|
|
|
|
switch (bo->type) {
|
|
case ttm_bo_type_device:
|
|
if (zero_alloc)
|
|
page_flags |= TTM_TT_FLAG_ZERO_ALLOC;
|
|
break;
|
|
case ttm_bo_type_kernel:
|
|
break;
|
|
case ttm_bo_type_sg:
|
|
page_flags |= TTM_TT_FLAG_EXTERNAL;
|
|
break;
|
|
default:
|
|
pr_err("Illegal buffer object type\n");
|
|
return -EINVAL;
|
|
}
|
|
/*
|
|
* When using dma_alloc_coherent with memory encryption the
|
|
* mapped TT pages need to be decrypted or otherwise the drivers
|
|
* will end up sending encrypted mem to the gpu.
|
|
*/
|
|
if (bdev->pool.use_dma_alloc && cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
|
|
page_flags |= TTM_TT_FLAG_DECRYPTED;
|
|
drm_info_once(ddev, "TT memory decryption enabled.");
|
|
}
|
|
|
|
bo->ttm = bdev->funcs->ttm_tt_create(bo, page_flags);
|
|
if (unlikely(bo->ttm == NULL))
|
|
return -ENOMEM;
|
|
|
|
WARN_ON(bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL_MAPPABLE &&
|
|
!(bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL));
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_create);
|
|
|
|
/*
|
|
* Allocates storage for pointers to the pages that back the ttm.
|
|
*/
|
|
static int ttm_tt_alloc_page_directory(struct ttm_tt *ttm)
|
|
{
|
|
ttm->pages = kvcalloc(ttm->num_pages, sizeof(void*), GFP_KERNEL);
|
|
if (!ttm->pages)
|
|
return -ENOMEM;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ttm_dma_tt_alloc_page_directory(struct ttm_tt *ttm)
|
|
{
|
|
ttm->pages = kvcalloc(ttm->num_pages, sizeof(*ttm->pages) +
|
|
sizeof(*ttm->dma_address), GFP_KERNEL);
|
|
if (!ttm->pages)
|
|
return -ENOMEM;
|
|
|
|
ttm->dma_address = (void *)(ttm->pages + ttm->num_pages);
|
|
return 0;
|
|
}
|
|
|
|
static int ttm_sg_tt_alloc_page_directory(struct ttm_tt *ttm)
|
|
{
|
|
ttm->dma_address = kvcalloc(ttm->num_pages, sizeof(*ttm->dma_address),
|
|
GFP_KERNEL);
|
|
if (!ttm->dma_address)
|
|
return -ENOMEM;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
|
|
{
|
|
bdev->funcs->ttm_tt_destroy(bdev, ttm);
|
|
}
|
|
EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_destroy);
|
|
|
|
static void ttm_tt_init_fields(struct ttm_tt *ttm,
|
|
struct ttm_buffer_object *bo,
|
|
uint32_t page_flags,
|
|
enum ttm_caching caching,
|
|
unsigned long extra_pages)
|
|
{
|
|
ttm->num_pages = (PAGE_ALIGN(bo->base.size) >> PAGE_SHIFT) + extra_pages;
|
|
ttm->page_flags = page_flags;
|
|
ttm->dma_address = NULL;
|
|
ttm->swap_storage = NULL;
|
|
ttm->sg = bo->sg;
|
|
ttm->caching = caching;
|
|
}
|
|
|
|
int ttm_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo,
|
|
uint32_t page_flags, enum ttm_caching caching,
|
|
unsigned long extra_pages)
|
|
{
|
|
ttm_tt_init_fields(ttm, bo, page_flags, caching, extra_pages);
|
|
|
|
if (ttm_tt_alloc_page_directory(ttm)) {
|
|
pr_err("Failed allocating page table\n");
|
|
return -ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(ttm_tt_init);
|
|
|
|
void ttm_tt_fini(struct ttm_tt *ttm)
|
|
{
|
|
WARN_ON(ttm->page_flags & TTM_TT_FLAG_PRIV_POPULATED);
|
|
|
|
if (ttm->swap_storage)
|
|
fput(ttm->swap_storage);
|
|
ttm->swap_storage = NULL;
|
|
|
|
if (ttm->pages)
|
|
kvfree(ttm->pages);
|
|
else
|
|
kvfree(ttm->dma_address);
|
|
ttm->pages = NULL;
|
|
ttm->dma_address = NULL;
|
|
}
|
|
EXPORT_SYMBOL(ttm_tt_fini);
|
|
|
|
int ttm_sg_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo,
|
|
uint32_t page_flags, enum ttm_caching caching)
|
|
{
|
|
int ret;
|
|
|
|
ttm_tt_init_fields(ttm, bo, page_flags, caching, 0);
|
|
|
|
if (page_flags & TTM_TT_FLAG_EXTERNAL)
|
|
ret = ttm_sg_tt_alloc_page_directory(ttm);
|
|
else
|
|
ret = ttm_dma_tt_alloc_page_directory(ttm);
|
|
if (ret) {
|
|
pr_err("Failed allocating page table\n");
|
|
return -ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(ttm_sg_tt_init);
|
|
|
|
int ttm_tt_swapin(struct ttm_tt *ttm)
|
|
{
|
|
struct address_space *swap_space;
|
|
struct file *swap_storage;
|
|
struct page *from_page;
|
|
struct page *to_page;
|
|
gfp_t gfp_mask;
|
|
int i, ret;
|
|
|
|
swap_storage = ttm->swap_storage;
|
|
BUG_ON(swap_storage == NULL);
|
|
|
|
swap_space = swap_storage->f_mapping;
|
|
gfp_mask = mapping_gfp_mask(swap_space);
|
|
|
|
for (i = 0; i < ttm->num_pages; ++i) {
|
|
from_page = shmem_read_mapping_page_gfp(swap_space, i,
|
|
gfp_mask);
|
|
if (IS_ERR(from_page)) {
|
|
ret = PTR_ERR(from_page);
|
|
goto out_err;
|
|
}
|
|
to_page = ttm->pages[i];
|
|
if (unlikely(to_page == NULL)) {
|
|
ret = -ENOMEM;
|
|
goto out_err;
|
|
}
|
|
|
|
copy_highpage(to_page, from_page);
|
|
put_page(from_page);
|
|
}
|
|
|
|
fput(swap_storage);
|
|
ttm->swap_storage = NULL;
|
|
ttm->page_flags &= ~TTM_TT_FLAG_SWAPPED;
|
|
|
|
return 0;
|
|
|
|
out_err:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* ttm_tt_swapout - swap out tt object
|
|
*
|
|
* @bdev: TTM device structure.
|
|
* @ttm: The struct ttm_tt.
|
|
* @gfp_flags: Flags to use for memory allocation.
|
|
*
|
|
* Swapout a TT object to a shmem_file, return number of pages swapped out or
|
|
* negative error code.
|
|
*/
|
|
int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm,
|
|
gfp_t gfp_flags)
|
|
{
|
|
loff_t size = (loff_t)ttm->num_pages << PAGE_SHIFT;
|
|
struct address_space *swap_space;
|
|
struct file *swap_storage;
|
|
struct page *from_page;
|
|
struct page *to_page;
|
|
int i, ret;
|
|
|
|
swap_storage = shmem_file_setup("ttm swap", size, 0);
|
|
if (IS_ERR(swap_storage)) {
|
|
pr_err("Failed allocating swap storage\n");
|
|
return PTR_ERR(swap_storage);
|
|
}
|
|
|
|
swap_space = swap_storage->f_mapping;
|
|
gfp_flags &= mapping_gfp_mask(swap_space);
|
|
|
|
for (i = 0; i < ttm->num_pages; ++i) {
|
|
from_page = ttm->pages[i];
|
|
if (unlikely(from_page == NULL))
|
|
continue;
|
|
|
|
to_page = shmem_read_mapping_page_gfp(swap_space, i, gfp_flags);
|
|
if (IS_ERR(to_page)) {
|
|
ret = PTR_ERR(to_page);
|
|
goto out_err;
|
|
}
|
|
copy_highpage(to_page, from_page);
|
|
set_page_dirty(to_page);
|
|
mark_page_accessed(to_page);
|
|
put_page(to_page);
|
|
}
|
|
|
|
ttm_tt_unpopulate(bdev, ttm);
|
|
ttm->swap_storage = swap_storage;
|
|
ttm->page_flags |= TTM_TT_FLAG_SWAPPED;
|
|
|
|
return ttm->num_pages;
|
|
|
|
out_err:
|
|
fput(swap_storage);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ttm_tt_populate(struct ttm_device *bdev,
|
|
struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
|
|
{
|
|
int ret;
|
|
|
|
if (!ttm)
|
|
return -EINVAL;
|
|
|
|
if (ttm_tt_is_populated(ttm))
|
|
return 0;
|
|
|
|
if (!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL)) {
|
|
atomic_long_add(ttm->num_pages, &ttm_pages_allocated);
|
|
if (bdev->pool.use_dma32)
|
|
atomic_long_add(ttm->num_pages,
|
|
&ttm_dma32_pages_allocated);
|
|
}
|
|
|
|
while (atomic_long_read(&ttm_pages_allocated) > ttm_pages_limit ||
|
|
atomic_long_read(&ttm_dma32_pages_allocated) >
|
|
ttm_dma32_pages_limit) {
|
|
|
|
ret = ttm_global_swapout(ctx, GFP_KERNEL);
|
|
if (ret == 0)
|
|
break;
|
|
if (ret < 0)
|
|
goto error;
|
|
}
|
|
|
|
if (bdev->funcs->ttm_tt_populate)
|
|
ret = bdev->funcs->ttm_tt_populate(bdev, ttm, ctx);
|
|
else
|
|
ret = ttm_pool_alloc(&bdev->pool, ttm, ctx);
|
|
if (ret)
|
|
goto error;
|
|
|
|
ttm->page_flags |= TTM_TT_FLAG_PRIV_POPULATED;
|
|
if (unlikely(ttm->page_flags & TTM_TT_FLAG_SWAPPED)) {
|
|
ret = ttm_tt_swapin(ttm);
|
|
if (unlikely(ret != 0)) {
|
|
ttm_tt_unpopulate(bdev, ttm);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
error:
|
|
if (!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL)) {
|
|
atomic_long_sub(ttm->num_pages, &ttm_pages_allocated);
|
|
if (bdev->pool.use_dma32)
|
|
atomic_long_sub(ttm->num_pages,
|
|
&ttm_dma32_pages_allocated);
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(ttm_tt_populate);
|
|
|
|
void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm)
|
|
{
|
|
if (!ttm_tt_is_populated(ttm))
|
|
return;
|
|
|
|
if (bdev->funcs->ttm_tt_unpopulate)
|
|
bdev->funcs->ttm_tt_unpopulate(bdev, ttm);
|
|
else
|
|
ttm_pool_free(&bdev->pool, ttm);
|
|
|
|
if (!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL)) {
|
|
atomic_long_sub(ttm->num_pages, &ttm_pages_allocated);
|
|
if (bdev->pool.use_dma32)
|
|
atomic_long_sub(ttm->num_pages,
|
|
&ttm_dma32_pages_allocated);
|
|
}
|
|
|
|
ttm->page_flags &= ~TTM_TT_FLAG_PRIV_POPULATED;
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
/* Test the shrinker functions and dump the result */
|
|
static int ttm_tt_debugfs_shrink_show(struct seq_file *m, void *data)
|
|
{
|
|
struct ttm_operation_ctx ctx = { false, false };
|
|
|
|
seq_printf(m, "%d\n", ttm_global_swapout(&ctx, GFP_KERNEL));
|
|
return 0;
|
|
}
|
|
DEFINE_SHOW_ATTRIBUTE(ttm_tt_debugfs_shrink);
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
* ttm_tt_mgr_init - register with the MM shrinker
|
|
*
|
|
* Register with the MM shrinker for swapping out BOs.
|
|
*/
|
|
void ttm_tt_mgr_init(unsigned long num_pages, unsigned long num_dma32_pages)
|
|
{
|
|
#ifdef CONFIG_DEBUG_FS
|
|
debugfs_create_file("tt_shrink", 0400, ttm_debugfs_root, NULL,
|
|
&ttm_tt_debugfs_shrink_fops);
|
|
#endif
|
|
|
|
if (!ttm_pages_limit)
|
|
ttm_pages_limit = num_pages;
|
|
|
|
if (!ttm_dma32_pages_limit)
|
|
ttm_dma32_pages_limit = num_dma32_pages;
|
|
}
|
|
|
|
static void ttm_kmap_iter_tt_map_local(struct ttm_kmap_iter *iter,
|
|
struct iosys_map *dmap,
|
|
pgoff_t i)
|
|
{
|
|
struct ttm_kmap_iter_tt *iter_tt =
|
|
container_of(iter, typeof(*iter_tt), base);
|
|
|
|
iosys_map_set_vaddr(dmap, kmap_local_page_prot(iter_tt->tt->pages[i],
|
|
iter_tt->prot));
|
|
}
|
|
|
|
static void ttm_kmap_iter_tt_unmap_local(struct ttm_kmap_iter *iter,
|
|
struct iosys_map *map)
|
|
{
|
|
kunmap_local(map->vaddr);
|
|
}
|
|
|
|
static const struct ttm_kmap_iter_ops ttm_kmap_iter_tt_ops = {
|
|
.map_local = ttm_kmap_iter_tt_map_local,
|
|
.unmap_local = ttm_kmap_iter_tt_unmap_local,
|
|
.maps_tt = true,
|
|
};
|
|
|
|
/**
|
|
* ttm_kmap_iter_tt_init - Initialize a struct ttm_kmap_iter_tt
|
|
* @iter_tt: The struct ttm_kmap_iter_tt to initialize.
|
|
* @tt: Struct ttm_tt holding page pointers of the struct ttm_resource.
|
|
*
|
|
* Return: Pointer to the embedded struct ttm_kmap_iter.
|
|
*/
|
|
struct ttm_kmap_iter *
|
|
ttm_kmap_iter_tt_init(struct ttm_kmap_iter_tt *iter_tt,
|
|
struct ttm_tt *tt)
|
|
{
|
|
iter_tt->base.ops = &ttm_kmap_iter_tt_ops;
|
|
iter_tt->tt = tt;
|
|
if (tt)
|
|
iter_tt->prot = ttm_prot_from_caching(tt->caching, PAGE_KERNEL);
|
|
else
|
|
iter_tt->prot = PAGE_KERNEL;
|
|
|
|
return &iter_tt->base;
|
|
}
|
|
EXPORT_SYMBOL(ttm_kmap_iter_tt_init);
|
|
|
|
unsigned long ttm_tt_pages_limit(void)
|
|
{
|
|
return ttm_pages_limit;
|
|
}
|
|
EXPORT_SYMBOL(ttm_tt_pages_limit);
|