Skip to content

Commit 2e21de9

Browse files
ickleramalingamc
authored andcommitted
drm/i915: Sanitycheck device iomem on probe
As we setup the memory regions for the device, give each a quick test to verify that we can read and write to the full iomem range. This ensures that our physical addressing for the device's memory is correct, and some reassurance that the memory is functional. v2: wrapper for memtest [Chris] v3: Removed the unused ptr i915 [Chris] v4: used the %pa for the resource_size_t. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.auld@intel.com> Signed-off-by: Ramalingam C <ramalingam.c@intel.com> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20211209162620.5218-1-ramalingam.c@intel.com
1 parent 0ef42fb commit 2e21de9

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

drivers/gpu/drm/i915/intel_memory_region.c

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Copyright © 2019 Intel Corporation
44
*/
55

6+
#include <linux/prandom.h>
7+
68
#include "intel_memory_region.h"
79
#include "i915_drv.h"
810
#include "i915_ttm_buddy_manager.h"
@@ -29,6 +31,99 @@ static const struct {
2931
},
3032
};
3133

34+
static int __iopagetest(struct intel_memory_region *mem,
35+
u8 __iomem *va, int pagesize,
36+
u8 value, resource_size_t offset,
37+
const void *caller)
38+
{
39+
int byte = prandom_u32_max(pagesize);
40+
u8 result[3];
41+
42+
memset_io(va, value, pagesize); /* or GPF! */
43+
wmb();
44+
45+
result[0] = ioread8(va);
46+
result[1] = ioread8(va + byte);
47+
result[2] = ioread8(va + pagesize - 1);
48+
if (memchr_inv(result, value, sizeof(result))) {
49+
dev_err(mem->i915->drm.dev,
50+
"Failed to read back from memory region:%pR at [%pa + %pa] for %ps; wrote %x, read (%x, %x, %x)\n",
51+
&mem->region, &mem->io_start, &offset, caller,
52+
value, result[0], result[1], result[2]);
53+
return -EINVAL;
54+
}
55+
56+
return 0;
57+
}
58+
59+
static int iopagetest(struct intel_memory_region *mem,
60+
resource_size_t offset,
61+
const void *caller)
62+
{
63+
const u8 val[] = { 0x0, 0xa5, 0xc3, 0xf0 };
64+
void __iomem *va;
65+
int err;
66+
int i;
67+
68+
va = ioremap_wc(mem->io_start + offset, PAGE_SIZE);
69+
if (!va) {
70+
dev_err(mem->i915->drm.dev,
71+
"Failed to ioremap memory region [%pa + %pa] for %ps\n",
72+
&mem->io_start, &offset, caller);
73+
return -EFAULT;
74+
}
75+
76+
for (i = 0; i < ARRAY_SIZE(val); i++) {
77+
err = __iopagetest(mem, va, PAGE_SIZE, val[i], offset, caller);
78+
if (err)
79+
break;
80+
81+
err = __iopagetest(mem, va, PAGE_SIZE, ~val[i], offset, caller);
82+
if (err)
83+
break;
84+
}
85+
86+
iounmap(va);
87+
return err;
88+
}
89+
90+
static resource_size_t random_page(resource_size_t last)
91+
{
92+
/* Limited to low 44b (16TiB), but should suffice for a spot check */
93+
return prandom_u32_max(last >> PAGE_SHIFT) << PAGE_SHIFT;
94+
}
95+
96+
static int iomemtest(struct intel_memory_region *mem, const void *caller)
97+
{
98+
resource_size_t last = resource_size(&mem->region) - PAGE_SIZE;
99+
int err;
100+
101+
/*
102+
* Quick test to check read/write access to the iomap (backing store).
103+
*
104+
* Write a byte, read it back. If the iomapping fails, we expect
105+
* a GPF preventing further execution. If the backing store does not
106+
* exist, the read back will return garbage. We check a couple of pages,
107+
* the first and last of the specified region to confirm the backing
108+
* store + iomap does cover the entire memory region; and we check
109+
* a random offset within as a quick spot check for bad memory.
110+
*/
111+
112+
err = iopagetest(mem, 0, caller);
113+
if (err)
114+
return err;
115+
116+
err = iopagetest(mem, last, caller);
117+
if (err)
118+
return err;
119+
120+
err = iopagetest(mem, random_page(last), caller);
121+
if (err)
122+
return err;
123+
124+
return 0;
125+
}
126+
32127
struct intel_memory_region *
33128
intel_memory_region_lookup(struct drm_i915_private *i915,
34129
u16 class, u16 instance)
@@ -90,6 +185,20 @@ void intel_memory_region_debug(struct intel_memory_region *mr,
90185
&mr->total, &mr->avail);
91186
}
92187

188+
static int intel_memory_region_memtest(struct intel_memory_region *mem,
189+
void *caller)
190+
{
191+
int err = 0;
192+
193+
if (!mem->io_start)
194+
return 0;
195+
196+
if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
197+
err = iomemtest(mem, caller);
198+
199+
return err;
200+
}
201+
93202
struct intel_memory_region *
94203
intel_memory_region_create(struct drm_i915_private *i915,
95204
resource_size_t start,
@@ -126,8 +235,15 @@ intel_memory_region_create(struct drm_i915_private *i915,
126235
goto err_free;
127236
}
128237

238+
err = intel_memory_region_memtest(mem, (void *)_RET_IP_);
239+
if (err)
240+
goto err_release;
241+
129242
return mem;
130243

244+
err_release:
245+
if (mem->ops->release)
246+
mem->ops->release(mem);
131247
err_free:
132248
kfree(mem);
133249
return ERR_PTR(err);

0 commit comments

Comments
 (0)