drm/i915/lmem: add the fake lmem region

Intended for upstream testing so that we can still exercise the LMEM
plumbing and !i915_ggtt_has_aperture paths. Smoke tested on Skull Canyon
device. This works by allocating an intel_memory_region for a reserved
portion of system memory, which we treat like LMEM. For the LMEMBAR we
steal the aperture and 1:1 it map to the stolen region.

To enable simply set the i915 modparam fake_lmem_start= on the kernel
cmdline with the start of reserved region(see memmap=). The size of the
region we can use is determined by the size of the mappable aperture, so
the size of reserved region should be >= mappable_end. For now we only
enable for the selftests. Depends on CONFIG_DRM_I915_UNSTABLE being
enabled.

eg. memmap=2G$16G i915.fake_lmem_start=0x400000000

v2: make fake_lmem_start an i915 modparam

Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
Cc: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20191030173320.8850-1-matthew.auld@intel.com
This commit is contained in:
Matthew Auld 2019-10-30 17:33:20 +00:00 committed by Chris Wilson
parent 4974826482
commit 1629224324
9 changed files with 140 additions and 0 deletions

View File

@ -19,3 +19,11 @@ config DRM_I915_UNSTABLE
Recommended for driver developers _only_. Recommended for driver developers _only_.
If in the slightest bit of doubt, say "N". If in the slightest bit of doubt, say "N".
config DRM_I915_UNSTABLE_FAKE_LMEM
bool "Enable the experimental fake lmem"
depends on DRM_I915_UNSTABLE
default n
help
Convert some system memory into a fake local memory region for
testing.

View File

@ -24,6 +24,7 @@ i915_gem_object_lmem_io_map_page(struct drm_i915_gem_object *obj,
resource_size_t offset; resource_size_t offset;
offset = i915_gem_object_get_dma_address(obj, n); offset = i915_gem_object_get_dma_address(obj, n);
offset -= obj->mm.region->region.start;
return io_mapping_map_wc(&obj->mm.region->iomap, offset, PAGE_SIZE); return io_mapping_map_wc(&obj->mm.region->iomap, offset, PAGE_SIZE);
} }
@ -35,6 +36,7 @@ i915_gem_object_lmem_io_map_page_atomic(struct drm_i915_gem_object *obj,
resource_size_t offset; resource_size_t offset;
offset = i915_gem_object_get_dma_address(obj, n); offset = i915_gem_object_get_dma_address(obj, n);
offset -= obj->mm.region->region.start;
return io_mapping_map_atomic_wc(&obj->mm.region->iomap, offset); return io_mapping_map_atomic_wc(&obj->mm.region->iomap, offset);
} }
@ -49,6 +51,7 @@ i915_gem_object_lmem_io_map(struct drm_i915_gem_object *obj,
GEM_BUG_ON(!i915_gem_object_is_contiguous(obj)); GEM_BUG_ON(!i915_gem_object_is_contiguous(obj));
offset = i915_gem_object_get_dma_address(obj, n); offset = i915_gem_object_get_dma_address(obj, n);
offset -= obj->mm.region->region.start;
return io_mapping_map_wc(&obj->mm.region->iomap, offset, size); return io_mapping_map_wc(&obj->mm.region->iomap, offset, size);
} }

View File

@ -1483,6 +1483,21 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!i915_modparams.nuclear_pageflip && match_info->gen < 5) if (!i915_modparams.nuclear_pageflip && match_info->gen < 5)
dev_priv->drm.driver_features &= ~DRIVER_ATOMIC; dev_priv->drm.driver_features &= ~DRIVER_ATOMIC;
/*
* Check if we support fake LMEM -- for now we only unleash this for
* the live selftests(test-and-exit).
*/
if (IS_ENABLED(CONFIG_DRM_I915_UNSTABLE_FAKE_LMEM)) {
if (INTEL_GEN(dev_priv) >= 9 && i915_selftest.live < 0 &&
i915_modparams.fake_lmem_start) {
mkwrite_device_info(dev_priv)->memory_regions =
REGION_SMEM | REGION_LMEM | REGION_STOLEN;
mkwrite_device_info(dev_priv)->is_dgfx = true;
GEM_BUG_ON(!HAS_LMEM(dev_priv));
GEM_BUG_ON(!IS_DGFX(dev_priv));
}
}
ret = pci_enable_device(pdev); ret = pci_enable_device(pdev);
if (ret) if (ret)
goto out_fini; goto out_fini;

View File

@ -179,6 +179,11 @@ i915_param_named(enable_gvt, bool, 0400,
"Enable support for Intel GVT-g graphics virtualization host support(default:false)"); "Enable support for Intel GVT-g graphics virtualization host support(default:false)");
#endif #endif
#if IS_ENABLED(CONFIG_DRM_I915_UNSTABLE_FAKE_LMEM)
i915_param_named_unsafe(fake_lmem_start, ulong, 0600,
"Fake LMEM start offset (default: 0)");
#endif
static __always_inline void _print_param(struct drm_printer *p, static __always_inline void _print_param(struct drm_printer *p,
const char *name, const char *name,
const char *type, const char *type,
@ -190,6 +195,8 @@ static __always_inline void _print_param(struct drm_printer *p,
drm_printf(p, "i915.%s=%d\n", name, *(const int *)x); drm_printf(p, "i915.%s=%d\n", name, *(const int *)x);
else if (!__builtin_strcmp(type, "unsigned int")) else if (!__builtin_strcmp(type, "unsigned int"))
drm_printf(p, "i915.%s=%u\n", name, *(const unsigned int *)x); drm_printf(p, "i915.%s=%u\n", name, *(const unsigned int *)x);
else if (!__builtin_strcmp(type, "unsigned long"))
drm_printf(p, "i915.%s=%lu\n", name, *(const unsigned long *)x);
else if (!__builtin_strcmp(type, "char *")) else if (!__builtin_strcmp(type, "char *"))
drm_printf(p, "i915.%s=%s\n", name, *(const char **)x); drm_printf(p, "i915.%s=%s\n", name, *(const char **)x);
else else

View File

@ -66,6 +66,7 @@ struct drm_printer;
param(int, fastboot, -1) \ param(int, fastboot, -1) \
param(int, enable_dpcd_backlight, 0) \ param(int, enable_dpcd_backlight, 0) \
param(char *, force_probe, CONFIG_DRM_I915_FORCE_PROBE) \ param(char *, force_probe, CONFIG_DRM_I915_FORCE_PROBE) \
param(unsigned long, fake_lmem_start, 0) \
/* leave bools at the end to not create holes */ \ /* leave bools at the end to not create holes */ \
param(bool, alpha_support, IS_ENABLED(CONFIG_DRM_I915_ALPHA_SUPPORT)) \ param(bool, alpha_support, IS_ENABLED(CONFIG_DRM_I915_ALPHA_SUPPORT)) \
param(bool, enable_hangcheck, true) \ param(bool, enable_hangcheck, true) \

View File

@ -228,6 +228,9 @@ int intel_memory_regions_hw_probe(struct drm_i915_private *i915)
case INTEL_MEMORY_STOLEN: case INTEL_MEMORY_STOLEN:
mem = i915_gem_stolen_setup(i915); mem = i915_gem_stolen_setup(i915);
break; break;
case INTEL_MEMORY_LOCAL:
mem = intel_setup_fake_lmem(i915);
break;
} }
if (IS_ERR(mem)) { if (IS_ERR(mem)) {

View File

@ -10,6 +10,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/io-mapping.h> #include <linux/io-mapping.h>
#include <drm/drm_mm.h>
#include "i915_buddy.h" #include "i915_buddy.h"
@ -71,6 +72,9 @@ struct intel_memory_region {
struct io_mapping iomap; struct io_mapping iomap;
struct resource region; struct resource region;
/* For fake LMEM */
struct drm_mm_node fake_mappable;
struct i915_buddy_mm mm; struct i915_buddy_mm mm;
struct mutex mm_lock; struct mutex mm_lock;
@ -83,6 +87,8 @@ struct intel_memory_region {
unsigned int instance; unsigned int instance;
unsigned int id; unsigned int id;
dma_addr_t remap_addr;
struct { struct {
struct mutex lock; /* Protects access to objects */ struct mutex lock; /* Protects access to objects */
struct list_head list; struct list_head list;

View File

@ -9,9 +9,62 @@
#include "gem/i915_gem_region.h" #include "gem/i915_gem_region.h"
#include "intel_region_lmem.h" #include "intel_region_lmem.h"
static int init_fake_lmem_bar(struct intel_memory_region *mem)
{
struct drm_i915_private *i915 = mem->i915;
struct i915_ggtt *ggtt = &i915->ggtt;
unsigned long n;
int ret;
/* We want to 1:1 map the mappable aperture to our reserved region */
mem->fake_mappable.start = 0;
mem->fake_mappable.size = resource_size(&mem->region);
mem->fake_mappable.color = I915_COLOR_UNEVICTABLE;
ret = drm_mm_reserve_node(&ggtt->vm.mm, &mem->fake_mappable);
if (ret)
return ret;
mem->remap_addr = dma_map_resource(&i915->drm.pdev->dev,
mem->region.start,
mem->fake_mappable.size,
PCI_DMA_BIDIRECTIONAL,
DMA_ATTR_FORCE_CONTIGUOUS);
if (dma_mapping_error(&i915->drm.pdev->dev, mem->remap_addr)) {
drm_mm_remove_node(&mem->fake_mappable);
return -EINVAL;
}
for (n = 0; n < mem->fake_mappable.size >> PAGE_SHIFT; ++n) {
ggtt->vm.insert_page(&ggtt->vm,
mem->remap_addr + (n << PAGE_SHIFT),
n << PAGE_SHIFT,
I915_CACHE_NONE, 0);
}
mem->region = (struct resource)DEFINE_RES_MEM(mem->remap_addr,
mem->fake_mappable.size);
return 0;
}
static void release_fake_lmem_bar(struct intel_memory_region *mem)
{
if (drm_mm_node_allocated(&mem->fake_mappable))
drm_mm_remove_node(&mem->fake_mappable);
dma_unmap_resource(&mem->i915->drm.pdev->dev,
mem->remap_addr,
mem->fake_mappable.size,
PCI_DMA_BIDIRECTIONAL,
DMA_ATTR_FORCE_CONTIGUOUS);
}
static void static void
region_lmem_release(struct intel_memory_region *mem) region_lmem_release(struct intel_memory_region *mem)
{ {
release_fake_lmem_bar(mem);
io_mapping_fini(&mem->iomap); io_mapping_fini(&mem->iomap);
intel_memory_region_release_buddy(mem); intel_memory_region_release_buddy(mem);
} }
@ -21,6 +74,11 @@ region_lmem_init(struct intel_memory_region *mem)
{ {
int ret; int ret;
if (i915_modparams.fake_lmem_start) {
ret = init_fake_lmem_bar(mem);
GEM_BUG_ON(ret);
}
if (!io_mapping_init_wc(&mem->iomap, if (!io_mapping_init_wc(&mem->iomap,
mem->io_start, mem->io_start,
resource_size(&mem->region))) resource_size(&mem->region)))
@ -38,3 +96,37 @@ const struct intel_memory_region_ops intel_region_lmem_ops = {
.release = region_lmem_release, .release = region_lmem_release,
.create_object = __i915_gem_lmem_object_create, .create_object = __i915_gem_lmem_object_create,
}; };
struct intel_memory_region *
intel_setup_fake_lmem(struct drm_i915_private *i915)
{
struct pci_dev *pdev = i915->drm.pdev;
struct intel_memory_region *mem;
resource_size_t mappable_end;
resource_size_t io_start;
resource_size_t start;
GEM_BUG_ON(i915_ggtt_has_aperture(&i915->ggtt));
GEM_BUG_ON(!i915_modparams.fake_lmem_start);
/* Your mappable aperture belongs to me now! */
mappable_end = pci_resource_len(pdev, 2);
io_start = pci_resource_start(pdev, 2),
start = i915_modparams.fake_lmem_start;
mem = intel_memory_region_create(i915,
start,
mappable_end,
PAGE_SIZE,
io_start,
&intel_region_lmem_ops);
if (!IS_ERR(mem)) {
DRM_INFO("Intel graphics fake LMEM: %pR\n", &mem->region);
DRM_INFO("Intel graphics fake LMEM IO start: %llx\n",
(u64)mem->io_start);
DRM_INFO("Intel graphics fake LMEM size: %llx\n",
(u64)resource_size(&mem->region));
}
return mem;
}

View File

@ -6,6 +6,11 @@
#ifndef __INTEL_REGION_LMEM_H #ifndef __INTEL_REGION_LMEM_H
#define __INTEL_REGION_LMEM_H #define __INTEL_REGION_LMEM_H
struct drm_i915_private;
extern const struct intel_memory_region_ops intel_region_lmem_ops; extern const struct intel_memory_region_ops intel_region_lmem_ops;
struct intel_memory_region *
intel_setup_fake_lmem(struct drm_i915_private *i915);
#endif /* !__INTEL_REGION_LMEM_H */ #endif /* !__INTEL_REGION_LMEM_H */