Message ID | 1504641507-14084-4-git-send-email-zhi.a.wang@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Quoting Zhi Wang (2017-09-05 20:58:27) > Introduce two live tests of private PAT managment: > > igt_ppat_init - This test is to check if all the PPAT configuration is > 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 "partial match" test case will generate a parital matched value from > the existing PPAT table and try to match it. > > 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. > > An example output of these test cases on my SKL box is: > > [ 38.934158] ppat: check private PAT on HW > [ 38.942498] ppat: OK > [ 38.946752] ppat: ppat table before the test > [ 38.955580] ppat 0: 0x7 > [ 38.960509] ppat 2: 0xa > [ 38.965484] ppat 3: 0x0 > [ 38.970267] ppat 4: 0xb > [ 38.975387] ppat: make sure it's same with HW ppat table > [ 38.985996] ppat: check private PAT on HW > [ 38.994492] ppat: OK > [ 38.998921] ppat: case 1: perfect match > [ 39.006706] ppat: OK > [ 39.011135] ppat: case 2: alloc new entries > [ 39.019825] ppat: alloc new entry value 0x37 index 1 > [ 39.029771] ppat: alloc new entry value 0x27 index 5 > [ 39.039829] ppat: alloc new entry value 0x17 index 6 > [ 39.050076] ppat: alloc new entry value 0x3b index 7 > [ 39.059980] ppat: OK > [ 39.064570] ppat: case 3: partial match > [ 39.072354] ppat: generate value 0x2b > [ 39.079432] ppat: partial match entry value 0x3b index 7 > [ 39.090219] ppat: put entries > [ 39.096061] ppat: put entry value 0x37 index 1 > [ 39.105262] ppat: put entry value 0x27 index 5 > [ 39.114150] ppat: put entry value 0x17 index 6 > [ 39.123154] ppat: put entry value 0x3b index 7 > [ 39.132335] ppat: OK > [ 39.136588] ppat: ppat table after the test > [ 39.145239] ppat 0: 0x7 > [ 39.150198] ppat 2: 0xa > [ 39.154981] ppat 3: 0x0 > [ 39.160100] ppat 4: 0xb > [ 39.165058] ppat: make sure it's same with HW ppat table > [ 39.175844] ppat: check private PAT on HW > [ 39.184007] ppat: OK > [ 39.188261] ppat: OK You don't feel this is too verbose? It's just noise (even at pr_debug and so usually hidden) for the signal is in the failure condition, which appears well documented. I couldn't see any failure conditions tested, checking the handling of ENOSPC and then reallocation will be important. -Chris
Hi Zhi, [auto build test WARNING on drm-intel/for-linux-next] [also build test WARNING on next-20170908] [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/20170908-154240 base: git://anongit.freedesktop.org/drm-intel for-linux-next config: i386-randconfig-x001-201736 (attached as .config) compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901 reproduce: # save the attached .config to linux build tree make ARCH=i386 All warnings (new ones prefixed by >>): In file included from include/linux/kernel.h:13:0, from include/asm-generic/bug.h:15, from arch/x86/include/asm/bug.h:81, from include/linux/bug.h:4, from include/linux/mmdebug.h:4, from include/linux/gfp.h:4, from include/linux/slab.h:14, from drivers/gpu/drm/i915/i915_gem_gtt.c:26: drivers/gpu/drm/i915/selftests/i915_gem_gtt.c: In function 'igt_ppat_get': include/linux/kern_levels.h:4:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'int' [-Wformat=] #define KERN_SOH "\001" /* ASCII Start Of Header */ ^ include/linux/printk.h:136:11: note: in definition of macro 'no_printk' printk(fmt, ##__VA_ARGS__); \ ^~~ include/linux/kern_levels.h:14:20: note: in expansion of macro 'KERN_SOH' #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */ ^~~~~~~~ include/linux/printk.h:339:12: note: in expansion of macro 'KERN_DEBUG' no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~ >> drivers/gpu/drm/i915/selftests/i915_gem_gtt.c:1293:3: note: in expansion of macro 'pr_debug' pr_debug("ppat: alloc new entry value 0x%x index %lu\n", ^~~~~~~~ include/linux/kern_levels.h:4:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'int' [-Wformat=] #define KERN_SOH "\001" /* ASCII Start Of Header */ ^ include/linux/printk.h:136:11: note: in definition of macro 'no_printk' printk(fmt, ##__VA_ARGS__); \ ^~~ include/linux/kern_levels.h:14:20: note: in expansion of macro 'KERN_SOH' #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */ ^~~~~~~~ include/linux/printk.h:339:12: note: in expansion of macro 'KERN_DEBUG' no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~ drivers/gpu/drm/i915/selftests/i915_gem_gtt.c:1330:2: note: in expansion of macro 'pr_debug' pr_debug("ppat: partial match entry value 0x%x index %lu\n", ^~~~~~~~ include/linux/kern_levels.h:4:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'int' [-Wformat=] #define KERN_SOH "\001" /* ASCII Start Of Header */ ^ include/linux/printk.h:136:11: note: in definition of macro 'no_printk' printk(fmt, ##__VA_ARGS__); \ ^~~ include/linux/kern_levels.h:14:20: note: in expansion of macro 'KERN_SOH' #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */ ^~~~~~~~ include/linux/printk.h:339:12: note: in expansion of macro 'KERN_DEBUG' no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~ drivers/gpu/drm/i915/selftests/i915_gem_gtt.c:1343:4: note: in expansion of macro 'pr_debug' pr_debug("ppat: put entry value 0x%x index %lu\n", ^~~~~~~~ vim +/pr_debug +1293 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c 1205 1206 static int igt_ppat_get(void *arg) 1207 { 1208 struct drm_i915_private *i915 = arg; 1209 struct intel_ppat *ppat = &i915->ppat; 1210 const struct intel_ppat_entry **entries; 1211 const struct intel_ppat_entry *entry; 1212 unsigned int size = 0; 1213 u8 value; 1214 int i, ret; 1215 1216 if (!ppat->max_entries) 1217 return 0; 1218 1219 pr_debug("ppat: ppat table before the test\n"); 1220 1221 for_each_set_bit(i, ppat->used, ppat->max_entries) 1222 pr_debug("ppat %d: 0x%x\n", i, ppat->entries[i].value); 1223 1224 pr_debug("ppat: make sure it's same with HW ppat table\n"); 1225 1226 ret = igt_ppat_init(i915); 1227 if (ret) 1228 return ret; 1229 1230 pr_debug("ppat: case 1: perfect match\n"); 1231 1232 entry = intel_ppat_get(i915, ppat->entries[0].value); 1233 if (IS_ERR(entry)) 1234 return PTR_ERR(entry); 1235 1236 if (entry != &ppat->entries[0]) { 1237 pr_err("not expected entry\n"); 1238 intel_ppat_put(entry); 1239 return -EINVAL; 1240 } 1241 1242 intel_ppat_put(entry); 1243 1244 pr_debug("ppat: OK\n"); 1245 pr_debug("ppat: case 2: alloc new entries\n"); 1246 1247 entries = NULL; 1248 ret = 0; 1249 1250 while (!ppat_table_is_full(ppat)) { 1251 const struct intel_ppat_entry **p_entry; 1252 DECLARE_BITMAP(used, INTEL_MAX_PPAT_ENTRIES); 1253 1254 bitmap_copy(used, ppat->used, ppat->max_entries); 1255 1256 entries = krealloc(entries, (size + 1) * 1257 sizeof(struct intel_ppat_entry *), 1258 GFP_KERNEL); 1259 if (!entries) { 1260 ret = -ENOSPC; 1261 break; 1262 } 1263 1264 p_entry = &entries[size++]; 1265 *p_entry = NULL; 1266 1267 value = generate_new_value(ppat, false); 1268 if (!value) { 1269 pr_err("cannot fill the unused PPAT entries?\n"); 1270 ret = -EINVAL; 1271 break; 1272 } 1273 1274 *p_entry = entry = intel_ppat_get(i915, value); 1275 if (IS_ERR(entry)) { 1276 pr_err("fail to get new entry\n"); 1277 ret = PTR_ERR(entry); 1278 break; 1279 } 1280 1281 if (entry->value != value) { 1282 pr_err("fail to get expected new value\n"); 1283 ret = -EINVAL; 1284 break; 1285 } 1286 1287 if (bitmap_equal(used, ppat->used, ppat->max_entries)) { 1288 pr_err("fail to alloc a new entry\n"); 1289 ret = -EINVAL; 1290 break; 1291 } 1292 > 1293 pr_debug("ppat: alloc new entry value 0x%x index %lu\n", 1294 entry->value, entry - ppat->entries); 1295 } 1296 1297 if (!ret) 1298 pr_debug("ppat: OK\n"); 1299 1300 if (!entries) 1301 pr_debug("ppat: ppat table is full, skip\n"); 1302 1303 if (ret) 1304 goto ppat_put; 1305 1306 pr_debug("ppat: case 3: partial match\n"); 1307 1308 value = generate_new_value(ppat, true); 1309 if (!value) { 1310 pr_err("fail to get new value\n"); 1311 ret = -EINVAL; 1312 goto ppat_put; 1313 } 1314 1315 pr_debug("ppat: generate value 0x%x\n", value); 1316 1317 entry = intel_ppat_get(i915, value); 1318 if (IS_ERR(entry)) { 1319 pr_err("fail to get new entry\n"); 1320 ret = PTR_ERR(entry); 1321 goto ppat_put; 1322 } 1323 1324 if (!(entry->value != value && 1325 GEN8_PPAT_GET_CA(entry->value) == GEN8_PPAT_GET_CA(value))) { 1326 pr_err("fail to get expected value\n"); 1327 ret = -EINVAL; 1328 } 1329 1330 pr_debug("ppat: partial match entry value 0x%x index %lu\n", 1331 entry->value, entry - ppat->entries); 1332 1333 intel_ppat_put(entry); 1334 1335 ppat_put: 1336 if (entries) { 1337 pr_debug("ppat: put entries\n"); 1338 1339 for (i = 0; i < size; i++) { 1340 if (IS_ERR(entries[i]) || !entries[i]) 1341 continue; 1342 1343 pr_debug("ppat: put entry value 0x%x index %lu\n", 1344 entries[i]->value, entries[i] - ppat->entries); 1345 1346 intel_ppat_put(entries[i]); 1347 1348 if (entries[i]->value != ppat->clear_value) { 1349 pr_err("fail to put ppat value\n"); 1350 ret = -EINVAL; 1351 break; 1352 } 1353 } 1354 pr_debug("ppat: OK\n"); 1355 kfree(entries); 1356 entries = NULL; 1357 } 1358 1359 pr_debug("ppat: ppat table after the test\n"); 1360 1361 for_each_set_bit(i, ppat->used, ppat->max_entries) 1362 pr_debug("ppat %d: 0x%x\n", i, ppat->entries[i].value); 1363 1364 pr_debug("ppat: make sure it's same with HW ppat table\n"); 1365 1366 ret = igt_ppat_init(i915); 1367 if (ret) 1368 return ret; 1369 1370 pr_debug("ppat: OK\n"); 1371 1372 return ret; 1373 } 1374 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Zhi, [auto build test WARNING on drm-intel/for-linux-next] [also build test WARNING on next-20170908] [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/20170908-154240 base: git://anongit.freedesktop.org/drm-intel for-linux-next config: i386-allmodconfig (attached as .config) compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901 reproduce: # save the attached .config to linux build tree make ARCH=i386 All warnings (new ones prefixed by >>): In file included from include/linux/kernel.h:13:0, from include/asm-generic/bug.h:15, from arch/x86/include/asm/bug.h:81, from include/linux/bug.h:4, from include/linux/mmdebug.h:4, from include/linux/gfp.h:4, from include/linux/slab.h:14, from drivers/gpu/drm/i915/i915_gem_gtt.c:26: drivers/gpu/drm/i915/selftests/i915_gem_gtt.c: In function 'igt_ppat_get': >> drivers/gpu/drm/i915/selftests/i915_gem_gtt.c:1293:12: warning: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'int' [-Wformat=] pr_debug("ppat: alloc new entry value 0x%x index %lu\n", ^ include/linux/printk.h:285:21: note: in definition of macro 'pr_fmt' #define pr_fmt(fmt) fmt ^~~ include/linux/printk.h:333:2: note: in expansion of macro 'dynamic_pr_debug' dynamic_pr_debug(fmt, ##__VA_ARGS__) ^~~~~~~~~~~~~~~~ drivers/gpu/drm/i915/selftests/i915_gem_gtt.c:1293:3: note: in expansion of macro 'pr_debug' pr_debug("ppat: alloc new entry value 0x%x index %lu\n", ^~~~~~~~ drivers/gpu/drm/i915/selftests/i915_gem_gtt.c:1330:11: warning: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'int' [-Wformat=] pr_debug("ppat: partial match entry value 0x%x index %lu\n", ^ include/linux/printk.h:285:21: note: in definition of macro 'pr_fmt' #define pr_fmt(fmt) fmt ^~~ include/linux/printk.h:333:2: note: in expansion of macro 'dynamic_pr_debug' dynamic_pr_debug(fmt, ##__VA_ARGS__) ^~~~~~~~~~~~~~~~ drivers/gpu/drm/i915/selftests/i915_gem_gtt.c:1330:2: note: in expansion of macro 'pr_debug' pr_debug("ppat: partial match entry value 0x%x index %lu\n", ^~~~~~~~ drivers/gpu/drm/i915/selftests/i915_gem_gtt.c:1343:13: warning: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'int' [-Wformat=] pr_debug("ppat: put entry value 0x%x index %lu\n", ^ include/linux/printk.h:285:21: note: in definition of macro 'pr_fmt' #define pr_fmt(fmt) fmt ^~~ include/linux/printk.h:333:2: note: in expansion of macro 'dynamic_pr_debug' dynamic_pr_debug(fmt, ##__VA_ARGS__) ^~~~~~~~~~~~~~~~ drivers/gpu/drm/i915/selftests/i915_gem_gtt.c:1343:4: note: in expansion of macro 'pr_debug' pr_debug("ppat: put entry value 0x%x index %lu\n", ^~~~~~~~ vim +1293 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c 1205 1206 static int igt_ppat_get(void *arg) 1207 { 1208 struct drm_i915_private *i915 = arg; 1209 struct intel_ppat *ppat = &i915->ppat; 1210 const struct intel_ppat_entry **entries; 1211 const struct intel_ppat_entry *entry; 1212 unsigned int size = 0; 1213 u8 value; 1214 int i, ret; 1215 1216 if (!ppat->max_entries) 1217 return 0; 1218 1219 pr_debug("ppat: ppat table before the test\n"); 1220 1221 for_each_set_bit(i, ppat->used, ppat->max_entries) 1222 pr_debug("ppat %d: 0x%x\n", i, ppat->entries[i].value); 1223 1224 pr_debug("ppat: make sure it's same with HW ppat table\n"); 1225 1226 ret = igt_ppat_init(i915); 1227 if (ret) 1228 return ret; 1229 1230 pr_debug("ppat: case 1: perfect match\n"); 1231 1232 entry = intel_ppat_get(i915, ppat->entries[0].value); 1233 if (IS_ERR(entry)) 1234 return PTR_ERR(entry); 1235 1236 if (entry != &ppat->entries[0]) { 1237 pr_err("not expected entry\n"); 1238 intel_ppat_put(entry); 1239 return -EINVAL; 1240 } 1241 1242 intel_ppat_put(entry); 1243 1244 pr_debug("ppat: OK\n"); 1245 pr_debug("ppat: case 2: alloc new entries\n"); 1246 1247 entries = NULL; 1248 ret = 0; 1249 1250 while (!ppat_table_is_full(ppat)) { 1251 const struct intel_ppat_entry **p_entry; 1252 DECLARE_BITMAP(used, INTEL_MAX_PPAT_ENTRIES); 1253 1254 bitmap_copy(used, ppat->used, ppat->max_entries); 1255 1256 entries = krealloc(entries, (size + 1) * 1257 sizeof(struct intel_ppat_entry *), 1258 GFP_KERNEL); 1259 if (!entries) { 1260 ret = -ENOSPC; 1261 break; 1262 } 1263 1264 p_entry = &entries[size++]; 1265 *p_entry = NULL; 1266 1267 value = generate_new_value(ppat, false); 1268 if (!value) { 1269 pr_err("cannot fill the unused PPAT entries?\n"); 1270 ret = -EINVAL; 1271 break; 1272 } 1273 1274 *p_entry = entry = intel_ppat_get(i915, value); 1275 if (IS_ERR(entry)) { 1276 pr_err("fail to get new entry\n"); 1277 ret = PTR_ERR(entry); 1278 break; 1279 } 1280 1281 if (entry->value != value) { 1282 pr_err("fail to get expected new value\n"); 1283 ret = -EINVAL; 1284 break; 1285 } 1286 1287 if (bitmap_equal(used, ppat->used, ppat->max_entries)) { 1288 pr_err("fail to alloc a new entry\n"); 1289 ret = -EINVAL; 1290 break; 1291 } 1292 > 1293 pr_debug("ppat: alloc new entry value 0x%x index %lu\n", 1294 entry->value, entry - ppat->entries); 1295 } 1296 1297 if (!ret) 1298 pr_debug("ppat: OK\n"); 1299 1300 if (!entries) 1301 pr_debug("ppat: ppat table is full, skip\n"); 1302 1303 if (ret) 1304 goto ppat_put; 1305 1306 pr_debug("ppat: case 3: partial match\n"); 1307 1308 value = generate_new_value(ppat, true); 1309 if (!value) { 1310 pr_err("fail to get new value\n"); 1311 ret = -EINVAL; 1312 goto ppat_put; 1313 } 1314 1315 pr_debug("ppat: generate value 0x%x\n", value); 1316 1317 entry = intel_ppat_get(i915, value); 1318 if (IS_ERR(entry)) { 1319 pr_err("fail to get new entry\n"); 1320 ret = PTR_ERR(entry); 1321 goto ppat_put; 1322 } 1323 1324 if (!(entry->value != value && 1325 GEN8_PPAT_GET_CA(entry->value) == GEN8_PPAT_GET_CA(value))) { 1326 pr_err("fail to get expected value\n"); 1327 ret = -EINVAL; 1328 } 1329 1330 pr_debug("ppat: partial match entry value 0x%x index %lu\n", 1331 entry->value, entry - ppat->entries); 1332 1333 intel_ppat_put(entry); 1334 1335 ppat_put: 1336 if (entries) { 1337 pr_debug("ppat: put entries\n"); 1338 1339 for (i = 0; i < size; i++) { 1340 if (IS_ERR(entries[i]) || !entries[i]) 1341 continue; 1342 1343 pr_debug("ppat: put entry value 0x%x index %lu\n", 1344 entries[i]->value, entries[i] - ppat->entries); 1345 1346 intel_ppat_put(entries[i]); 1347 1348 if (entries[i]->value != ppat->clear_value) { 1349 pr_err("fail to put ppat value\n"); 1350 ret = -EINVAL; 1351 break; 1352 } 1353 } 1354 pr_debug("ppat: OK\n"); 1355 kfree(entries); 1356 entries = NULL; 1357 } 1358 1359 pr_debug("ppat: ppat table after the test\n"); 1360 1361 for_each_set_bit(i, ppat->used, ppat->max_entries) 1362 pr_debug("ppat %d: 0x%x\n", i, ppat->entries[i].value); 1363 1364 pr_debug("ppat: make sure it's same with HW ppat table\n"); 1365 1366 ret = igt_ppat_init(i915); 1367 if (ret) 1368 return ret; 1369 1370 pr_debug("ppat: OK\n"); 1371 1372 return ret; 1373 } 1374 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 6b132ca..cda0a41 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -1094,6 +1094,284 @@ static int igt_ggtt_page(void *arg) return err; } +static int check_cnl_ppat_init(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("expected PPAT value isn't written into HW\n"); + return -EINVAL; + } + } + return 0; +} + +static int check_bdw_ppat_init(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("expected PPAT value isn't written into HW\n"); + return -EINVAL; + } + return 0; +} + +static int igt_ppat_init(void *arg) +{ + struct drm_i915_private *i915 = arg; + int ret; + + if (!i915->ppat.max_entries) + return 0; + + pr_debug("ppat: check private PAT on HW\n"); + + if (INTEL_GEN(i915) >= 10) + ret = check_cnl_ppat_init(i915); + else + ret = check_bdw_ppat_init(i915); + + if (!ret) + pr_debug("ppat: OK\n"); + + return ret; +} + +static u8 generate_new_value(struct intel_ppat *ppat, bool partial) +{ + u8 ca[] = { GEN8_PPAT_WB, GEN8_PPAT_WC, GEN8_PPAT_WT, GEN8_PPAT_UC }; + 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) }; + u8 value = 0; + bool same; + int ca_index, tc_index, age_index, i; + +#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]; + same = false; + + for_each_set_bit(i, ppat->used, ppat->max_entries) { + if (value != ppat->entries[i].value) + continue; + + same = true; + break; + } + + if (same) + continue; + + if (!partial) + return value; + + /* partial match, cache attribute has to be the same. */ + 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 value; + } + } +#undef for_each_ppat_attr + return 0; +} + +static inline bool ppat_table_is_full(struct intel_ppat *ppat) +{ + return bitmap_weight(ppat->used, ppat->max_entries) == + ppat->max_entries; +} + +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; + const struct intel_ppat_entry *entry; + unsigned int size = 0; + u8 value; + int i, ret; + + if (!ppat->max_entries) + return 0; + + pr_debug("ppat: ppat table before the test\n"); + + for_each_set_bit(i, ppat->used, ppat->max_entries) + pr_debug("ppat %d: 0x%x\n", i, ppat->entries[i].value); + + pr_debug("ppat: make sure it's same with HW ppat table\n"); + + ret = igt_ppat_init(i915); + if (ret) + return ret; + + pr_debug("ppat: case 1: perfect match\n"); + + entry = intel_ppat_get(i915, ppat->entries[0].value); + if (IS_ERR(entry)) + return PTR_ERR(entry); + + if (entry != &ppat->entries[0]) { + pr_err("not expected entry\n"); + intel_ppat_put(entry); + return -EINVAL; + } + + intel_ppat_put(entry); + + pr_debug("ppat: OK\n"); + pr_debug("ppat: case 2: alloc new entries\n"); + + entries = NULL; + ret = 0; + + while (!ppat_table_is_full(ppat)) { + const struct intel_ppat_entry **p_entry; + DECLARE_BITMAP(used, INTEL_MAX_PPAT_ENTRIES); + + bitmap_copy(used, ppat->used, ppat->max_entries); + + entries = krealloc(entries, (size + 1) * + sizeof(struct intel_ppat_entry *), + GFP_KERNEL); + if (!entries) { + ret = -ENOSPC; + break; + } + + p_entry = &entries[size++]; + *p_entry = NULL; + + value = generate_new_value(ppat, false); + if (!value) { + pr_err("cannot fill the unused PPAT entries?\n"); + ret = -EINVAL; + break; + } + + *p_entry = entry = intel_ppat_get(i915, value); + if (IS_ERR(entry)) { + pr_err("fail to get new entry\n"); + ret = PTR_ERR(entry); + break; + } + + if (entry->value != value) { + pr_err("fail to get expected new value\n"); + ret = -EINVAL; + break; + } + + if (bitmap_equal(used, ppat->used, ppat->max_entries)) { + pr_err("fail to alloc a new entry\n"); + ret = -EINVAL; + break; + } + + pr_debug("ppat: alloc new entry value 0x%x index %lu\n", + entry->value, entry - ppat->entries); + } + + if (!ret) + pr_debug("ppat: OK\n"); + + if (!entries) + pr_debug("ppat: ppat table is full, skip\n"); + + if (ret) + goto ppat_put; + + pr_debug("ppat: case 3: partial match\n"); + + value = generate_new_value(ppat, true); + if (!value) { + pr_err("fail to get new value\n"); + ret = -EINVAL; + goto ppat_put; + } + + pr_debug("ppat: generate value 0x%x\n", value); + + entry = intel_ppat_get(i915, value); + if (IS_ERR(entry)) { + pr_err("fail to get new entry\n"); + ret = PTR_ERR(entry); + goto ppat_put; + } + + if (!(entry->value != value && + GEN8_PPAT_GET_CA(entry->value) == GEN8_PPAT_GET_CA(value))) { + pr_err("fail to get expected value\n"); + ret = -EINVAL; + } + + pr_debug("ppat: partial match entry value 0x%x index %lu\n", + entry->value, entry - ppat->entries); + + intel_ppat_put(entry); + +ppat_put: + if (entries) { + pr_debug("ppat: put entries\n"); + + for (i = 0; i < size; i++) { + if (IS_ERR(entries[i]) || !entries[i]) + continue; + + pr_debug("ppat: put entry value 0x%x index %lu\n", + entries[i]->value, entries[i] - ppat->entries); + + intel_ppat_put(entries[i]); + + if (entries[i]->value != ppat->clear_value) { + pr_err("fail to put ppat value\n"); + ret = -EINVAL; + break; + } + } + pr_debug("ppat: OK\n"); + kfree(entries); + entries = NULL; + } + + pr_debug("ppat: ppat table after the test\n"); + + for_each_set_bit(i, ppat->used, ppat->max_entries) + pr_debug("ppat %d: 0x%x\n", i, ppat->entries[i].value); + + pr_debug("ppat: make sure it's same with HW ppat table\n"); + + ret = igt_ppat_init(i915); + if (ret) + return ret; + + pr_debug("ppat: OK\n"); + + return ret; +} + static void track_vma_bind(struct i915_vma *vma) { struct drm_i915_gem_object *obj = vma->obj; @@ -1560,6 +1838,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_init), + SUBTEST(igt_ppat_get), }; GEM_BUG_ON(offset_in_page(i915->ggtt.base.total));
Introduce two live tests of private PAT managment: igt_ppat_init - This test is to check if all the PPAT configuration is 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 "partial match" test case will generate a parital matched value from the existing PPAT table and try to match it. 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. An example output of these test cases on my SKL box is: [ 38.934158] ppat: check private PAT on HW [ 38.942498] ppat: OK [ 38.946752] ppat: ppat table before the test [ 38.955580] ppat 0: 0x7 [ 38.960509] ppat 2: 0xa [ 38.965484] ppat 3: 0x0 [ 38.970267] ppat 4: 0xb [ 38.975387] ppat: make sure it's same with HW ppat table [ 38.985996] ppat: check private PAT on HW [ 38.994492] ppat: OK [ 38.998921] ppat: case 1: perfect match [ 39.006706] ppat: OK [ 39.011135] ppat: case 2: alloc new entries [ 39.019825] ppat: alloc new entry value 0x37 index 1 [ 39.029771] ppat: alloc new entry value 0x27 index 5 [ 39.039829] ppat: alloc new entry value 0x17 index 6 [ 39.050076] ppat: alloc new entry value 0x3b index 7 [ 39.059980] ppat: OK [ 39.064570] ppat: case 3: partial match [ 39.072354] ppat: generate value 0x2b [ 39.079432] ppat: partial match entry value 0x3b index 7 [ 39.090219] ppat: put entries [ 39.096061] ppat: put entry value 0x37 index 1 [ 39.105262] ppat: put entry value 0x27 index 5 [ 39.114150] ppat: put entry value 0x17 index 6 [ 39.123154] ppat: put entry value 0x3b index 7 [ 39.132335] ppat: OK [ 39.136588] ppat: ppat table after the test [ 39.145239] ppat 0: 0x7 [ 39.150198] ppat 2: 0xa [ 39.154981] ppat 3: 0x0 [ 39.160100] ppat 4: 0xb [ 39.165058] ppat: make sure it's same with HW ppat table [ 39.175844] ppat: check private PAT on HW [ 39.184007] ppat: OK [ 39.188261] ppat: OK 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 | 280 ++++++++++++++++++++++++++ 1 file changed, 280 insertions(+)