linux/drivers/gpu/drm/i915/gt/intel_region_lmem.c
<<
>>
Prefs
   1// SPDX-License-Identifier: MIT
   2/*
   3 * Copyright © 2019 Intel Corporation
   4 */
   5
   6#include "i915_drv.h"
   7#include "intel_memory_region.h"
   8#include "intel_region_lmem.h"
   9#include "intel_region_ttm.h"
  10#include "gem/i915_gem_lmem.h"
  11#include "gem/i915_gem_region.h"
  12#include "gem/i915_gem_ttm.h"
  13#include "gt/intel_gt.h"
  14
  15static int init_fake_lmem_bar(struct intel_memory_region *mem)
  16{
  17        struct drm_i915_private *i915 = mem->i915;
  18        struct i915_ggtt *ggtt = &i915->ggtt;
  19        unsigned long n;
  20        int ret;
  21
  22        /* We want to 1:1 map the mappable aperture to our reserved region */
  23
  24        mem->fake_mappable.start = 0;
  25        mem->fake_mappable.size = resource_size(&mem->region);
  26        mem->fake_mappable.color = I915_COLOR_UNEVICTABLE;
  27
  28        ret = drm_mm_reserve_node(&ggtt->vm.mm, &mem->fake_mappable);
  29        if (ret)
  30                return ret;
  31
  32        mem->remap_addr = dma_map_resource(i915->drm.dev,
  33                                           mem->region.start,
  34                                           mem->fake_mappable.size,
  35                                           PCI_DMA_BIDIRECTIONAL,
  36                                           DMA_ATTR_FORCE_CONTIGUOUS);
  37        if (dma_mapping_error(i915->drm.dev, mem->remap_addr)) {
  38                drm_mm_remove_node(&mem->fake_mappable);
  39                return -EINVAL;
  40        }
  41
  42        for (n = 0; n < mem->fake_mappable.size >> PAGE_SHIFT; ++n) {
  43                ggtt->vm.insert_page(&ggtt->vm,
  44                                     mem->remap_addr + (n << PAGE_SHIFT),
  45                                     n << PAGE_SHIFT,
  46                                     I915_CACHE_NONE, 0);
  47        }
  48
  49        mem->region = (struct resource)DEFINE_RES_MEM(mem->remap_addr,
  50                                                      mem->fake_mappable.size);
  51
  52        return 0;
  53}
  54
  55static void release_fake_lmem_bar(struct intel_memory_region *mem)
  56{
  57        if (!drm_mm_node_allocated(&mem->fake_mappable))
  58                return;
  59
  60        drm_mm_remove_node(&mem->fake_mappable);
  61
  62        dma_unmap_resource(mem->i915->drm.dev,
  63                           mem->remap_addr,
  64                           mem->fake_mappable.size,
  65                           PCI_DMA_BIDIRECTIONAL,
  66                           DMA_ATTR_FORCE_CONTIGUOUS);
  67}
  68
  69static void
  70region_lmem_release(struct intel_memory_region *mem)
  71{
  72        intel_region_ttm_fini(mem);
  73        io_mapping_fini(&mem->iomap);
  74        release_fake_lmem_bar(mem);
  75}
  76
  77static int
  78region_lmem_init(struct intel_memory_region *mem)
  79{
  80        int ret;
  81
  82        if (mem->i915->params.fake_lmem_start) {
  83                ret = init_fake_lmem_bar(mem);
  84                GEM_BUG_ON(ret);
  85        }
  86
  87        if (!io_mapping_init_wc(&mem->iomap,
  88                                mem->io_start,
  89                                resource_size(&mem->region))) {
  90                ret = -EIO;
  91                goto out_no_io;
  92        }
  93
  94        ret = intel_region_ttm_init(mem);
  95        if (ret)
  96                goto out_no_buddy;
  97
  98        return 0;
  99
 100out_no_buddy:
 101        io_mapping_fini(&mem->iomap);
 102out_no_io:
 103        release_fake_lmem_bar(mem);
 104
 105        return ret;
 106}
 107
 108static const struct intel_memory_region_ops intel_region_lmem_ops = {
 109        .init = region_lmem_init,
 110        .release = region_lmem_release,
 111        .init_object = __i915_gem_ttm_object_init,
 112};
 113
 114struct intel_memory_region *
 115intel_gt_setup_fake_lmem(struct intel_gt *gt)
 116{
 117        struct drm_i915_private *i915 = gt->i915;
 118        struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
 119        struct intel_memory_region *mem;
 120        resource_size_t mappable_end;
 121        resource_size_t io_start;
 122        resource_size_t start;
 123
 124        if (!HAS_LMEM(i915))
 125                return ERR_PTR(-ENODEV);
 126
 127        if (!i915->params.fake_lmem_start)
 128                return ERR_PTR(-ENODEV);
 129
 130        GEM_BUG_ON(i915_ggtt_has_aperture(&i915->ggtt));
 131
 132        /* Your mappable aperture belongs to me now! */
 133        mappable_end = pci_resource_len(pdev, 2);
 134        io_start = pci_resource_start(pdev, 2);
 135        start = i915->params.fake_lmem_start;
 136
 137        mem = intel_memory_region_create(i915,
 138                                         start,
 139                                         mappable_end,
 140                                         PAGE_SIZE,
 141                                         io_start,
 142                                         INTEL_MEMORY_LOCAL,
 143                                         0,
 144                                         &intel_region_lmem_ops);
 145        if (!IS_ERR(mem)) {
 146                drm_info(&i915->drm, "Intel graphics fake LMEM: %pR\n",
 147                         &mem->region);
 148                drm_info(&i915->drm,
 149                         "Intel graphics fake LMEM IO start: %llx\n",
 150                        (u64)mem->io_start);
 151                drm_info(&i915->drm, "Intel graphics fake LMEM size: %llx\n",
 152                         (u64)resource_size(&mem->region));
 153        }
 154
 155        return mem;
 156}
 157
 158static bool get_legacy_lowmem_region(struct intel_uncore *uncore,
 159                                     u64 *start, u32 *size)
 160{
 161        if (!IS_DG1_GT_STEP(uncore->i915, STEP_A0, STEP_C0))
 162                return false;
 163
 164        *start = 0;
 165        *size = SZ_1M;
 166
 167        drm_dbg(&uncore->i915->drm, "LMEM: reserved legacy low-memory [0x%llx-0x%llx]\n",
 168                *start, *start + *size);
 169
 170        return true;
 171}
 172
 173static int reserve_lowmem_region(struct intel_uncore *uncore,
 174                                 struct intel_memory_region *mem)
 175{
 176        u64 reserve_start;
 177        u32 reserve_size;
 178        int ret;
 179
 180        if (!get_legacy_lowmem_region(uncore, &reserve_start, &reserve_size))
 181                return 0;
 182
 183        ret = intel_memory_region_reserve(mem, reserve_start, reserve_size);
 184        if (ret)
 185                drm_err(&uncore->i915->drm, "LMEM: reserving low memory region failed\n");
 186
 187        return ret;
 188}
 189
 190static struct intel_memory_region *setup_lmem(struct intel_gt *gt)
 191{
 192        struct drm_i915_private *i915 = gt->i915;
 193        struct intel_uncore *uncore = gt->uncore;
 194        struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
 195        struct intel_memory_region *mem;
 196        resource_size_t io_start;
 197        resource_size_t lmem_size;
 198        int err;
 199
 200        if (!IS_DGFX(i915))
 201                return ERR_PTR(-ENODEV);
 202
 203        /* Stolen starts from GSMBASE on DG1 */
 204        lmem_size = intel_uncore_read64(uncore, GEN12_GSMBASE);
 205
 206        io_start = pci_resource_start(pdev, 2);
 207        if (GEM_WARN_ON(lmem_size > pci_resource_len(pdev, 2)))
 208                return ERR_PTR(-ENODEV);
 209
 210        mem = intel_memory_region_create(i915,
 211                                         0,
 212                                         lmem_size,
 213                                         I915_GTT_PAGE_SIZE_4K,
 214                                         io_start,
 215                                         INTEL_MEMORY_LOCAL,
 216                                         0,
 217                                         &intel_region_lmem_ops);
 218        if (IS_ERR(mem))
 219                return mem;
 220
 221        err = reserve_lowmem_region(uncore, mem);
 222        if (err)
 223                goto err_region_put;
 224
 225        drm_dbg(&i915->drm, "Local memory: %pR\n", &mem->region);
 226        drm_dbg(&i915->drm, "Local memory IO start: %pa\n",
 227                &mem->io_start);
 228        drm_info(&i915->drm, "Local memory available: %pa\n",
 229                 &lmem_size);
 230
 231        return mem;
 232
 233err_region_put:
 234        intel_memory_region_put(mem);
 235        return ERR_PTR(err);
 236}
 237
 238struct intel_memory_region *intel_gt_setup_lmem(struct intel_gt *gt)
 239{
 240        return setup_lmem(gt);
 241}
 242