From patchwork Thu Sep 14 12:39:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wang, Zhi A" X-Patchwork-Id: 9952977 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 481D460230 for ; Thu, 14 Sep 2017 12:40:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3865429113 for ; Thu, 14 Sep 2017 12:40:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 335AD290CD; Thu, 14 Sep 2017 12:40:53 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 7CE93290C4 for ; Thu, 14 Sep 2017 12:40:48 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B6C2F6EA28; Thu, 14 Sep 2017 12:40:02 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 3A9F36EA28; Thu, 14 Sep 2017 12:40:01 +0000 (UTC) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 14 Sep 2017 05:40:00 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.42,392,1500966000"; d="scan'208"; a="1014396995" Received: from crlyons-mobl.ger.corp.intel.com (HELO zhiwang1-MOBL.ger.corp.intel.com) ([10.252.11.245]) by orsmga003.jf.intel.com with ESMTP; 14 Sep 2017 05:39:57 -0700 From: Zhi Wang To: intel-gfx@lists.freedesktop.org, intel-gvt-dev@lists.freedesktop.org Date: Thu, 14 Sep 2017 20:39:43 +0800 Message-Id: <1505392783-4084-4-git-send-email-zhi.a.wang@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1505392783-4084-1-git-send-email-zhi.a.wang@intel.com> References: <1505392783-4084-1-git-send-email-zhi.a.wang@intel.com> Cc: Rodrigo Vivi , Ben Widawsky Subject: [Intel-gfx] [PATCH v17 4/4] drm/i915/selftests: Introduce live tests of private PAT management X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP 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. v11: - Fix one indent problem in v10. 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) Suggested-by: Chris Wilson Signed-off-by: Zhi Wang Cc: Ben Widawsky Cc: Rodrigo Vivi Cc: Joonas Lahtinen Reviewed-by: Chris Wilson Reviewed-by: Chris Wilson -Chris --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 378 ++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 6b132ca..cd7eeb6 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));