diff mbox

[v10,5/5] drm/i915/selftests: Introduce live tests of private PAT management

Message ID 1504947190-22680-5-git-send-email-zhi.a.wang@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Wang, Zhi A Sept. 9, 2017, 8:53 a.m. UTC
Introduce two live tests of private PAT management:

igt_ppat_init - This test is to check if all the PPAT configurations are
written into HW.

igt_ppat_get - This test performs several sub-tests on intel_ppat_get()
and intel_ppat_put().

The "perfect match" test case will try to get a PPAT entry with an existing
value, then check if the returned PPAT entry is the same one.

The "alloc entries" test case will run out of PPAT table, and check if all
the requested values are put into the newly allocated PPAT entries.

The negative test case will try to generate a new PPAT value, and get it
when PPAT table is full.

The "partial match" test case will generate a parital matched value from
the existing PPAT table and try to match it.

The "re-alloc" test case will try to free and then allocate a new entry
when the PPAT table is full.

The "put entries" test case will free all the PPAT entries that allocated
in "alloc entries" test case. It will check if the values of freed PPAT
entries turn into ppat->clear_value.

v10:

- Refine code structure.
- Introduce "re-alloc" test case. (Chris)

v9:

- Refine generate_new_value(). (Chris)
- Refine failure output. (Chris)
- Refine test flow of "perfect match". (Chris)
- Introduce another negative test case after "partial match". (Chris)

v8:

- Remove noisy output. (Chris)
- Add negative test case. (Chris)

Cc: Ben Widawsky <benjamin.widawsky@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 378 ++++++++++++++++++++++++++
 1 file changed, 378 insertions(+)

Comments

kernel test robot Sept. 13, 2017, 5:37 p.m. UTC | #1
Hi Zhi,

[auto build test ERROR on drm-intel/for-linux-next]
[also build test ERROR on next-20170913]
[cannot apply to v4.13]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Zhi-Wang/drm-i915-Factor-out-setup_private_pat/20170912-152713
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: x86_64-randconfig-a0-09140023 (attached as .config)
compiler: gcc-4.4 (Debian 4.4.7-8) 4.4.7
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All errors (new ones prefixed by >>):

   cc1: warnings being treated as errors
   drivers/gpu/drm/i915/i915_gem_gtt.c: In function 'intel_ppat_get':
   drivers/gpu/drm/i915/i915_gem_gtt.c:2791: error: 'entry' may be used uninitialized in this function
   In file included from drivers/gpu/drm/i915/i915_gem_gtt.c:3767:
   drivers/gpu/drm/i915/selftests/i915_gem_gtt.c: In function 'igt_ppat_get':
>> drivers/gpu/drm/i915/selftests/i915_gem_gtt.c:1365: error: 'entry' may be used uninitialized in this function
   drivers/gpu/drm/i915/i915_gem_gtt.c: In function 'gen8_ppgtt_insert_4lvl':
   drivers/gpu/drm/i915/i915_gem_gtt.c:938: error: 'iter.sg' is used uninitialized in this function
   drivers/gpu/drm/i915/i915_gem_gtt.c:939: error: 'iter.dma' is used uninitialized in this function
   drivers/gpu/drm/i915/i915_gem_gtt.c: In function 'gen8_ppgtt_insert_3lvl':
   drivers/gpu/drm/i915/i915_gem_gtt.c:921: error: 'iter.sg' is used uninitialized in this function
   drivers/gpu/drm/i915/i915_gem_gtt.c:922: error: 'iter.dma' is used uninitialized in this function

vim +/entry +1365 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c

  1359	
  1360	static int igt_ppat_get(void *arg)
  1361	{
  1362		struct drm_i915_private *i915 = arg;
  1363		struct intel_ppat *ppat = &i915->ppat;
  1364		const struct intel_ppat_entry **entries, **p;
> 1365		const struct intel_ppat_entry *entry;
  1366		unsigned int size = 0;
  1367		int i, ret;
  1368	
  1369		if (!ppat->max_entries)
  1370			return 0;
  1371	
  1372		ret = igt_ppat_check(i915);
  1373		if (ret)
  1374			return ret;
  1375	
  1376		/* case 1: perfect match */
  1377		ret = perform_perfect_match_test(ppat);
  1378		if (ret) {
  1379			pr_err("fail on perfect match test\n");
  1380			return ret;
  1381		}
  1382	
  1383		/* case 2: alloc new entries */
  1384		entries = NULL;
  1385		ret = 0;
  1386	
  1387		while (!bitmap_full(ppat->used, ppat->max_entries)) {
  1388			p = krealloc(entries, (size + 1) *
  1389					   sizeof(struct intel_ppat_entry *),
  1390					   GFP_KERNEL);
  1391			if (!p) {
  1392				ret = -ENOMEM;
  1393				goto ppat_put;
  1394			}
  1395	
  1396			entries = p;
  1397	
  1398			p = &entries[size++];
  1399			*p = NULL;
  1400	
  1401			entry = generate_and_check_new_value(ppat);
  1402			if (IS_ERR(entry)) {
  1403				ret = PTR_ERR(entry);
  1404				pr_err("fail on alloc new entries test\n");
  1405				goto ppat_put;
  1406			}
  1407			*p = entry;
  1408		}
  1409	
  1410		/* case 3: negative test 1, suppose PPAT table is full now */
  1411		ret = perform_negative_test(ppat);
  1412		if (ret) {
  1413			pr_err("fail on negative test 1\n");
  1414			goto ppat_put;
  1415		}
  1416	
  1417		/* case 4: partial match */
  1418		ret = perform_partial_match_test(ppat);
  1419		if (ret) {
  1420			pr_err("fail on partial match test\n");
  1421			goto ppat_put;
  1422		}
  1423	
  1424		/* case 3: negative test 2, suppose PPAT table is still full now */
  1425		ret = perform_negative_test(ppat);
  1426		if (ret) {
  1427			pr_err("fail on negative test 2\n");
  1428			goto ppat_put;
  1429		}
  1430	
  1431		/* case 5: re-alloc test, make a hole and it should work again */
  1432		if (entries) {
  1433			for(i = 0; i < size; i++) {
  1434				entry = entries[i];
  1435	
  1436				ret = put_and_check_entry(entry);
  1437				entries[i] = NULL;
  1438				if (ret) {
  1439					pr_err("fail on re-alloc test\n");
  1440					goto ppat_put;
  1441				}
  1442	
  1443				entry = generate_and_check_new_value(ppat);
  1444				if (IS_ERR(entry)) {
  1445					ret = PTR_ERR(entry);
  1446					pr_err("fail on re-alloc test\n");
  1447					goto ppat_put;
  1448				}
  1449				entries[i] = entry;
  1450			}
  1451		}
  1452	
  1453	ppat_put:
  1454		if (entries) {
  1455			for (i = 0; i < size; i++) {
  1456				if (IS_ERR(entries[i]) || !entries[i])
  1457					continue;
  1458	
  1459				if (ret)
  1460					intel_ppat_put(entry);
  1461				else
  1462					ret = put_and_check_entry(entries[i]);
  1463			}
  1464			kfree(entries);
  1465			entries = NULL;
  1466		}
  1467		if (ret)
  1468			return ret;
  1469	
  1470		return igt_ppat_check(i915);
  1471	}
  1472	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index 6b132ca..88c87ac 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -1094,6 +1094,382 @@  static int igt_ggtt_page(void *arg)
 	return err;
 }
 
+static int check_cnl_ppat(struct drm_i915_private *dev_priv)
+{
+	struct intel_ppat *ppat = &dev_priv->ppat;
+	int i;
+
+	for (i = 0; i < ppat->max_entries; i++) {
+		u32 value = I915_READ(GEN10_PAT_INDEX(i));
+
+		if (value != ppat->entries[i].value) {
+			pr_err("check PPAT failed: expected %x found %x\n",
+			       ppat->entries[i].value, value);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int check_bdw_ppat(struct drm_i915_private *dev_priv)
+{
+	struct intel_ppat *ppat = &dev_priv->ppat;
+	u64 pat, hw_pat;
+	int i;
+
+	pat = hw_pat = 0;
+
+	for (i = 0; i < ppat->max_entries; i++)
+		pat |= GEN8_PPAT(i, ppat->entries[i].value);
+
+	hw_pat = I915_READ(GEN8_PRIVATE_PAT_HI);
+	hw_pat <<= 32;
+	hw_pat |= I915_READ(GEN8_PRIVATE_PAT_LO);
+
+	if (pat != hw_pat) {
+		pr_err("check PPAT failed: expected %llx found %llx\n",
+		        pat, hw_pat);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int igt_ppat_check(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	int ret;
+
+	if (!i915->ppat.max_entries)
+		return 0;
+
+	if (INTEL_GEN(i915) >= 10)
+		ret = check_cnl_ppat(i915);
+	else
+		ret = check_bdw_ppat(i915);
+
+	if (ret)
+		pr_err("check PPAT failed\n");
+
+	return ret;
+}
+
+static bool value_is_new(struct intel_ppat *ppat, u8 value)
+{
+	int i;
+
+	for_each_set_bit(i, ppat->used, ppat->max_entries) {
+		if (value != ppat->entries[i].value)
+			continue;
+
+		return false;
+	}
+	return true;
+}
+
+static bool value_for_partial_test(struct intel_ppat *ppat, u8 value)
+{
+	int i;
+
+	if (!value_is_new(ppat, value))
+		return false;
+
+	/*
+	 * At least, there should be one entry whose cache attribute is
+	 * same with the required value.
+	 */
+	for_each_set_bit(i, ppat->used, ppat->max_entries) {
+		if (GEN8_PPAT_GET_CA(value) !=
+		    GEN8_PPAT_GET_CA(ppat->entries[i].value))
+			continue;
+
+		return true;
+	}
+	return false;
+}
+
+static bool value_for_negative_test(struct intel_ppat *ppat, u8 value)
+{
+	int i;
+
+	if (!value_is_new(ppat, value))
+		return false;
+
+	/*
+	 * cache attribute has to be different, so i915_ppat_get() would
+	 * allocate a new entry.
+	 */
+	for_each_set_bit(i, ppat->used, ppat->max_entries) {
+		if (GEN8_PPAT_GET_CA(value) ==
+		    GEN8_PPAT_GET_CA(ppat->entries[i].value))
+			return false;
+	}
+	return true;
+}
+
+static u8 generate_new_value(struct intel_ppat *ppat,
+			     bool (*check_value)(struct intel_ppat *, u8))
+{
+	u8 ca[] = { GEN8_PPAT_WB, GEN8_PPAT_WT, GEN8_PPAT_UC, GEN8_PPAT_WC };
+	u8 tc[] = { GEN8_PPAT_LLC, GEN8_PPAT_LLCELLC, GEN8_PPAT_LLCeLLC };
+	u8 age[] = { GEN8_PPAT_AGE(3), GEN8_PPAT_AGE(2), GEN8_PPAT_AGE(1),
+		     GEN8_PPAT_AGE(0) };
+	int ca_index, tc_index, age_index;
+	u8 value;
+
+#define for_each_ppat_attr(ca_index, tc_index, age_index) \
+	for ((ca_index) = 0 ; (ca_index) < ARRAY_SIZE(ca); (ca_index)++) \
+	for ((tc_index) = 0; (tc_index) < ARRAY_SIZE(tc); (tc_index)++) \
+	for ((age_index) = 0; (age_index) < ARRAY_SIZE(age); (age_index)++)
+
+	for_each_ppat_attr(ca_index, tc_index, age_index) {
+		value = age[age_index] | ca[ca_index] | tc[tc_index];
+		if (check_value(ppat, value))
+			return value;
+	}
+#undef for_each_ppat_attr
+	return 0;
+}
+
+static const struct intel_ppat_entry *
+generate_and_check_new_value(struct intel_ppat *ppat)
+{
+	struct drm_i915_private *i915 = ppat->i915;
+	const struct intel_ppat_entry *entry;
+	u8 value;
+	DECLARE_BITMAP(used, INTEL_MAX_PPAT_ENTRIES);
+
+	value = generate_new_value(ppat, value_is_new);
+	if (!value) {
+		pr_err("fail to generate new value\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	bitmap_copy(used, ppat->used, ppat->max_entries);
+
+	entry = intel_ppat_get(i915, value);
+	if (IS_ERR(entry)) {
+		pr_err("fail to get new entry\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (entry->value != value) {
+		pr_err("value is not expected, expected %x found %x\n",
+				value, entry->value);
+		goto err;
+	}
+
+	if (bitmap_equal(used, ppat->used, ppat->max_entries)) {
+		pr_err("fail to alloc a new entry\n");
+		goto err;
+	}
+
+	return entry;
+err:
+	intel_ppat_put(entry);
+	return ERR_PTR(-EINVAL);
+}
+
+static int put_and_check_entry(const struct intel_ppat_entry *entry)
+{
+	intel_ppat_put(entry);
+
+	if (entry->value != entry->ppat->clear_value) {
+		pr_err("fail to put ppat value\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int perform_perfect_match_test(struct intel_ppat *ppat)
+{
+	struct drm_i915_private *i915 = ppat->i915;
+	const struct intel_ppat_entry *entry;
+	int ret, i;
+
+	for_each_set_bit(i, ppat->used, ppat->max_entries) {
+		entry = intel_ppat_get(i915, ppat->entries[i].value);
+		if (IS_ERR(entry))
+			return PTR_ERR(entry);
+
+		if (entry != &ppat->entries[i]) {
+			pr_err("entry is not expected\n");
+			intel_ppat_put(entry);
+			return -EINVAL;
+		}
+		ret = put_and_check_entry(entry);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static int perform_negative_test(struct intel_ppat *ppat)
+{
+	struct drm_i915_private *i915 = ppat->i915;
+	const struct intel_ppat_entry *entry;
+	u8 value;
+
+	value = generate_new_value(ppat, value_for_negative_test);
+	if (!value) {
+		pr_err("fail to generate new value for negative test 2\n");
+		return -EINVAL;
+	}
+
+	entry = intel_ppat_get(i915, value);
+	if (!IS_ERR(entry) || PTR_ERR(entry) != -ENOSPC) {
+		pr_err("fail on negative test\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int perform_partial_match_test(struct intel_ppat *ppat)
+{
+	struct drm_i915_private *i915 = ppat->i915;
+	const struct intel_ppat_entry *entry;
+	u8 value;
+	int ret;
+
+	value = generate_new_value(ppat, value_for_partial_test);
+	if (!value) {
+		pr_err("fail to generate new value for partial test\n");
+		return -EINVAL;
+	}
+
+	entry = intel_ppat_get(i915, value);
+	if (IS_ERR(entry)) {
+		pr_err("fail to get new entry\n");
+		return PTR_ERR(entry);
+	}
+
+	if (!(entry->value != value &&
+	    GEN8_PPAT_GET_CA(entry->value) == GEN8_PPAT_GET_CA(value))) {
+		pr_err("value is not expected, expected %x found %x\n",
+				value, entry->value);
+		intel_ppat_put(entry);
+		return -EINVAL;
+	}
+
+	ret = put_and_check_entry(entry);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int igt_ppat_get(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct intel_ppat *ppat = &i915->ppat;
+	const struct intel_ppat_entry **entries, **p;
+	const struct intel_ppat_entry *entry;
+	unsigned int size = 0;
+	int i, ret;
+
+	if (!ppat->max_entries)
+		return 0;
+
+	ret = igt_ppat_check(i915);
+	if (ret)
+		return ret;
+
+	/* case 1: perfect match */
+	ret = perform_perfect_match_test(ppat);
+	if (ret) {
+		pr_err("fail on perfect match test\n");
+		return ret;
+	}
+
+	/* case 2: alloc new entries */
+	entries = NULL;
+	ret = 0;
+
+	while (!bitmap_full(ppat->used, ppat->max_entries)) {
+		p = krealloc(entries, (size + 1) *
+				   sizeof(struct intel_ppat_entry *),
+				   GFP_KERNEL);
+		if (!p) {
+			ret = -ENOMEM;
+			goto ppat_put;
+		}
+
+		entries = p;
+
+		p = &entries[size++];
+		*p = NULL;
+
+		entry = generate_and_check_new_value(ppat);
+		if (IS_ERR(entry)) {
+			ret = PTR_ERR(entry);
+			pr_err("fail on alloc new entries test\n");
+			goto ppat_put;
+		}
+		*p = entry;
+	}
+
+	/* case 3: negative test 1, suppose PPAT table is full now */
+	ret = perform_negative_test(ppat);
+	if (ret) {
+		pr_err("fail on negative test 1\n");
+		goto ppat_put;
+	}
+
+	/* case 4: partial match */
+	ret = perform_partial_match_test(ppat);
+	if (ret) {
+		pr_err("fail on partial match test\n");
+		goto ppat_put;
+	}
+
+	/* case 3: negative test 2, suppose PPAT table is still full now */
+	ret = perform_negative_test(ppat);
+	if (ret) {
+		pr_err("fail on negative test 2\n");
+		goto ppat_put;
+	}
+
+	/* case 5: re-alloc test, make a hole and it should work again */
+	if (entries) {
+		for(i = 0; i < size; i++) {
+			entry = entries[i];
+
+			ret = put_and_check_entry(entry);
+			entries[i] = NULL;
+			if (ret) {
+				pr_err("fail on re-alloc test\n");
+				goto ppat_put;
+			}
+
+			entry = generate_and_check_new_value(ppat);
+			if (IS_ERR(entry)) {
+				ret = PTR_ERR(entry);
+				pr_err("fail on re-alloc test\n");
+				goto ppat_put;
+			}
+			entries[i] = entry;
+		}
+	}
+
+ppat_put:
+	if (entries) {
+		for (i = 0; i < size; i++) {
+			if (IS_ERR(entries[i]) || !entries[i])
+				continue;
+
+			if (ret)
+				intel_ppat_put(entry);
+			else
+				ret = put_and_check_entry(entries[i]);
+		}
+		kfree(entries);
+		entries = NULL;
+	}
+	if (ret)
+		return ret;
+
+	return igt_ppat_check(i915);
+}
+
 static void track_vma_bind(struct i915_vma *vma)
 {
 	struct drm_i915_gem_object *obj = vma->obj;
@@ -1560,6 +1936,8 @@  int i915_gem_gtt_live_selftests(struct drm_i915_private *i915)
 		SUBTEST(igt_ggtt_pot),
 		SUBTEST(igt_ggtt_fill),
 		SUBTEST(igt_ggtt_page),
+		SUBTEST(igt_ppat_check),
+		SUBTEST(igt_ppat_get),
 	};
 
 	GEM_BUG_ON(offset_in_page(i915->ggtt.base.total));