1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00
linux/drivers/gpu/drm/ttm/ttm_tt.c
Linus Torvalds db5d28c0bf drm for 6.10-rc1
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
  ...
2024-05-15 09:43:42 -07:00

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);