[Intel-gfx] [PATCH v2 0/1] Stop users from using the device on driver unbind

2019-04-18 Thread Janusz Krzysztofik
Use drm_dev_unplug() to have device resources protected from user access
by DRM layer as soon as the driver is going to be unbound.

Janusz Krzysztofik (1):
  drm/i915: Use drm_dev_unplug()

 drivers/gpu/drm/i915/i915_drv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Since this patch should be now safe for use if merged with current
drm-next or drm-tip branch which no longer suffer from incorrectly
resolved merge confilct that was breaking it, finally fixed by commit
bd53280ef042 ("drm/drv: Fix incorrect resolution of merge conflict"),
I'm resending it with Daniel's Reviewed-by: added.

Former patch 2/2 has been dropped as it is already in drm-intel-next as
commit 141f3767e7b8 ("drm/i915: Mark GEM wedged right after marking
device unplugged").  BTW, the wersion I sent was screwed up, not
reflecting Chris' intention precisely enough, but Chris was vigilant and
fixed it.  Sorry Chris.

Thanks,
Janusz
-- 
2.20.1

___
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

[Intel-gfx] [PATCH v2 1/1] drm/i915: Use drm_dev_unplug()

2019-04-18 Thread Janusz Krzysztofik
From: Janusz Krzysztofik 

The driver does not currently support unbinding from a device which is
in use.  Since open file descriptors may still be pointing into kernel
memory where the device structures used to be, entirely correct kernel
panics protect the driver from being unbound as we should not be
unbinding it before those dangling pointers have been made safe.

According to the documentation found inside drivers/gpu/drm/drm_drv.c,
drm_dev_unplug() should be used instead of drm_dev_unregister() in
order to make a device inaccessible to users as soon as it is unpluged.
Follow that advice to make those possibly dangling pointers safe,
protected by DRM layer from a user who is otherwise left pointing into
possibly reused kernel memory after the driver has been unbound from
the device.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Chris Wilson 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/i915/i915_drv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 9df65d386d11..66163378c481 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -1596,7 +1596,7 @@ static void i915_driver_unregister(struct 
drm_i915_private *dev_priv)
i915_pmu_unregister(dev_priv);
 
i915_teardown_sysfs(dev_priv);
-   drm_dev_unregister(&dev_priv->drm);
+   drm_dev_unplug(&dev_priv->drm);
 
i915_gem_shrinker_unregister(dev_priv);
 }
-- 
2.20.1

___
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

[Intel-gfx] [PATCH RESEND] drm/i915: Flush buffer pools on driver remove

2021-09-03 Thread Janusz Krzysztofik
In preparation for clean driver release, attempts to drain work queues
and release freed objects are taken at driver remove time.  However, GT
buffer pools are now not flushed before the driver release phase.
Since unused objects may stay there for up to one second, some may
survive until driver release is attempted.  That can potentially
explain sporadic then hardly reproducible issues observed at driver
release time, like non-zero shrink counter or outstanding address space
areas.

Flush buffer pools on GT remove as a fix.  On driver release, don't
flush the pools again, just assert that the flush was called and
nothing added more in between.

Signed-off-by: Janusz Krzysztofik 
Cc: Chris Wilson 
---
Resending with Cc: dri-de...@lists.freedesktop.org as requested, and a
typo in commit description fixed.

Thanks,
Janusz

 drivers/gpu/drm/i915/gt/intel_gt.c | 2 ++
 drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c | 2 --
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c 
b/drivers/gpu/drm/i915/gt/intel_gt.c
index 62d40c986642..8f322a4ecd87 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -737,6 +737,8 @@ void intel_gt_driver_remove(struct intel_gt *gt)
intel_uc_driver_remove(>->uc);
 
intel_engines_release(gt);
+
+   intel_gt_flush_buffer_pool(gt);
 }
 
 void intel_gt_driver_unregister(struct intel_gt *gt)
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c 
b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
index aa0a59c5b614..acc49c56a9f3 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
@@ -245,8 +245,6 @@ void intel_gt_fini_buffer_pool(struct intel_gt *gt)
struct intel_gt_buffer_pool *pool = >->buffer_pool;
int n;
 
-   intel_gt_flush_buffer_pool(gt);
-
for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++)
GEM_BUG_ON(!list_empty(&pool->cache_list[n]));
 }
-- 
2.25.1



[Intel-gfx] [PATCH RESEND] drm/i915: Mark GPU wedging on driver unregister unrecoverable

2021-09-03 Thread Janusz Krzysztofik
GPU wedged flag now set on driver unregister to prevent from further
using the GPU can be then cleared unintentionally when calling
__intel_gt_unset_wedged() still before the flag is finally marked
unrecoverable.  We need to have it marked unrecoverable earlier.
Implement that by replacing a call to intel_gt_set_wedged() in
intel_gt_driver_unregister() with intel_gt_set_wedged_on_fini().

With the above in place, intel_gt_set_wedged_on_fini() is now called
twice on driver remove, second time from __intel_gt_disable().  This
seems harmless, while dropping intel_gt_set_wedged_on_fini() from
__intel_gt_disable() proved to break some driver probe error unwind
paths as well as mock selftest exit path.

Signed-off-by: Janusz Krzysztofik 
Cc: Michał Winiarski 
---
Resending with Cc: dri-de...@lists.freedesktop.org as requested.

Thanks,
Janusz

 drivers/gpu/drm/i915/gt/intel_gt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c 
b/drivers/gpu/drm/i915/gt/intel_gt.c
index 62d40c986642..173b53cb2b47 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -750,7 +750,7 @@ void intel_gt_driver_unregister(struct intel_gt *gt)
 * all in-flight requests so that we can quickly unbind the active
 * resources.
 */
-   intel_gt_set_wedged(gt);
+   intel_gt_set_wedged_on_fini(gt);
 
/* Scrub all HW state upon release */
with_intel_runtime_pm(gt->uncore->rpm, wakeref)
-- 
2.25.1



Re: [Intel-gfx] ✗ Fi.CI.IGT: failure for drm/i915: Mark GPU wedging on driver unregister unrecoverable (rev2)

2021-09-06 Thread Janusz Krzysztofik
On piątek, 3 września 2021 21:07:00 CEST Patchwork wrote:
> == Series Details ==
> 
> Series: drm/i915: Mark GPU wedging on driver unregister unrecoverable (rev2)
> URL   : https://patchwork.freedesktop.org/series/94247/
> State : failure
> 
> == Summary ==
> 
> CI Bug Log - changes from CI_DRM_10550_full -> Patchwork_20953_full
> 
> 
> Summary
> ---
> 
>   **FAILURE**
> 
>   Serious unknown changes coming with Patchwork_20953_full absolutely need to 
> be
>   verified manually.
>   
>   If you think the reported changes have nothing to do with the changes
>   introduced in Patchwork_20953_full, please notify your bug team to allow 
> them
>   to document this new failure mode, which will reduce false positives in CI.
> 
>   
> 
> Possible new issues
> ---
> 
>   Here are the unknown changes that may have been introduced in 
> Patchwork_20953_full:
> 
> ### IGT changes ###
> 
>  Possible regressions 
> 
>   * igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile:
> - shard-iclb: [PASS][1] -> [SKIP][2]
>[1]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10550/shard-iclb4/igt@kms_flip_scaled_...@flip-32bpp-ytile-to-64bpp-ytile.html
>[2]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-iclb2/igt@kms_flip_scaled_...@flip-32bpp-ytile-to-64bpp-ytile.html

stdout: No valid pipe/connector/format/mod combination found

That doesn't sound like a driver unregister related issue to me.

Thanks,
Janusz

> 
>   
> Known issues
> 
> 
>   Here are the changes found in Patchwork_20953_full that come from known 
> issues:
> 
> ### IGT changes ###
> 
>  Issues hit 
> 
>   * igt@feature_discovery@display-2x:
> - shard-iclb: NOTRUN -> [SKIP][3] ([i915#1839])
>[3]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-iclb8/igt@feature_discov...@display-2x.html
> 
>   * igt@gem_create@create-massive:
> - shard-snb:  NOTRUN -> [DMESG-WARN][4] ([i915#3002])
>[4]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-snb6/igt@gem_cre...@create-massive.html
> 
>   * igt@gem_ctx_persistence@legacy-engines-hostile:
> - shard-snb:  NOTRUN -> [SKIP][5] ([fdo#109271] / [i915#1099]) +2 
> similar issues
>[5]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-snb6/igt@gem_ctx_persiste...@legacy-engines-hostile.html
> 
>   * igt@gem_eio@in-flight-contexts-10ms:
> - shard-tglb: [PASS][6] -> [TIMEOUT][7] ([i915#3063])
>[6]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10550/shard-tglb3/igt@gem_...@in-flight-contexts-10ms.html
>[7]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-tglb6/igt@gem_...@in-flight-contexts-10ms.html
> 
>   * igt@gem_eio@unwedge-stress:
> - shard-tglb: [PASS][8] -> [TIMEOUT][9] ([i915#2369] / 
> [i915#3063] / [i915#3648])
>[8]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10550/shard-tglb8/igt@gem_...@unwedge-stress.html
>[9]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-tglb7/igt@gem_...@unwedge-stress.html
> 
>   * igt@gem_exec_fair@basic-flow@rcs0:
> - shard-tglb: [PASS][10] -> [FAIL][11] ([i915#2842])
>[10]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10550/shard-tglb1/igt@gem_exec_fair@basic-f...@rcs0.html
>[11]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-tglb1/igt@gem_exec_fair@basic-f...@rcs0.html
> 
>   * igt@gem_exec_fair@basic-throttle@rcs0:
> - shard-iclb: [PASS][12] -> [FAIL][13] ([i915#2849])
>[12]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_10550/shard-iclb8/igt@gem_exec_fair@basic-throt...@rcs0.html
>[13]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-iclb2/igt@gem_exec_fair@basic-throt...@rcs0.html
> 
>   * igt@gem_exec_params@secure-non-master:
> - shard-iclb: NOTRUN -> [SKIP][14] ([fdo#112283])
>[14]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-iclb8/igt@gem_exec_par...@secure-non-master.html
> 
>   * igt@gem_pread@exhaustion:
> - shard-apl:  NOTRUN -> [WARN][15] ([i915#2658])
>[15]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-apl6/igt@gem_pr...@exhaustion.html
> - shard-skl:  NOTRUN -> [WARN][16] ([i915#2658])
>[16]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-skl3/igt@gem_pr...@exhaustion.html
> 
>   * igt@gem_pwrite@basic-exhaustion:
> - shard-kbl:  NOTRUN -> [WARN][17] ([i915#2658]) +1 similar issue
>[17]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-kbl3/igt@gem_pwr...@basic-exhaustion.html
> 
>   * igt@gem_render_copy@yf-tiled-to-vebox-x-tiled:
> - shard-iclb: NOTRUN -> [SKIP][18] ([i915#768])
>[18]: 
> https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_20953/shard-iclb8/igt@gem_render_c...@yf-tiled-to-vebox-x-tiled

Re: [Intel-gfx] [PATCH RESEND] drm/i915: Flush buffer pools on driver remove

2021-09-23 Thread Janusz Krzysztofik
Hi Matt,

Thanks for review.

On czwartek, 23 września 2021 00:24:29 CEST Matt Roper wrote:
> On Fri, Sep 03, 2021 at 04:23:20PM +0200, Janusz Krzysztofik wrote:
> > In preparation for clean driver release, attempts to drain work queues
> > and release freed objects are taken at driver remove time.  However, GT
> > buffer pools are now not flushed before the driver release phase.
> > Since unused objects may stay there for up to one second, some may
> > survive until driver release is attempted.  That can potentially
> > explain sporadic then hardly reproducible issues observed at driver
> > release time, like non-zero shrink counter or outstanding address space
> 
> So just to make sure I'm understanding the description here:
>  - We currently do an explicit flush of the buffer pools within the call
>path of drm_driver.release(); this removes all buffers, regardless of
>their age.

And also triggers release of the buffers' underlying resources (objects, 
address space areas).

>  - However there may be other code that runs *earlier* within the
>drm_driver.release() call chain 

Yes, within the drm_driver.release() call chain, but not necessarily earlier 
-- that's irrelevant, I believe, ...

>that expects buffer pools have
>already been flushed and are already empty.

... since that other code expects not just buffer pools but resource 
categories they consume (objects, address space areas) to be flushed already, 
while some may still be busy with old buffers not auto-flushed yet.

>  - Since buffer pools auto-flush old buffers once per second in a worker
>thread, there's a small window where if we remove the driver while
>there are still buffers with an age of less than one second, the
>assumptions of the other release code may be violated.

Correct.

> So by moving the flush to driver remove (which executes earlier via the
> pci_driver.remove() flow) you're ensuring that all buffers are flushed
> before _any_ code in drm_driver.release() executes.

And also flushed before some other code in pci_driver.remove() flushes those 
other resource categories released on buffer pools flush, then completeness of 
all those flushes is checked in drm_driver.release().

May I copy-paste some of you wording while rephrasing my commit description?

Thanks,
Janusz

> 
> I found the wording of the commit message here somewhat confusing since
> it's talking about flushes we do in driver release, but mentions
> problems that arise during driver release due to lack of flushing.  You
> might want to reword the commit message somewhat to help clarify.
> Otherwise, the code change itself looks reasonable to me.
> 
> BTW, I do notice that drm_driver.release() in general is technically
> deprecated at this point (with a suggestion in the drm_drv.h comments to
> switch to using drmm_add_action(), drmm_kmalloc(), etc. to manage the
> cleanup of resources).  At some point in the future me may want to
> rework the i915 cleanup in general according to that guidance.
> 
> 
> Matt
> 
> > areas.
> > 
> > Flush buffer pools on GT remove as a fix.  On driver release, don't
> > flush the pools again, just assert that the flush was called and
> > nothing added more in between.
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > Cc: Chris Wilson 
> > ---
> > Resending with Cc: dri-de...@lists.freedesktop.org as requested, and a
> > typo in commit description fixed.
> > 
> > Thanks,
> > Janusz
> > 
> >  drivers/gpu/drm/i915/gt/intel_gt.c | 2 ++
> >  drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c | 2 --
> >  2 files changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c 
> > b/drivers/gpu/drm/i915/gt/intel_gt.c
> > index 62d40c986642..8f322a4ecd87 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gt.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_gt.c
> > @@ -737,6 +737,8 @@ void intel_gt_driver_remove(struct intel_gt *gt)
> > intel_uc_driver_remove(>->uc);
> >  
> > intel_engines_release(gt);
> > +
> > +   intel_gt_flush_buffer_pool(gt);
> >  }
> >  
> >  void intel_gt_driver_unregister(struct intel_gt *gt)
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c 
> > b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
> > index aa0a59c5b614..acc49c56a9f3 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
> > @@ -245,8 +245,6 @@ void intel_gt_fini_buffer_pool(struct intel_gt *gt)
> > struct intel_gt_buffer_pool *pool = >->buffer_pool;
> > int n;
> >  
> > -   intel_gt_flush_buffer_pool(gt);
> > -
> > for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++)
> > GEM_BUG_ON(!list_empty(&pool->cache_list[n]));
> >  }
> 
> 






[Intel-gfx] [PATCH v2] drm/i915: Flush buffer pools on driver remove

2021-09-24 Thread Janusz Krzysztofik
We currently do an explicit flush of the buffer pools within the call path
of drm_driver.release(); this removes all buffers, regardless of their age,
freeing the buffers' associated resources (objects, adress space areas).
However there is other code that runs within the drm_driver.release() call
chain that expects objects and their associated address space areas have
already been flushed.

Since buffer pools auto-flush old buffers once per second in a worker
thread, there's a small window where if we remove the driver while there
are still objects in buffers with an age of less than one second, the
assumptions of the other release code may be violated.

By moving the flush to driver remove (which executes earlier via the
pci_driver.remove() flow) we're ensuring that all buffers are flushed and
their associated objects freed before some other code in
pci_driver.remove() flushes those objects so they are released before
_any_ code in drm_driver.release() that check completness of those
flushes executes.

v2: Reword commit descriptiom as suggested by Matt.

Signed-off-by: Janusz Krzysztofik 
Cc: Chris Wilson 
Cc: Matt Roper 
---
 drivers/gpu/drm/i915/gt/intel_gt.c | 2 ++
 drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c | 2 --
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c 
b/drivers/gpu/drm/i915/gt/intel_gt.c
index 4037c3778225..5b3acf2b064e 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -741,6 +741,8 @@ void intel_gt_driver_remove(struct intel_gt *gt)
intel_uc_driver_remove(>->uc);
 
intel_engines_release(gt);
+
+   intel_gt_flush_buffer_pool(gt);
 }
 
 void intel_gt_driver_unregister(struct intel_gt *gt)
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c 
b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
index aa0a59c5b614..acc49c56a9f3 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
@@ -245,8 +245,6 @@ void intel_gt_fini_buffer_pool(struct intel_gt *gt)
struct intel_gt_buffer_pool *pool = >->buffer_pool;
int n;
 
-   intel_gt_flush_buffer_pool(gt);
-
for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++)
GEM_BUG_ON(!list_empty(&pool->cache_list[n]));
 }
-- 
2.25.1



[Intel-gfx] [PATCH] drm/i915: Mark GPU wedging on driver unregister unrecoverable

2021-09-01 Thread Janusz Krzysztofik
GPU wedged flag now set on driver unregister to prevent from further
using the GPU can be then cleared unintentionally when calling
__intel_gt_unset_wedged() still before the flag is finally marked
unrecoverable.  We need to have it marked unrecoverable earlier.
Implement that by replacing a call to intel_gt_set_wedged() in
intel_gt_driver_unregister() with intel_gt_set_wedged_on_fini().

With the above in place, intel_gt_set_wedged_on_fini() is now called
twice on driver remove, second time from __intel_gt_disable().  This
seems harmless, while dropping intel_gt_set_wedged_on_fini() from
__intel_gt_disable() proved to break some driver probe error unwind
paths as well as mock selftest exit path.

Signed-off-by: Janusz Krzysztofik 
Cc: Michał Winiarski 
---
 drivers/gpu/drm/i915/gt/intel_gt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c 
b/drivers/gpu/drm/i915/gt/intel_gt.c
index 62d40c986642..173b53cb2b47 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -750,7 +750,7 @@ void intel_gt_driver_unregister(struct intel_gt *gt)
 * all in-flight requests so that we can quickly unbind the active
 * resources.
 */
-   intel_gt_set_wedged(gt);
+   intel_gt_set_wedged_on_fini(gt);
 
/* Scrub all HW state upon release */
with_intel_runtime_pm(gt->uncore->rpm, wakeref)
-- 
2.25.1



[Intel-gfx] [PATCH] drm/i915: Flush buffer pools on driver remove

2021-09-01 Thread Janusz Krzysztofik
In preparation for clean driver release, attempts to drain work queues
and release freed objects are taken at driver remove time.  However, GT
buffer pools are now not flushed before the driver release phase.
Since unused objects may stay there for up to one second, some may
survive until driver release is attempted.  That can potentially
explain sporadic then hardly reproducible issues observed at driver
release time, like non-zero shrink counter or outstanding address space
areas.

Flush buffer pools on GT remove as a fix.  On driver release, don't push
the pools again, just assert that the flush was called and nothing added
more in between.

Signed-off-by: Janusz Krzysztofik 
Cc: Chris Wilson 
---
 drivers/gpu/drm/i915/gt/intel_gt.c | 2 ++
 drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c | 2 --
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c 
b/drivers/gpu/drm/i915/gt/intel_gt.c
index 62d40c986642..8f322a4ecd87 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -737,6 +737,8 @@ void intel_gt_driver_remove(struct intel_gt *gt)
intel_uc_driver_remove(>->uc);
 
intel_engines_release(gt);
+
+   intel_gt_flush_buffer_pool(gt);
 }
 
 void intel_gt_driver_unregister(struct intel_gt *gt)
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c 
b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
index aa0a59c5b614..acc49c56a9f3 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c
@@ -245,8 +245,6 @@ void intel_gt_fini_buffer_pool(struct intel_gt *gt)
struct intel_gt_buffer_pool *pool = >->buffer_pool;
int n;
 
-   intel_gt_flush_buffer_pool(gt);
-
for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++)
GEM_BUG_ON(!list_empty(&pool->cache_list[n]));
 }
-- 
2.25.1



[Intel-gfx] [PATCH i-g-t] tests/core_hotunplug: Show device PCI bus address on errors

2021-11-18 Thread Janusz Krzysztofik
Strange -ENODEV responses from the kernel to i915 driver rebind attempts
have been sporadically observed.  After successfully unbinding the driver
from a device by writing a string representing its PCI bus address to
/sys/bus/pci/driver/i915/unbind, the test then fails while writing the
same device PCI bus address string to /sys/bus/pci/drivers/i915/bind.  It
is unlikely that the device disappears from the bus when this happens --
the test would attempt to rescan the bus in such cases while it doesn't.

To shed more light on what may be going on, extend error messages emitted
by the test with the device PCI bus address string it uses also printed.

Signed-off-by: Janusz Krzysztofik 
---
 tests/core_hotunplug.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/tests/core_hotunplug.c b/tests/core_hotunplug.c
index b36616688..2f2fb7ac1 100644
--- a/tests/core_hotunplug.c
+++ b/tests/core_hotunplug.c
@@ -174,11 +174,11 @@ static void driver_unbind(struct hotunplug *priv, const 
char *prefix,
igt_set_timeout(timeout, "Driver unbind timeout!");
igt_assert_f(igt_sysfs_set(priv->fd.sysfs_drv, "unbind",
   priv->dev_bus_addr),
-"Driver unbind failure!\n");
+"Driver unbind failure (%s)!\n", priv->dev_bus_addr);
igt_reset_timeout();
 
igt_assert_f(faccessat(priv->fd.sysfs_drv, priv->dev_bus_addr, F_OK, 0),
-"Unbound device still present\n");
+"Unbound device still present (%s)\n", priv->dev_bus_addr);
 }
 
 /* Re-bind the driver to the device */
@@ -190,12 +190,12 @@ static void driver_bind(struct hotunplug *priv, int 
timeout)
igt_set_timeout(timeout, "Driver re-bind timeout!");
igt_assert_f(igt_sysfs_set(priv->fd.sysfs_drv, "bind",
   priv->dev_bus_addr),
-"Driver re-bind failure\n!");
+"Driver re-bind failure (%s)!\n", priv->dev_bus_addr);
igt_reset_timeout();
 
igt_fail_on_f(faccessat(priv->fd.sysfs_drv, priv->dev_bus_addr,
F_OK, 0),
- "Rebound device not present!\n");
+ "Rebound device not present (%s)!\n", priv->dev_bus_addr);
 
if (priv->snd_unload)
igt_kmod_load("snd_hda_intel", NULL);
@@ -223,7 +223,7 @@ static void device_unplug(struct hotunplug *priv, const 
char *prefix,
igt_assert_eq(priv->fd.sysfs_dev, -1);
 
igt_assert_f(faccessat(priv->fd.sysfs_bus, priv->dev_bus_addr, F_OK, 0),
-"Unplugged device still present\n");
+"Unplugged device still present (%s)\n", 
priv->dev_bus_addr);
 }
 
 /* Re-discover the device by rescanning its bus */
@@ -239,7 +239,7 @@ static void bus_rescan(struct hotunplug *priv, int timeout)
 
igt_fail_on_f(faccessat(priv->fd.sysfs_bus, priv->dev_bus_addr,
F_OK, 0),
- "Fakely unplugged device not rediscovered!\n");
+ "Fakely unplugged device not rediscovered (%s)!\n", 
priv->dev_bus_addr);
 }
 
 static void cleanup(struct hotunplug *priv)
-- 
2.25.1



Re: [Intel-gfx] [PATCH i-g-t] tests/core_hotunplug: Show device PCI bus address on errors

2021-11-26 Thread Janusz Krzysztofik
On Friday, 26 November 2021 09:00:06 CET Bernatowicz, Marcin wrote:
> 
> On 11/18/2021 9:41 AM, Janusz Krzysztofik wrote:
> > Strange -ENODEV responses from the kernel to i915 driver rebind attempts
> > have been sporadically observed.  After successfully unbinding the driver
> > from a device by writing a string representing its PCI bus address to
> > /sys/bus/pci/driver/i915/unbind, the test then fails while writing the
> > same device PCI bus address string to /sys/bus/pci/drivers/i915/bind.  It
> > is unlikely that the device disappears from the bus when this happens --
> > the test would attempt to rescan the bus in such cases while it doesn't.
> > 
> > To shed more light on what may be going on, extend error messages emitted
> > by the test with the device PCI bus address string it uses also printed.
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > ---
> >   tests/core_hotunplug.c | 12 ++--
> >   1 file changed, 6 insertions(+), 6 deletions(-)
> > 
> > diff --git a/tests/core_hotunplug.c b/tests/core_hotunplug.c
> > index b36616688..2f2fb7ac1 100644
> > --- a/tests/core_hotunplug.c
> > +++ b/tests/core_hotunplug.c
> > @@ -174,11 +174,11 @@ static void driver_unbind(struct hotunplug *priv, 
> > const char *prefix,
> > igt_set_timeout(timeout, "Driver unbind timeout!");
> > igt_assert_f(igt_sysfs_set(priv->fd.sysfs_drv, "unbind",
> >priv->dev_bus_addr),
> > -"Driver unbind failure!\n");
> > +"Driver unbind failure (%s)!\n", priv->dev_bus_addr);
> > igt_reset_timeout();
> >   
> > igt_assert_f(faccessat(priv->fd.sysfs_drv, priv->dev_bus_addr, F_OK, 0),
> > -"Unbound device still present\n");
> > +"Unbound device still present (%s)\n", priv->dev_bus_addr);
> >   }
> >   
> >   /* Re-bind the driver to the device */
> > @@ -190,12 +190,12 @@ static void driver_bind(struct hotunplug *priv, int 
> > timeout)
> > igt_set_timeout(timeout, "Driver re-bind timeout!");
> > igt_assert_f(igt_sysfs_set(priv->fd.sysfs_drv, "bind",
> >priv->dev_bus_addr),
> > -"Driver re-bind failure\n!");
> > +"Driver re-bind failure (%s)!\n", priv->dev_bus_addr);
> > igt_reset_timeout();
> >   
> > igt_fail_on_f(faccessat(priv->fd.sysfs_drv, priv->dev_bus_addr,
> > F_OK, 0),
> > - "Rebound device not present!\n");
> > + "Rebound device not present (%s)!\n", priv->dev_bus_addr);
> >   
> > if (priv->snd_unload)
> > igt_kmod_load("snd_hda_intel", NULL);
> > @@ -223,7 +223,7 @@ static void device_unplug(struct hotunplug *priv, const 
> > char *prefix,
> > igt_assert_eq(priv->fd.sysfs_dev, -1);
> >   
> > igt_assert_f(faccessat(priv->fd.sysfs_bus, priv->dev_bus_addr, F_OK, 0),
> > -"Unplugged device still present\n");
> > +"Unplugged device still present (%s)\n", 
> > priv->dev_bus_addr);
> >   }
> >   
> >   /* Re-discover the device by rescanning its bus */
> > @@ -239,7 +239,7 @@ static void bus_rescan(struct hotunplug *priv, int 
> > timeout)
> >   
> > igt_fail_on_f(faccessat(priv->fd.sysfs_bus, priv->dev_bus_addr,
> > F_OK, 0),
> > - "Fakely unplugged device not rediscovered!\n");
> > + "Fakely unplugged device not rediscovered (%s)!\n", 
> > priv->dev_bus_addr);
> >   }
> >   
> >   static void cleanup(struct hotunplug *priv)
> > 
> LGTM,
> Reviewed-by: Marcin Bernatowicz 

Thanks Marcin, pushed.

Janusz





[Intel-gfx] [PATCH i-g-t] lib/igt_device: Add support for accessing unbound VF PCI devices

2022-02-18 Thread Janusz Krzysztofik
The library provides igt_device_get_pci_device() function that allows to
get access to a PCI device from an open DRM device file descriptor.  It
can be used on VF devices as long as a DRM driver is bound to them.
However, SR-IOV tests may want to exercise VF PCI devices created by a PF
without binding any DRM driver to them.

While keeping the API of igt_device_get_pci_device() untouched, extend API
of its underlying helper __igt_device_get_pci_device() with an extra
argument for specifying VF ID of the requested PCI device and expose this
function as public.

While being at it, fix pci_system_cleanup() not called on errors and
instruct users to call it for symmetry when the obtained struct pci_device
is no longer needed.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_device.c | 44 
 lib/igt_device.h |  1 +
 2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/lib/igt_device.c b/lib/igt_device.c
index 07bb0a0d41..56f66afc6f 100644
--- a/lib/igt_device.c
+++ b/lib/igt_device.c
@@ -149,9 +149,9 @@ struct igt_pci_addr {
unsigned int function;
 };
 
-static int igt_device_get_pci_addr(int fd, struct igt_pci_addr *pci)
+static int igt_device_get_pci_addr(int fd, unsigned int vf_id, struct 
igt_pci_addr *pci)
 {
-   char path[IGT_DEV_PATH_LEN];
+   char link[20], path[IGT_DEV_PATH_LEN];
char *buf;
int sysfs;
int len;
@@ -159,11 +159,21 @@ static int igt_device_get_pci_addr(int fd, struct 
igt_pci_addr *pci)
if (!igt_device_is_pci(fd))
return -ENODEV;
 
+   if (vf_id)
+   len = snprintf(link, sizeof(link), "device/virtfn%u", vf_id - 
1);
+   else
+   len = snprintf(link, sizeof(link), "device");
+   if (igt_warn_on_f(len > sizeof(link) || link[len -1],
+   "IGT bug: insufficient buffer space for rendering PCI device link 
name\n"))
+   return -ENOSPC;
+   else if (igt_debug_on_f(len < 0, "unexpected failure from 
snprintf()\n"))
+   return len;
+
sysfs = igt_sysfs_open(fd);
if (sysfs == -1)
return -ENOENT;
 
-   len = readlinkat(sysfs, "device", path, sizeof(path) - 1);
+   len = readlinkat(sysfs, link, path, sizeof(path) - 1);
close(sysfs);
if (len == -1)
return -ENOENT;
@@ -183,12 +193,25 @@ static int igt_device_get_pci_addr(int fd, struct 
igt_pci_addr *pci)
return 0;
 }
 
-static struct pci_device *__igt_device_get_pci_device(int fd)
+/**
+ * __igt_device_get_pci_device:
+ *
+ * @fd: DRM device file descriptor
+ * @vf_id: virtual function number (0 if native or PF)
+ *
+ * Looks up the graphics pci device using libpciaccess.
+ * Since pci_system_init() is called, users are expected to call 
pci_sytem_clenup() after use
+ * unless an error occurs and NULL is returned.
+ *
+ * Returns:
+ * The pci_device, NULL on any failures.
+ */
+struct pci_device *__igt_device_get_pci_device(int fd, unsigned int vf_id)
 {
struct igt_pci_addr pci_addr;
struct pci_device *pci_dev;
 
-   if (igt_device_get_pci_addr(fd, &pci_addr)) {
+   if (igt_device_get_pci_addr(fd, vf_id, &pci_addr)) {
igt_warn("Unable to find device PCI address\n");
return NULL;
}
@@ -206,15 +229,19 @@ static struct pci_device *__igt_device_get_pci_device(int 
fd)
igt_warn("Couldn't find PCI device %04x:%02x:%02x:%02x\n",
 pci_addr.domain, pci_addr.bus,
 pci_addr.device, pci_addr.function);
-   return NULL;
+   goto cleanup;
}
 
if (pci_device_probe(pci_dev)) {
igt_warn("Couldn't probe PCI device\n");
-   return NULL;
+   goto cleanup;
}
 
return pci_dev;
+
+cleanup:
+   pci_system_cleanup();
+   return NULL;
 }
 
 /**
@@ -223,6 +250,7 @@ static struct pci_device *__igt_device_get_pci_device(int 
fd)
  * @fd: the device
  *
  * Looks up the main graphics pci device using libpciaccess.
+ * Since pci_system_init() is called, users are expected to call 
pci_sytem_clenup() after use.
  *
  * Returns:
  * The pci_device, skips the test on any failures.
@@ -231,7 +259,7 @@ struct pci_device *igt_device_get_pci_device(int fd)
 {
struct pci_device *pci_dev;
 
-   pci_dev = __igt_device_get_pci_device(fd);
+   pci_dev = __igt_device_get_pci_device(fd, 0);
igt_require(pci_dev);
 
return pci_dev;
diff --git a/lib/igt_device.h b/lib/igt_device.h
index 278ba7a9b3..1aaa840e25 100644
--- a/lib/igt_device.h
+++ b/lib/igt_device.h
@@ -33,5 +33,6 @@ void igt_device_drop_master(int fd);
 
 int igt_device_get_card_index(int fd);
 struct pci_device *igt_device_get_pci_device(int fd);
+struct pci_device *__igt_device_get_pci_device(int fd, unsigned int vf_id);
 
 #endif /* __IGT_DEVICE_H__ */
-- 
2.25.1



Re: [Intel-gfx] [igt-dev] [PATCH i-g-t] lib/igt_device: Add support for accessing unbound VF PCI devices

2022-02-18 Thread Janusz Krzysztofik
Hi Chris,

On Friday, 18 February 2022 17:03:01 CET Chris Wilson wrote:
> Quoting Janusz Krzysztofik (2022-02-18 15:19:35)
> > @@ -206,15 +229,19 @@ static struct pci_device 
> > *__igt_device_get_pci_device(int fd)
> > igt_warn("Couldn't find PCI device %04x:%02x:%02x:%02x\n",
> >  pci_addr.domain, pci_addr.bus,
> >  pci_addr.device, pci_addr.function);
> > -   return NULL;
> > +   goto cleanup;
> > }
> >  
> > if (pci_device_probe(pci_dev)) {
> > igt_warn("Couldn't probe PCI device\n");
> > -   return NULL;
> > +   goto cleanup;
> > }
> >  
> > return pci_dev;
> > +
> > +cleanup:
> > +   pci_system_cleanup();
> 
> This is a global cleanup of libpciaccess iirc, such that if anyone else
> was using the library they would be affected.

Right, but shouldn't we also drop pci_system_init() from here and request 
users to manage initialization and cleanup of that data themselves?  On each 
call pci_system_init() abandons existing data and overwrites a pointer to it 
with that of newly allocated memory, then tests calling 
igt_device_get_pci_device() multiple times are going to suffer from 
significant memory leaking.

Thanks,
Janusz

> 
> > +   return NULL;
> >  }
> 






[Intel-gfx] [PATCH i-g-t 1/2] lib: Use safe wrappers around libpciaccess initialization functions

2022-02-22 Thread Janusz Krzysztofik
Multiple calls to igt functions using pci_system_init() provided by
libpciaccess result in memory leaking if not followed by its counterpart
pci_system_cleanup() before next use.  On the other hand, calling
pci_system_cleanup() can affect other users which still depend on global
data initialized by pci_system_init().

Introduce safe IGT wrappers around those libpciaccess functions and use
those wrappers in IGT library and tests.

Signed-off-by: Janusz Krzysztofik 
Cc: Chris Wilson 
---
 lib/igt_core.c  | 20 
 lib/igt_core.h  | 28 
 lib/igt_device.c|  2 +-
 lib/intel_chipset.c |  2 +-
 4 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/lib/igt_core.c b/lib/igt_core.c
index ab27a24d5a..88e2f7d01e 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -3070,3 +3070,23 @@ err:
 
return -1;
 }
+
+/* IGT wrappers around libpciaccess init/cleanup functions */
+
+static void pci_system_exit_handler(int sig)
+{
+   pci_system_cleanup();
+}
+
+static void __pci_system_init(void)
+{
+   if (!igt_warn_on_f(pci_system_init(), "Could not initialize 
libpciaccess global data\n"))
+   igt_install_exit_handler(pci_system_exit_handler);
+}
+
+int igt_pci_system_init(void)
+{
+   static pthread_once_t pci_system_init_once_control = PTHREAD_ONCE_INIT;
+
+   return pthread_once(&pci_system_init_once_control, __pci_system_init);
+}
diff --git a/lib/igt_core.h b/lib/igt_core.h
index 0aad161da5..78dc6202ce 100644
--- a/lib/igt_core.h
+++ b/lib/igt_core.h
@@ -1452,4 +1452,32 @@ void igt_kmsg(const char *format, ...);
 
 #define for_if(expr__) if (!(expr__)) {} else
 
+/**
+ * igt_pci_system_init:
+ * IGT wrapper around pci_system_init()
+ *
+ * Runs pci_system_init() and installs pci_system_cleanup() as IGT exit 
handler when
+ * called first per thread, subsequent calls are noop.  Tests should use this 
wrapper
+ * instead of pci_system_init() to avoid memory leaking which happens each 
time a call
+ * to pci_system_init() is repeated not preceded by pci_system_cleanup() (may 
easily
+ * happen in consequence of long jumps performed by IGT flow control 
functions).
+ *
+ * Return value: equal return value of pthread_once() (return value of 
pci_system_init()
+ *  can't be passed through pthread_once())
+ */
+int igt_pci_system_init(void);
+
+/**
+ * igt_pci_system_cleanup():
+ * IGT replacement for pci_system_cleanup()
+ *
+ * For use in IGT library and tests to avoid destroying libpciaccess global 
data.
+ * Direct calls to pci_system_cleanup() should be either dropped or replaced 
with this
+ * wrapper (for code clarity), otherwise subsequent access to libpciaccess 
global data
+ * may be lost unless preceded by direct call to pci_system_init() (not 
recommended).
+ */
+static inline void igt_pci_system_cleanup(void)
+{
+}
+
 #endif /* IGT_CORE_H */
diff --git a/lib/igt_device.c b/lib/igt_device.c
index 07bb0a0d41..c50bf4a1f7 100644
--- a/lib/igt_device.c
+++ b/lib/igt_device.c
@@ -193,7 +193,7 @@ static struct pci_device *__igt_device_get_pci_device(int 
fd)
return NULL;
}
 
-   if (pci_system_init()) {
+   if (igt_pci_system_init()) {
igt_warn("Couldn't initialize PCI system\n");
return NULL;
}
diff --git a/lib/intel_chipset.c b/lib/intel_chipset.c
index 4748a3fb85..efb6f17714 100644
--- a/lib/intel_chipset.c
+++ b/lib/intel_chipset.c
@@ -75,7 +75,7 @@ intel_get_pci_device(void)
struct pci_device *pci_dev;
int error;
 
-   error = pci_system_init();
+   error = igt_pci_system_init();
igt_fail_on_f(error != 0,
  "Couldn't initialize PCI system\n");
 
-- 
2.25.1



[Intel-gfx] [PATCH i-g-t 2/2] lib/igt_device: Add support for accessing unbound VF PCI devices

2022-02-22 Thread Janusz Krzysztofik
The library provides igt_device_get_pci_device() function that allows to
get access to a PCI device from an open DRM device file descriptor.  It
can be used on VF devices as long as a DRM driver is bound to them.
However, SR-IOV tests may want to exercise VF PCI devices created by a PF
without binding any DRM driver to them.

While keeping the API of igt_device_get_pci_device() untouched, extend API
of its underlying helper __igt_device_get_pci_device() with an extra
argument for specifying VF ID of the requested PCI device and expose this
function as public.

v2: refresh on top of IGT libpciaccess wrappers and drop previously added
but no longer needed error unwind path and recommendations for users
on calling pci_system_cleanup() after use (Chris),
  - fix incorrect validation of snprintf() result and misaligned
formatting of igt_warn_on_f() arguments.

Signed-off-by: Janusz Krzysztofik 
Cc: Chris Wilson 
---
 lib/igt_device.c | 34 --
 lib/igt_device.h |  1 +
 2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/lib/igt_device.c b/lib/igt_device.c
index c50bf4a1f7..1603bf351c 100644
--- a/lib/igt_device.c
+++ b/lib/igt_device.c
@@ -149,9 +149,9 @@ struct igt_pci_addr {
unsigned int function;
 };
 
-static int igt_device_get_pci_addr(int fd, struct igt_pci_addr *pci)
+static int igt_device_get_pci_addr(int fd, unsigned int vf_id, struct 
igt_pci_addr *pci)
 {
-   char path[IGT_DEV_PATH_LEN];
+   char link[20], path[IGT_DEV_PATH_LEN];
char *buf;
int sysfs;
int len;
@@ -159,11 +159,21 @@ static int igt_device_get_pci_addr(int fd, struct 
igt_pci_addr *pci)
if (!igt_device_is_pci(fd))
return -ENODEV;
 
+   if (vf_id)
+   len = snprintf(link, sizeof(link), "device/virtfn%u", vf_id - 
1);
+   else
+   len = snprintf(link, sizeof(link), "device");
+   if (igt_warn_on_f(len >= sizeof(link),
+ "IGT bug: insufficient buffer space for rendering PCI 
device link name\n"))
+   return -ENOSPC;
+   else if (igt_debug_on_f(len < 0, "unexpected failure from 
snprintf()\n"))
+   return len;
+
sysfs = igt_sysfs_open(fd);
if (sysfs == -1)
return -ENOENT;
 
-   len = readlinkat(sysfs, "device", path, sizeof(path) - 1);
+   len = readlinkat(sysfs, link, path, sizeof(path) - 1);
close(sysfs);
if (len == -1)
return -ENOENT;
@@ -183,12 +193,24 @@ static int igt_device_get_pci_addr(int fd, struct 
igt_pci_addr *pci)
return 0;
 }
 
-static struct pci_device *__igt_device_get_pci_device(int fd)
+/**
+ * __igt_device_get_pci_device:
+ *
+ * @fd: DRM device file descriptor
+ * @vf_id: virtual function number (0 if native or PF)
+ *
+ * Looks up the graphics pci device using libpciaccess.
+ * unless an error occurs and NULL is returned.
+ *
+ * Returns:
+ * The pci_device, NULL on any failures.
+ */
+struct pci_device *__igt_device_get_pci_device(int fd, unsigned int vf_id)
 {
struct igt_pci_addr pci_addr;
struct pci_device *pci_dev;
 
-   if (igt_device_get_pci_addr(fd, &pci_addr)) {
+   if (igt_device_get_pci_addr(fd, vf_id, &pci_addr)) {
igt_warn("Unable to find device PCI address\n");
return NULL;
}
@@ -231,7 +253,7 @@ struct pci_device *igt_device_get_pci_device(int fd)
 {
struct pci_device *pci_dev;
 
-   pci_dev = __igt_device_get_pci_device(fd);
+   pci_dev = __igt_device_get_pci_device(fd, 0);
igt_require(pci_dev);
 
return pci_dev;
diff --git a/lib/igt_device.h b/lib/igt_device.h
index 278ba7a9b3..1aaa840e25 100644
--- a/lib/igt_device.h
+++ b/lib/igt_device.h
@@ -33,5 +33,6 @@ void igt_device_drop_master(int fd);
 
 int igt_device_get_card_index(int fd);
 struct pci_device *igt_device_get_pci_device(int fd);
+struct pci_device *__igt_device_get_pci_device(int fd, unsigned int vf_id);
 
 #endif /* __IGT_DEVICE_H__ */
-- 
2.25.1



[Intel-gfx] [PATCH i-g-t v3] lib/igt_device: Add support for accessing unbound VF PCI devices

2022-02-22 Thread Janusz Krzysztofik
The library provides igt_device_get_pci_device() function that allows to
get access to a PCI device from an open DRM device file descriptor.  It
can be used on VF devices as long as a DRM driver is bound to them.
However, SR-IOV tests may want to exercise VF PCI devices created by a PF
without binding any DRM driver to them.

While keeping the API of igt_device_get_pci_device() untouched, extend API
of its underlying helper __igt_device_get_pci_device() with an extra
argument for specifying VF ID of the requested PCI device and expose this
function as public.

v2: refresh on top of IGT libpciaccess wrappers and drop previously added
but no longer needed error unwind path and recommendations for users
on calling pci_system_cleanup() after use (Chris),
  - fix incorrect validation of snprintf() result and misaligned
formatting of igt_warn_on_f() arguments.
v3: follow VF numbering convention of Linux PCI ABI (Chris),
  - fix and improve DOC.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Chris Wilson  # v2
---
 lib/igt_device.c | 33 +++--
 lib/igt_device.h |  1 +
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/lib/igt_device.c b/lib/igt_device.c
index c50bf4a1f7..46b7dbc490 100644
--- a/lib/igt_device.c
+++ b/lib/igt_device.c
@@ -149,9 +149,9 @@ struct igt_pci_addr {
unsigned int function;
 };
 
-static int igt_device_get_pci_addr(int fd, struct igt_pci_addr *pci)
+static int igt_device_get_pci_addr(int fd, int vf_id, struct igt_pci_addr *pci)
 {
-   char path[IGT_DEV_PATH_LEN];
+   char link[20], path[IGT_DEV_PATH_LEN];
char *buf;
int sysfs;
int len;
@@ -159,11 +159,21 @@ static int igt_device_get_pci_addr(int fd, struct 
igt_pci_addr *pci)
if (!igt_device_is_pci(fd))
return -ENODEV;
 
+   if (vf_id < 0)
+   len = snprintf(link, sizeof(link), "device");
+   else
+   len = snprintf(link, sizeof(link), "device/virtfn%u", vf_id);
+   if (igt_warn_on_f(len >= sizeof(link),
+ "IGT bug: insufficient buffer space for rendering PCI 
device link name\n"))
+   return -ENOSPC;
+   else if (igt_debug_on_f(len < 0, "unexpected failure from 
snprintf()\n"))
+   return len;
+
sysfs = igt_sysfs_open(fd);
if (sysfs == -1)
return -ENOENT;
 
-   len = readlinkat(sysfs, "device", path, sizeof(path) - 1);
+   len = readlinkat(sysfs, link, path, sizeof(path) - 1);
close(sysfs);
if (len == -1)
return -ENOENT;
@@ -183,12 +193,23 @@ static int igt_device_get_pci_addr(int fd, struct 
igt_pci_addr *pci)
return 0;
 }
 
-static struct pci_device *__igt_device_get_pci_device(int fd)
+/**
+ * __igt_device_get_pci_device:
+ *
+ * @fd: DRM device file descriptor
+ * @vf_id: PCI virtual function number or -1 if native or PF itself
+ *
+ * Looks up a PCI interface of a DRM device or a VF PCI device of the DRM PF 
using libpciaccess.
+ *
+ * Returns:
+ * The pci_device, NULL on any failures.
+ */
+struct pci_device *__igt_device_get_pci_device(int fd, int vf_id)
 {
struct igt_pci_addr pci_addr;
struct pci_device *pci_dev;
 
-   if (igt_device_get_pci_addr(fd, &pci_addr)) {
+   if (igt_device_get_pci_addr(fd, vf_id, &pci_addr)) {
igt_warn("Unable to find device PCI address\n");
return NULL;
}
@@ -231,7 +252,7 @@ struct pci_device *igt_device_get_pci_device(int fd)
 {
struct pci_device *pci_dev;
 
-   pci_dev = __igt_device_get_pci_device(fd);
+   pci_dev = __igt_device_get_pci_device(fd, -1);
igt_require(pci_dev);
 
return pci_dev;
diff --git a/lib/igt_device.h b/lib/igt_device.h
index 278ba7a9b3..00da853e71 100644
--- a/lib/igt_device.h
+++ b/lib/igt_device.h
@@ -33,5 +33,6 @@ void igt_device_drop_master(int fd);
 
 int igt_device_get_card_index(int fd);
 struct pci_device *igt_device_get_pci_device(int fd);
+struct pci_device *__igt_device_get_pci_device(int fd, int vf_id);
 
 #endif /* __IGT_DEVICE_H__ */
-- 
2.25.1



Re: [Intel-gfx] [igt-dev] [PATCH i-g-t v3] lib/igt_device: Add support for accessing unbound VF PCI devices

2022-02-22 Thread Janusz Krzysztofik
Hi Michał,

Thanks for review.

On Tuesday, 22 February 2022 17:16:54 CET Michal Wajdeczko wrote:
> 
> On 22.02.2022 16:11, Janusz Krzysztofik wrote:
> > The library provides igt_device_get_pci_device() function that allows to
> > get access to a PCI device from an open DRM device file descriptor.  It
> > can be used on VF devices as long as a DRM driver is bound to them.
> > However, SR-IOV tests may want to exercise VF PCI devices created by a PF
> > without binding any DRM driver to them.
> > 
> > While keeping the API of igt_device_get_pci_device() untouched, extend API
> > of its underlying helper __igt_device_get_pci_device() with an extra
> > argument for specifying VF ID of the requested PCI device and expose this
> > function as public.
> > 
> > v2: refresh on top of IGT libpciaccess wrappers and drop previously added
> > but no longer needed error unwind path and recommendations for users
> > on calling pci_system_cleanup() after use (Chris),
> >   - fix incorrect validation of snprintf() result and misaligned
> > formatting of igt_warn_on_f() arguments.
> > v3: follow VF numbering convention of Linux PCI ABI (Chris),
> >   - fix and improve DOC.
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > Reviewed-by: Chris Wilson  # v2
> > ---
> >  lib/igt_device.c | 33 +++--
> >  lib/igt_device.h |  1 +
> >  2 files changed, 28 insertions(+), 6 deletions(-)
> > 
> > diff --git a/lib/igt_device.c b/lib/igt_device.c
> > index c50bf4a1f7..46b7dbc490 100644
> > --- a/lib/igt_device.c
> > +++ b/lib/igt_device.c
> > @@ -149,9 +149,9 @@ struct igt_pci_addr {
> > unsigned int function;
> >  };
> >  
> > -static int igt_device_get_pci_addr(int fd, struct igt_pci_addr *pci)
> > +static int igt_device_get_pci_addr(int fd, int vf_id, struct igt_pci_addr 
> > *pci)
> >  {
> > -   char path[IGT_DEV_PATH_LEN];
> > +   char link[20], path[IGT_DEV_PATH_LEN];
> > char *buf;
> > int sysfs;
> > int len;
> > @@ -159,11 +159,21 @@ static int igt_device_get_pci_addr(int fd, struct 
> > igt_pci_addr *pci)
> > if (!igt_device_is_pci(fd))
> > return -ENODEV;
> >  
> > +   if (vf_id < 0)
> > +   len = snprintf(link, sizeof(link), "device");
> > +   else
> > +   len = snprintf(link, sizeof(link), "device/virtfn%u", vf_id);
> > +   if (igt_warn_on_f(len >= sizeof(link),
> > + "IGT bug: insufficient buffer space for rendering PCI 
> > device link name\n"))
> > +   return -ENOSPC;
> > +   else if (igt_debug_on_f(len < 0, "unexpected failure from 
> > snprintf()\n"))
> > +   return len;
> > +
> > sysfs = igt_sysfs_open(fd);
> > if (sysfs == -1)
> > return -ENOENT;
> >  
> > -   len = readlinkat(sysfs, "device", path, sizeof(path) - 1);
> > +   len = readlinkat(sysfs, link, path, sizeof(path) - 1);
> > close(sysfs);
> > if (len == -1)
> > return -ENOENT;
> > @@ -183,12 +193,23 @@ static int igt_device_get_pci_addr(int fd, struct 
> > igt_pci_addr *pci)
> > return 0;
> >  }
> >  
> > -static struct pci_device *__igt_device_get_pci_device(int fd)
> > +/**
> > + * __igt_device_get_pci_device:
> > + *
> > + * @fd: DRM device file descriptor
> > + * @vf_id: PCI virtual function number or -1 if native or PF itself
> 
> this param seems to be used here rather as 0-based "index" that
> subsystem uses to list virtfn entries, while real VF "numbers" are
> 1-based, see PCI spec which says:
> 
> "VFs are numbered starting with 1 so the first VF associated with PF M
> is VF M,1."

OK, since v2 using 1-based VF numbering has been positively reviewed by Chris
despite his comment on inconsistency with Linux PCI ABI then let's consider
the 0-based VF numbering used in that ABI as non-standard and merge v2 of this 
patch with some DOC improvements from v3 if there are no more comments.

Thanks,
Janusz

> 
> maybe we should update the wording to minimize any confusions?
> 
> Michal
> 
> > + *
> > + * Looks up a PCI interface of a DRM device or a VF PCI device of the DRM 
> > PF using libpciaccess.
> > + *
> > + * Returns:
> > + * The pci_device, NULL on any failures.
> > + */
> > +struct pci_device *__igt_device_get_pci_device(int fd, int vf_id)
> >  {
> > struct igt_pci_addr pci_addr;
> > struct pci_device *pci

[Intel-gfx] [PATCH i-g-t] lib/intel_mmio: Fix mmapped resources not unmapped on fini

2022-03-01 Thread Janusz Krzysztofik
Commit 5f3cfa485eb4 ("lib: Use safe wrappers around libpciaccess
initialization functions") took care of not leaking memory allocated by
pci_system_init() but didn't take care of users potentially attempting to
reinitialize global data maintained by libpciaccess.  For example,
intel_register_access_init() mmaps device's PCI BAR0 resource with
pci_device_map_range() but intel_register_access_fini() doesn't unmap it
and next call to intel_register_access_init() fails on attempt to mmap it
again with pci_device_map_range().

Fix it, and also provide intel_mmio_umap_*() counterparts to public
functions intel_mmio_use_pci_bar() and intel_mmio_use_dump_file().

Signed-off-by: Janusz Krzysztofik 
---
 lib/intel_io.h   |  4 +++
 lib/intel_mmio.c | 65 ++--
 2 files changed, 62 insertions(+), 7 deletions(-)

diff --git a/lib/intel_io.h b/lib/intel_io.h
index 1cfe4fb6b9..ea2649d9bc 100644
--- a/lib/intel_io.h
+++ b/lib/intel_io.h
@@ -49,6 +49,8 @@ struct intel_register_map {
 
 struct intel_mmio_data {
void *igt_mmio;
+   size_t mmio_size;
+   struct pci_device *dev;
struct intel_register_map map;
uint32_t pci_device_id;
int key;
@@ -57,7 +59,9 @@ struct intel_mmio_data {
 
 void intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data,
struct pci_device *pci_dev);
+void intel_mmio_unmap_pci_bar(struct intel_mmio_data *mmio_data);
 void intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char *file);
+void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data);
 
 int intel_register_access_init(struct intel_mmio_data *mmio_data,
   struct pci_device *pci_dev, int safe, int fd);
diff --git a/lib/intel_mmio.c b/lib/intel_mmio.c
index 667a69f5aa..c8800a6d53 100644
--- a/lib/intel_mmio.c
+++ b/lib/intel_mmio.c
@@ -82,6 +82,8 @@ void *igt_global_mmio;
  * Sets also up mmio_data->igt_mmio to point at the data contained
  * in @file. This allows the same code to get reused for dumping and decoding
  * from running hardware as from register dumps.
+ *
+ * Users are expected to call intel_mmio_unmap_dump_file() after use.
  */
 void
 intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char *file)
@@ -99,11 +101,29 @@ intel_mmio_use_dump_file(struct intel_mmio_data 
*mmio_data, char *file)
igt_fail_on_f(mmio_data->igt_mmio == MAP_FAILED,
  "Couldn't mmap %s\n", file);
 
+   mmio_data->mmio_size = st.st_size;
igt_global_mmio = mmio_data->igt_mmio;
 
close(fd);
 }
 
+/**
+ * intel_mmio_unmap_dump_file:
+ * @mmio_data:  mmio structure for IO operations
+ *
+ * Unmaps a dump file mmapped with intel_mmio_use_dump_file()
+ */
+void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data)
+{
+   if (igt_warn_on_f(!mmio_data->mmio_size || mmio_data->dev,
+ "test bug: argument doesn't point to struct 
intel_mmio_data initialized with intel_mmio_use_dump_file()\n"))
+   return;
+
+   igt_global_mmio = NULL;
+   igt_debug_on(munmap(mmio_data->igt_mmio, mmio_data->mmio_size) < 0);
+   mmio_data->mmio_size = 0;
+}
+
 /**
  * intel_mmio_use_pci_bar:
  * @mmio_data:  mmio structure for IO operations
@@ -112,12 +132,14 @@ intel_mmio_use_dump_file(struct intel_mmio_data 
*mmio_data, char *file)
  * Fill a mmio_data stucture with igt_mmio to point at the mmio bar.
  *
  * @pci_dev can be obtained from intel_get_pci_device().
+ *
+ * Users are expected to call intel_mmio_unmap_pci_bar() after use.
  */
 void
 intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data, struct pci_device 
*pci_dev)
 {
uint32_t devid, gen;
-   int mmio_bar, mmio_size;
+   int mmio_bar;
int error;
 
memset(mmio_data, 0, sizeof(struct intel_mmio_data));
@@ -129,11 +151,11 @@ intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data, 
struct pci_device *pci
 
gen = intel_gen(devid);
if (gen < 3)
-   mmio_size = 512*1024;
+   mmio_data->mmio_size = 512*1024;
else if (gen < 5)
-   mmio_size = 512*1024;
+   mmio_data->mmio_size = 512*1024;
else
-   mmio_size = 2*1024*1024;
+   mmio_data->mmio_size = 2*1024*1024;
 
error = pci_device_map_range (pci_dev,
  pci_dev->regions[mmio_bar].base_addr,
@@ -141,10 +163,30 @@ intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data, 
struct pci_device *pci
  PCI_DEV_MAP_FLAG_WRITABLE,
  &mmio_data->igt_mmio);
 
-   igt_global_mmio = mmio_data->igt_mmio;
-
igt_fail_on_f(error != 0,
  "Couldn't map MMIO region\n");
+
+   mmio_data->dev = pci_dev;
+

[Intel-gfx] [PATCH v2 i-g-t] lib/intel_mmio: Fix mmapped resources not unmapped on fini

2022-03-01 Thread Janusz Krzysztofik
Commit 5f3cfa485eb4 ("lib: Use safe wrappers around libpciaccess
initialization functions") took care of not leaking memory allocated by
pci_system_init() but didn't take care of users potentially attempting to
reinitialize global data maintained by libpciaccess.  For example,
intel_register_access_init() mmaps device's PCI BAR0 resource with
pci_device_map_range() but intel_register_access_fini() doesn't unmap it
and next call to intel_register_access_init() fails on attempt to mmap it
again with pci_device_map_range().

Fix it, and also provide intel_mmio_umap_*() counterparts to public
functions intel_mmio_use_pci_bar() and intel_mmio_use_dump_file().

v2: apply last minute fixes, cached but unfortunately not committed before
    sending

Signed-off-by: Janusz Krzysztofik 
---
 lib/intel_io.h   |  4 +++
 lib/intel_mmio.c | 67 ++--
 2 files changed, 63 insertions(+), 8 deletions(-)

diff --git a/lib/intel_io.h b/lib/intel_io.h
index 1cfe4fb6b9..ea2649d9bc 100644
--- a/lib/intel_io.h
+++ b/lib/intel_io.h
@@ -49,6 +49,8 @@ struct intel_register_map {
 
 struct intel_mmio_data {
void *igt_mmio;
+   size_t mmio_size;
+   struct pci_device *dev;
struct intel_register_map map;
uint32_t pci_device_id;
int key;
@@ -57,7 +59,9 @@ struct intel_mmio_data {
 
 void intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data,
struct pci_device *pci_dev);
+void intel_mmio_unmap_pci_bar(struct intel_mmio_data *mmio_data);
 void intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char *file);
+void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data);
 
 int intel_register_access_init(struct intel_mmio_data *mmio_data,
   struct pci_device *pci_dev, int safe, int fd);
diff --git a/lib/intel_mmio.c b/lib/intel_mmio.c
index 667a69f5aa..cb8f9db2e5 100644
--- a/lib/intel_mmio.c
+++ b/lib/intel_mmio.c
@@ -82,6 +82,8 @@ void *igt_global_mmio;
  * Sets also up mmio_data->igt_mmio to point at the data contained
  * in @file. This allows the same code to get reused for dumping and decoding
  * from running hardware as from register dumps.
+ *
+ * Users are expected to call intel_mmio_unmap_dump_file() after use.
  */
 void
 intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char *file)
@@ -99,11 +101,29 @@ intel_mmio_use_dump_file(struct intel_mmio_data 
*mmio_data, char *file)
igt_fail_on_f(mmio_data->igt_mmio == MAP_FAILED,
  "Couldn't mmap %s\n", file);
 
+   mmio_data->mmio_size = st.st_size;
igt_global_mmio = mmio_data->igt_mmio;
 
close(fd);
 }
 
+/**
+ * intel_mmio_unmap_dump_file:
+ * @mmio_data:  mmio structure for IO operations
+ *
+ * Unmaps a dump file mmapped with intel_mmio_use_dump_file()
+ */
+void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data)
+{
+   if (igt_warn_on_f(!mmio_data->mmio_size || mmio_data->dev,
+ "test bug: argument doesn't point to struct 
intel_mmio_data initialized with intel_mmio_use_dump_file()\n"))
+   return;
+
+   igt_global_mmio = NULL;
+   igt_debug_on(munmap(mmio_data->igt_mmio, mmio_data->mmio_size) < 0);
+   mmio_data->mmio_size = 0;
+}
+
 /**
  * intel_mmio_use_pci_bar:
  * @mmio_data:  mmio structure for IO operations
@@ -112,12 +132,14 @@ intel_mmio_use_dump_file(struct intel_mmio_data 
*mmio_data, char *file)
  * Fill a mmio_data stucture with igt_mmio to point at the mmio bar.
  *
  * @pci_dev can be obtained from intel_get_pci_device().
+ *
+ * Users are expected to call intel_mmio_unmap_pci_bar() after use.
  */
 void
 intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data, struct pci_device 
*pci_dev)
 {
uint32_t devid, gen;
-   int mmio_bar, mmio_size;
+   int mmio_bar;
int error;
 
memset(mmio_data, 0, sizeof(struct intel_mmio_data));
@@ -129,22 +151,42 @@ intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data, 
struct pci_device *pci
 
gen = intel_gen(devid);
if (gen < 3)
-   mmio_size = 512*1024;
+   mmio_data->mmio_size = 512*1024;
else if (gen < 5)
-   mmio_size = 512*1024;
+   mmio_data->mmio_size = 512*1024;
else
-   mmio_size = 2*1024*1024;
+   mmio_data->mmio_size = 2*1024*1024;
 
error = pci_device_map_range (pci_dev,
  pci_dev->regions[mmio_bar].base_addr,
- mmio_size,
+ mmio_data->mmio_size,
  PCI_DEV_MAP_FLAG_WRITABLE,
  &mmio_data->igt_mmio);
 
-   igt_global_mmio = mmio_data->igt_mmio;
-
igt_fail_on_f(error != 0,
  

Re: [Intel-gfx] [igt-dev] [PATCH v2 i-g-t] lib/intel_mmio: Fix mmapped resources not unmapped on fini

2022-03-04 Thread Janusz Krzysztofik
Hi Kamil,

Thanks for review.

On Friday, 4 March 2022 16:14:05 CET Kamil Konieczny wrote:
> Hi Janusz,
> 
> Dnia 2022-03-01 at 15:07:55 +0100, Janusz Krzysztofik napisał(a):
> > Commit 5f3cfa485eb4 ("lib: Use safe wrappers around libpciaccess
> > initialization functions") took care of not leaking memory allocated by
> > pci_system_init() but didn't take care of users potentially attempting to
> > reinitialize global data maintained by libpciaccess.  For example,
> > intel_register_access_init() mmaps device's PCI BAR0 resource with
> > pci_device_map_range() but intel_register_access_fini() doesn't unmap it
> > and next call to intel_register_access_init() fails on attempt to mmap it
> > again with pci_device_map_range().
> -- ^
> imho you can cut here, no need to repeat it twice.

OK

> > 
> > Fix it, and also provide intel_mmio_umap_*() counterparts to public
> -- ^
> s/umap/unmap/

Thanks.

> > functions intel_mmio_use_pci_bar() and intel_mmio_use_dump_file().
> > 
> > v2: apply last minute fixes, cached but unfortunately not committed before
> > sending
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > ---
> >  lib/intel_io.h   |  4 +++
> >  lib/intel_mmio.c | 67 ++--
> >  2 files changed, 63 insertions(+), 8 deletions(-)
> > 
> > diff --git a/lib/intel_io.h b/lib/intel_io.h
> > index 1cfe4fb6b9..ea2649d9bc 100644
> > --- a/lib/intel_io.h
> > +++ b/lib/intel_io.h
> > @@ -49,6 +49,8 @@ struct intel_register_map {
> >  
> >  struct intel_mmio_data {
> > void *igt_mmio;
> > +   size_t mmio_size;
> > +   struct pci_device *dev;
> > struct intel_register_map map;
> > uint32_t pci_device_id;
> > int key;
> > @@ -57,7 +59,9 @@ struct intel_mmio_data {
> >  
> >  void intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data,
> > struct pci_device *pci_dev);
> > +void intel_mmio_unmap_pci_bar(struct intel_mmio_data *mmio_data);
> >  void intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char 
> > *file);
> > +void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data);
> >  
> >  int intel_register_access_init(struct intel_mmio_data *mmio_data,
> >struct pci_device *pci_dev, int safe, int fd);
> > diff --git a/lib/intel_mmio.c b/lib/intel_mmio.c
> > index 667a69f5aa..cb8f9db2e5 100644
> > --- a/lib/intel_mmio.c
> > +++ b/lib/intel_mmio.c
> > @@ -82,6 +82,8 @@ void *igt_global_mmio;
> >   * Sets also up mmio_data->igt_mmio to point at the data contained
> >   * in @file. This allows the same code to get reused for dumping and 
> > decoding
> >   * from running hardware as from register dumps.
> > + *
> > + * Users are expected to call intel_mmio_unmap_dump_file() after use.
> >   */
> >  void
> >  intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char *file)
> > @@ -99,11 +101,29 @@ intel_mmio_use_dump_file(struct intel_mmio_data 
> > *mmio_data, char *file)
> 
> imho at beginning of this function there should be check
> that igt_global_mmio == NULL, and the same check should be at
> other init functions.

No, what I think needs to be fixed are users who are still using 
igt_global_mmio while they should use the value they passed as the mmio 
argument to intel_mmio_use_*() or intel_register_access_init(), and that 
global variable should be dropped.  But first of all, that's not related to 
the issue this patch is trying to fix, then out of scope of this patch.

> Looks like we cannot mmap two different pcie cards at the same
> time with this lib.

We can, if we just ignore that depreciated global variable, I believe.

> > igt_fail_on_f(mmio_data->igt_mmio == MAP_FAILED,
> >   "Couldn't mmap %s\n", file);
> >  
> > +   mmio_data->mmio_size = st.st_size;
> > igt_global_mmio = mmio_data->igt_mmio;
> >  
> > close(fd);
> >  }
> >  
> > +/**
> > + * intel_mmio_unmap_dump_file:
> > + * @mmio_data:  mmio structure for IO operations
> > + *
> > + * Unmaps a dump file mmapped with intel_mmio_use_dump_file()
> > + */
> > +void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data)
> > +{
> > +   if (igt_warn_on_f(!mmio_data->mmio_size || mmio_data->dev,
> > + "test bug: argument doesn't point to struct 
> > intel_mmio_data initialized with intel_mmio_use_dump_file()\n"))
> 
> Please shor

[Intel-gfx] [PATCH v3 i-g-t] lib/intel_mmio: Fix mmapped resources not unmapped on fini

2022-03-07 Thread Janusz Krzysztofik
Commit 5f3cfa485eb4 ("lib: Use safe wrappers around libpciaccess
initialization functions") took care of not leaking memory allocated by
pci_system_init() but didn't take care of users potentially attempting to
reinitialize global data maintained by libpciaccess.  For example,
intel_register_access_init() mmaps device's PCI BAR0 resource with
pci_device_map_range() but intel_register_access_fini() doesn't unmap it
and next call to intel_register_access_init() fails on attempt to mmap it
again.

Fix it, and also provide intel_mmio_unmap_*() counterparts to public
functions intel_mmio_use_pci_bar() and intel_mmio_use_dump_file().

v2: apply last minute fixes, cached but unfortunately not committed before
sending
v3: use .pci_device_id field content as an indicator of arg initialization
via intel_register_access_init(),
  - improve checks of argument initialization status,
  - shorten warning messages (Kamil),
  - don't fill .mmio_size field until initialization succeeds (Kamil)

Signed-off-by: Janusz Krzysztofik 
Cc: Kamil Konieczny 
---
 lib/intel_io.h   |  4 +++
 lib/intel_mmio.c | 64 +---
 2 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/lib/intel_io.h b/lib/intel_io.h
index 1cfe4fb6b9..ea2649d9bc 100644
--- a/lib/intel_io.h
+++ b/lib/intel_io.h
@@ -49,6 +49,8 @@ struct intel_register_map {
 
 struct intel_mmio_data {
void *igt_mmio;
+   size_t mmio_size;
+   struct pci_device *dev;
struct intel_register_map map;
uint32_t pci_device_id;
int key;
@@ -57,7 +59,9 @@ struct intel_mmio_data {
 
 void intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data,
struct pci_device *pci_dev);
+void intel_mmio_unmap_pci_bar(struct intel_mmio_data *mmio_data);
 void intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char *file);
+void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data);
 
 int intel_register_access_init(struct intel_mmio_data *mmio_data,
   struct pci_device *pci_dev, int safe, int fd);
diff --git a/lib/intel_mmio.c b/lib/intel_mmio.c
index 667a69f5aa..d6ce0ee3ea 100644
--- a/lib/intel_mmio.c
+++ b/lib/intel_mmio.c
@@ -82,6 +82,8 @@ void *igt_global_mmio;
  * Sets also up mmio_data->igt_mmio to point at the data contained
  * in @file. This allows the same code to get reused for dumping and decoding
  * from running hardware as from register dumps.
+ *
+ * Users are expected to call intel_mmio_unmap_dump_file() after use.
  */
 void
 intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char *file)
@@ -99,11 +101,32 @@ intel_mmio_use_dump_file(struct intel_mmio_data 
*mmio_data, char *file)
igt_fail_on_f(mmio_data->igt_mmio == MAP_FAILED,
  "Couldn't mmap %s\n", file);
 
+   mmio_data->mmio_size = st.st_size;
igt_global_mmio = mmio_data->igt_mmio;
 
close(fd);
 }
 
+/**
+ * intel_mmio_unmap_dump_file:
+ * @mmio_data:  mmio structure for IO operations
+ *
+ * Unmaps a dump file mmapped with intel_mmio_use_dump_file()
+ */
+void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data)
+{
+   if (igt_warn_on_f(mmio_data->dev,
+ "test bug: arg initialized with 
intel_mmio_use_pci_bar()\n"))
+   return;
+   if (igt_warn_on_f(!mmio_data->mmio_size,
+ "test bug: arg not initialized\n"))
+   return;
+
+   igt_global_mmio = NULL;
+   igt_debug_on(munmap(mmio_data->igt_mmio, mmio_data->mmio_size) < 0);
+   mmio_data->mmio_size = 0;
+}
+
 /**
  * intel_mmio_use_pci_bar:
  * @mmio_data:  mmio structure for IO operations
@@ -112,6 +135,8 @@ intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, 
char *file)
  * Fill a mmio_data stucture with igt_mmio to point at the mmio bar.
  *
  * @pci_dev can be obtained from intel_get_pci_device().
+ *
+ * Users are expected to call intel_mmio_unmap_pci_bar() after use.
  */
 void
 intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data, struct pci_device 
*pci_dev)
@@ -141,10 +166,34 @@ intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data, 
struct pci_device *pci
  PCI_DEV_MAP_FLAG_WRITABLE,
  &mmio_data->igt_mmio);
 
-   igt_global_mmio = mmio_data->igt_mmio;
-
igt_fail_on_f(error != 0,
  "Couldn't map MMIO region\n");
+
+   mmio_data->mmio_size = mmio_size;
+   mmio_data->dev = pci_dev;
+   igt_global_mmio = mmio_data->igt_mmio;
+}
+
+/**
+ * intel_mmio_unmap_pci_bar:
+ * @mmio_data:  mmio structure for IO operations
+ *
+ * Unmaps a PCI BAR region mmapped with intel_mmio_use_pci_bar()
+ */
+void intel_mmio_unmap_pci_bar(struct intel_mmio_data *mmio_data)
+{
+   if (igt_warn_on_f(mmio_data-&g

Re: [Intel-gfx] [PATCH v3 i-g-t] lib/intel_mmio: Fix mmapped resources not unmapped on fini

2022-03-07 Thread Janusz Krzysztofik
Hi Kamil,

On Monday, 7 March 2022 14:23:30 CET Kamil Konieczny wrote:
> Hi Janusz,
> 
> Dnia 2022-03-07 at 09:26:43 +0100, Janusz Krzysztofik napisał(a):
> > Commit 5f3cfa485eb4 ("lib: Use safe wrappers around libpciaccess
> > initialization functions") took care of not leaking memory allocated by
> > pci_system_init() but didn't take care of users potentially attempting to
> > reinitialize global data maintained by libpciaccess.  For example,
> > intel_register_access_init() mmaps device's PCI BAR0 resource with
> > pci_device_map_range() but intel_register_access_fini() doesn't unmap it
> > and next call to intel_register_access_init() fails on attempt to mmap it
> > again.
> > 
> > Fix it, and also provide intel_mmio_unmap_*() counterparts to public
> > functions intel_mmio_use_pci_bar() and intel_mmio_use_dump_file().
> > 
> > v2: apply last minute fixes, cached but unfortunately not committed before
> > sending
> > v3: use .pci_device_id field content as an indicator of arg initialization
> > via intel_register_access_init(),
> >   - improve checks of argument initialization status,
> >   - shorten warning messages (Kamil),
> >   - don't fill .mmio_size field until initialization succeeds (Kamil)
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > Cc: Kamil Konieczny 
> > ---
> >  lib/intel_io.h   |  4 +++
> >  lib/intel_mmio.c | 64 +---
> >  2 files changed, 65 insertions(+), 3 deletions(-)
> > 
> > diff --git a/lib/intel_io.h b/lib/intel_io.h
> > index 1cfe4fb6b9..ea2649d9bc 100644
> > --- a/lib/intel_io.h
> > +++ b/lib/intel_io.h
> > @@ -49,6 +49,8 @@ struct intel_register_map {
> >  
> >  struct intel_mmio_data {
> > void *igt_mmio;
> > +   size_t mmio_size;
> > +   struct pci_device *dev;
> > struct intel_register_map map;
> > uint32_t pci_device_id;
> > int key;
> > @@ -57,7 +59,9 @@ struct intel_mmio_data {
> >  
> >  void intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data,
> > struct pci_device *pci_dev);
> > +void intel_mmio_unmap_pci_bar(struct intel_mmio_data *mmio_data);
> >  void intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char 
> > *file);
> > +void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data);
> >  
> >  int intel_register_access_init(struct intel_mmio_data *mmio_data,
> >struct pci_device *pci_dev, int safe, int fd);
> > diff --git a/lib/intel_mmio.c b/lib/intel_mmio.c
> > index 667a69f5aa..d6ce0ee3ea 100644
> > --- a/lib/intel_mmio.c
> > +++ b/lib/intel_mmio.c
> > @@ -82,6 +82,8 @@ void *igt_global_mmio;
> >   * Sets also up mmio_data->igt_mmio to point at the data contained
> >   * in @file. This allows the same code to get reused for dumping and 
> > decoding
> >   * from running hardware as from register dumps.
> > + *
> > + * Users are expected to call intel_mmio_unmap_dump_file() after use.
> >   */
> >  void
> >  intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char *file)
> > @@ -99,11 +101,32 @@ intel_mmio_use_dump_file(struct intel_mmio_data 
> > *mmio_data, char *file)
> > igt_fail_on_f(mmio_data->igt_mmio == MAP_FAILED,
> >   "Couldn't mmap %s\n", file);
> >  
> > +   mmio_data->mmio_size = st.st_size;
> > igt_global_mmio = mmio_data->igt_mmio;
> >  
> > close(fd);
> >  }
> >  
> > +/**
> > + * intel_mmio_unmap_dump_file:
> > + * @mmio_data:  mmio structure for IO operations
> > + *
> > + * Unmaps a dump file mmapped with intel_mmio_use_dump_file()
> > + */
> > +void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data)
> > +{
> > +   if (igt_warn_on_f(mmio_data->dev,
> > + "test bug: arg initialized with 
> > intel_mmio_use_pci_bar()\n"))
> > +   return;
> 
> Please add a global description about this kind of errors, this
> one is for using unmap when mmio was mmap-ed from other mmap
> type.

Can you please be more specific in what you mean by "global description of 
this kind of errors"?  A more detailed warning?  A comment?  If the latter 
then how would you like me to make it global?

If you just don't like the reference to intel_mmio_use_pci_bar() here then 
would you be satisfied with something like "test bug: arg initialized by a 
method other than intel_mmio_use_dump_file()\n"?

> > +   if (igt_warn

[Intel-gfx] [PATCH i-g-t] lib/intel_mmio: Fix mmapped resources not unmapped on fini

2022-03-08 Thread Janusz Krzysztofik
Commit 5f3cfa485eb4 ("lib: Use safe wrappers around libpciaccess
initialization functions") took care of not leaking memory allocated by
pci_system_init() but didn't take care of users potentially attempting to
reinitialize global data maintained by libpciaccess.  For example,
intel_register_access_init() mmaps device's PCI BAR0 resource with
pci_device_map_range() but intel_register_access_fini() doesn't unmap it
and next call to intel_register_access_init() fails on attempt to mmap it
again.

Fix it, and also provide intel_mmio_unmap_*() counterparts to public
functions intel_mmio_use_pci_bar() and intel_mmio_use_dump_file().

v2: apply last minute fixes, cached but unfortunately not committed before
sending
v3: use .pci_device_id field content as an indicator of arg initialization
via intel_register_access_init(),
  - improve checks of argument initialization status,
  - shorten warning messages (Kamil),
  - don't fill .mmio_size field until initialization succeeds (Kamil)
v4: fix condition of forcewake release, broken in v3,
  - improve comments and warning messages (Kamil)

Signed-off-by: Janusz Krzysztofik 
Cc: Kamil Konieczny 
---
 lib/intel_io.h   |  4 +++
 lib/intel_mmio.c | 64 +---
 2 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/lib/intel_io.h b/lib/intel_io.h
index 1cfe4fb6b9..ea2649d9bc 100644
--- a/lib/intel_io.h
+++ b/lib/intel_io.h
@@ -49,6 +49,8 @@ struct intel_register_map {
 
 struct intel_mmio_data {
void *igt_mmio;
+   size_t mmio_size;
+   struct pci_device *dev;
struct intel_register_map map;
uint32_t pci_device_id;
int key;
@@ -57,7 +59,9 @@ struct intel_mmio_data {
 
 void intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data,
struct pci_device *pci_dev);
+void intel_mmio_unmap_pci_bar(struct intel_mmio_data *mmio_data);
 void intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char *file);
+void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data);
 
 int intel_register_access_init(struct intel_mmio_data *mmio_data,
   struct pci_device *pci_dev, int safe, int fd);
diff --git a/lib/intel_mmio.c b/lib/intel_mmio.c
index 667a69f5aa..10b07aabe1 100644
--- a/lib/intel_mmio.c
+++ b/lib/intel_mmio.c
@@ -82,6 +82,8 @@ void *igt_global_mmio;
  * Sets also up mmio_data->igt_mmio to point at the data contained
  * in @file. This allows the same code to get reused for dumping and decoding
  * from running hardware as from register dumps.
+ *
+ * Users are expected to call intel_mmio_unmap_dump_file() after use.
  */
 void
 intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, char *file)
@@ -99,11 +101,32 @@ intel_mmio_use_dump_file(struct intel_mmio_data 
*mmio_data, char *file)
igt_fail_on_f(mmio_data->igt_mmio == MAP_FAILED,
  "Couldn't mmap %s\n", file);
 
+   mmio_data->mmio_size = st.st_size;
igt_global_mmio = mmio_data->igt_mmio;
 
close(fd);
 }
 
+/**
+ * intel_mmio_unmap_dump_file:
+ * @mmio_data:  mmio structure initialized with intel_mmio_use_dump_file()
+ *
+ * Unmaps a dump file mmapped with intel_mmio_use_dump_file()
+ */
+void intel_mmio_unmap_dump_file(struct intel_mmio_data *mmio_data)
+{
+   if (igt_warn_on_f(mmio_data->dev,
+ "test bug: arg initialized with a method other than 
intel_mmio_use_dump_file()\n"))
+   return;
+   if (igt_warn_on_f(!mmio_data->mmio_size,
+ "test bug: arg not initialized\n"))
+   return;
+
+   igt_global_mmio = NULL;
+   igt_debug_on(munmap(mmio_data->igt_mmio, mmio_data->mmio_size) < 0);
+   mmio_data->mmio_size = 0;
+}
+
 /**
  * intel_mmio_use_pci_bar:
  * @mmio_data:  mmio structure for IO operations
@@ -112,6 +135,8 @@ intel_mmio_use_dump_file(struct intel_mmio_data *mmio_data, 
char *file)
  * Fill a mmio_data stucture with igt_mmio to point at the mmio bar.
  *
  * @pci_dev can be obtained from intel_get_pci_device().
+ *
+ * Users are expected to call intel_mmio_unmap_pci_bar() after use.
  */
 void
 intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data, struct pci_device 
*pci_dev)
@@ -141,10 +166,34 @@ intel_mmio_use_pci_bar(struct intel_mmio_data *mmio_data, 
struct pci_device *pci
  PCI_DEV_MAP_FLAG_WRITABLE,
  &mmio_data->igt_mmio);
 
-   igt_global_mmio = mmio_data->igt_mmio;
-
igt_fail_on_f(error != 0,
  "Couldn't map MMIO region\n");
+
+   mmio_data->mmio_size = mmio_size;
+   mmio_data->dev = pci_dev;
+   igt_global_mmio = mmio_data->igt_mmio;
+}
+
+/**
+ * intel_mmio_unmap_pci_bar:
+ * @mmio_data:  mmio structure initialized with intel_mmio_use_pci_bar()

[Intel-gfx] [PATCH 1/2] drm/i915/gem: Avoid taking runtime-pm under the shrinker

2022-07-20 Thread Janusz Krzysztofik
From: Chris Wilson 

Inside the shrinker, we cannot wake the device as that may cause
recursion into fs-reclaim, so instead we only unbind vma if the device
is currently awake. (In order to provide reclaim while asleep, we do
wake the device up during kswapd -- we probably want to limit that wake
up if we have anything to shrink though!)

To avoid the same fs_reclaim recursion potential during
i915_gem_object_unbind, we acquire a wakeref there, see commit
3e817471a34c ("drm/i915/gem: Take runtime-pm wakeref prior to unbinding").
However, we use i915_gem_object_unbind from the shrinker path to make the
object available for shrinking and so we must make the wakeref acquisition
here conditional.

<4> [437.542172] ==
<4> [437.542174] WARNING: possible circular locking dependency detected
<4> [437.542176] 5.19.0-rc6-CI_DRM_11876-g2305e0d00665+ #1 Tainted: G U
<4> [437.542179] --
<4> [437.542181] kswapd0/93 is trying to acquire lock:
<4> [437.542183] 827a7608 (acpi_wakeup_lock){+.+.}-{3:3}, at: 
acpi_device_wakeup_disable+0x12/0x50
<4> [437.542191]
but task is already holding lock:
<4> [437.542194] 8275d360 (fs_reclaim){+.+.}-{0:0}, at: 
balance_pgdat+0x91/0x5c0
<4> [437.542199]
which lock already depends on the new lock.
<4> [437.542202]
the existing dependency chain (in reverse order) is:
<4> [437.542204]
-> #2 (fs_reclaim){+.+.}-{0:0}:
<4> [437.542207]fs_reclaim_acquire+0x9d/0xd0
<4> [437.542211]kmem_cache_alloc_trace+0x2a/0x250
<4> [437.542214]__acpi_device_add+0x263/0x3a0
<4> [437.542217]acpi_add_single_object+0x3ea/0x710
<4> [437.542220]acpi_bus_check_add+0xf7/0x240
<4> [437.54]acpi_bus_scan+0x34/0xf0
<4> [437.542224]acpi_scan_init+0xf5/0x241
<4> [437.542228]acpi_init+0x449/0x4aa
<4> [437.542230]do_one_initcall+0x53/0x2e0
<4> [437.542233]kernel_init_freeable+0x18f/0x1dd
<4> [437.542236]kernel_init+0x11/0x110
<4> [437.542239]ret_from_fork+0x1f/0x30
<4> [437.542241]
-> #1 (acpi_device_lock){+.+.}-{3:3}:
<4> [437.542245]__mutex_lock+0x97/0xf20
<4> [437.542246]acpi_enable_wakeup_device_power+0x30/0xf0
<4> [437.542249]__acpi_device_wakeup_enable+0x31/0x110
<4> [437.542252]acpi_pm_set_device_wakeup+0x55/0x100
<4> [437.542254]__pci_enable_wake+0x5e/0xa0
<4> [437.542257]pci_finish_runtime_suspend+0x32/0x70
<4> [437.542259]pci_pm_runtime_suspend+0xa3/0x160
<4> [437.542262]__rpm_callback+0x3d/0x110
<4> [437.542265]rpm_callback+0x54/0x60
<4> [437.542268]rpm_suspend.part.10+0x105/0x5a0
<4> [437.542270]pm_runtime_work+0x7d/0x1e0
<4> [437.542273]process_one_work+0x272/0x5c0
<4> [437.542276]worker_thread+0x37/0x370
<4> [437.542278]kthread+0xed/0x120
<4> [437.542280]ret_from_fork+0x1f/0x30
<4> [437.542282]
-> #0 (acpi_wakeup_lock){+.+.}-{3:3}:
<4> [437.542285]__lock_acquire+0x15ad/0x2940
<4> [437.542288]lock_acquire+0xd3/0x310
<4> [437.542291]__mutex_lock+0x97/0xf20
<4> [437.542293]acpi_device_wakeup_disable+0x12/0x50
<4> [437.542295]acpi_pm_set_device_wakeup+0x6e/0x100
<4> [437.542297]__pci_enable_wake+0x73/0xa0
<4> [437.542300]pci_pm_runtime_resume+0x45/0x90
<4> [437.542302]__rpm_callback+0x3d/0x110
<4> [437.542304]rpm_callback+0x54/0x60
<4> [437.542307]rpm_resume+0x54f/0x750
<4> [437.542309]__pm_runtime_resume+0x42/0x80
<4> [437.542311]__intel_runtime_pm_get+0x19/0x80 [i915]
<4> [437.542386]i915_gem_object_unbind+0x8f/0x3b0 [i915]
<4> [437.542487]i915_gem_shrink+0x634/0x850 [i915]
<4> [437.542584]i915_gem_shrinker_scan+0x3a/0xc0 [i915]
<4> [437.542679]shrink_slab.constprop.97+0x1a4/0x4f0
<4> [437.542684]shrink_node+0x21e/0x420
<4> [437.542687]balance_pgdat+0x241/0x5c0
<4> [437.542690]kswapd+0x229/0x4f0
<4> [437.542694]kthread+0xed/0x120
<4> [437.542697]ret_from_fork+0x1f/0x30
<4> [437.542701]
other info that might help us debug this:
<4> [437.542705] Chain exists of:
  acpi_wakeup_lock --> acpi_device_lock --> fs_reclaim
<4> [437.542713]  Possible unsafe locking scenario:
<4> [437.542716]CPU0CPU1
<4> [437.542719]
<4> [437.542721]   lock(fs_reclaim);
<4> [437.542725]    lock(acpi_device_lock);
<4

[Intel-gfx] [RFC PATCH 2/2] drm/i915/gem: Perform active shrinking from a background thread

2022-07-20 Thread Janusz Krzysztofik
From: Chris Wilson 

i915 is very greedy and will retain system pages for as long as the user
requires them; once acquired they will be only returned when the object
is freed. In order to respond to system memory pressure, i915 hooks into
the shrinker subsystem, designed to prune the filesystem caches, to
unbind and return system pages. However, we can only do so if the device
is active at that moment, as we cannot resume the device from inside
direct reclaim to unbind pages from the GPU, nor do we want to delay
random processes with unbound waits trying to reclaim active pages. To
workaround that quandary, what we avoided in direct reclaim we
delegated to kswapd, as that is run from process context outside of
direct reclaim and able to sleep and resume the device.

In practice, kswapd also uses fs_reclaim_acquire() around its
shrink_slab calls, prohibiting runtime resume. If we cannot wake the
device from idle, we will retain system memory indefinitely.

As we cannot take advantage of kswapd's decoupled process context to
perform an active reclaim of bound pages, spawn our own kthread to wait
under our wakeref. Similar to kswapd, there is no direct dependency on
the background task to direct reclaim (other than failure to promptly
return pages will implicitly result in oom), as such the task itself does
not inherit the fs-reclaim context. A page reclaimed by i915 will
typically not immediately be available for re-use, as it will require
writeback, and so only a future allocation attempt may benefit.
Concurrent page allocation attempts do not wait for either kswapd or our
own swapper task.

We mark our kthread as a memallocator (allowed to dip into memory
reserves, but not allowed to trigger direct reclaim) and mark up
the call to the shrinker with a fs_reclaim critical section. This
should prevent us from accidentally abusing the background swapper task,
and so the swapper kthread behaves like kswapd with the exception of
being allowed to wake the device up, and being decoupled from the
shrinker_rwsem.

Reported-by: Thomas Hellström 
Bug: https://gitlab.freedesktop.org/drm/intel/-/issues/6449
Fixes: 178a30c90ac7 ("drm/i915: Unbind objects in shrinker only if device is 
runtime active")
Signed-off-by: Chris Wilson 
Cc: Thomas Hellström 
Cc: Matthew Auld 
Cc: Tvrtko Ursulin 
Cc: sta...@vger.kernel.org # v4.8+
Signed-off-by: Janusz Krzysztofik 
---
 drivers/gpu/drm/i915/gem/i915_gem_shrinker.c | 134 +--
 drivers/gpu/drm/i915/i915_drv.h  |  15 +++
 2 files changed, 135 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c 
b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
index 1030053571a2..bc6c1978e64a 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
@@ -310,6 +310,113 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct 
shrink_control *sc)
return count;
 }
 
+static unsigned long run_swapper(struct drm_i915_private *i915,
+unsigned long target,
+unsigned long *nr_scanned)
+{
+   return i915_gem_shrink(NULL, i915,
+  target, nr_scanned,
+  I915_SHRINK_ACTIVE |
+  I915_SHRINK_BOUND |
+  I915_SHRINK_UNBOUND |
+  I915_SHRINK_WRITEBACK);
+}
+
+static int swapper(void *arg)
+{
+   struct drm_i915_private *i915 = arg;
+   atomic_long_t *target = &i915->mm.swapper.target;
+   unsigned int noreclaim_state;
+
+   /*
+* For us to be running the swapper implies that the system is under
+* enough memory pressure to be swapping. At that point, we both want
+* to ensure we make forward progress in order to reclaim pages from
+* the device and not contribute further to direct reclaim pressure. We
+* mark ourselves as a memalloc task in order to not trigger direct
+* reclaim ourselves, but dip into the system memory reserves for
+* shrinkers.
+*/
+   noreclaim_state = memalloc_noreclaim_save();
+
+   do {
+   intel_wakeref_t wakeref;
+
+   ___wait_var_event(target,
+ atomic_long_read(target) ||
+ kthread_should_stop(),
+ TASK_IDLE, 0, 0, schedule());
+   if (kthread_should_stop())
+   break;
+
+   with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
+   unsigned long nr_scan = atomic_long_xchg(target, 0);
+
+   /*
+* Now that we have woken up the device hierarchy,
+* act as a normal shrinker. Our shrinker is primarily
+* focussed on supporting direct reclaim (low latency,
+*

[Intel-gfx] [PATCH i-g-t] tests/core_hotunplug: Wait for device nodes to re-appear

2023-08-22 Thread Janusz Krzysztofik
Sometimes our health check is not able to find a device node (cardX or
renderY) after driver rebind or device rediscover.  Since device nodes are
recreated in detmpvfs asynchronously, give it a bit of time to do its job
before we try to reopen the device for health check.

(core_hotunplug:3612) DEBUG: Test requirement passed: priv->fd.drm == -1
(core_hotunplug:3612) DEBUG: reopening DRM device for health check
(core_hotunplug:3612) drmtest-DEBUG: Looking for devices to open using filter 
0: 
sys:/sys/devices/pci:4a/:4a:02.0/:4b:00.0/:4c:01.0/:4d:00.0
(core_hotunplug:3612) drmtest-DEBUG: Filter matched /dev/dri/card1 | 
/dev/dri/renderD128
(core_hotunplug:3612) drmtest-DEBUG: Opened previously opened device: 
/dev/dri/card1
(core_hotunplug:3612) DEBUG: running device sysfs healthcheck
(core_hotunplug:3612) DEBUG: closing health checked device instance
(core_hotunplug:3612) DEBUG: reopening render device for health check
(core_hotunplug:3612) drmtest-DEBUG: Looking for devices to open using filter 
0: 
sys:/sys/devices/pci:4a/:4a:02.0/:4b:00.0/:4c:01.0/:4d:00.0
(core_hotunplug:3612) drmtest-DEBUG: Filter matched /dev/dri/card1 | 
/dev/dri/renderD128
(core_hotunplug:3612) drmtest-INFO: Opened device: /dev/dri/renderD128
(core_hotunplug:3612) DEBUG: running device sysfs healthcheck
(core_hotunplug:3612) DEBUG: closing health checked device instance
(core_hotunplug:3612) DEBUG: Test requirement passed: healthcheck(priv, false)
(core_hotunplug:3612) DEBUG: Test requirement passed: priv->fd.drm_hc == -1
(core_hotunplug:3612) igt_kmod-DEBUG: Module snd_hda_intel unloaded immediately
(core_hotunplug:3612) INFO: Unloaded audio driver snd_hda_intel
(core_hotunplug:3612) DEBUG: unbinding the driver from the device
(core_hotunplug:3612) DEBUG: rebinding the driver to the device
(core_hotunplug:3612) INFO: Realoading snd_hda_intel
(core_hotunplug:3612) DEBUG: reopening DRM device for health check
(core_hotunplug:3612) drmtest-DEBUG: Looking for devices to open using filter 
0: 
sys:/sys/devices/pci:4a/:4a:02.0/:4b:00.0/:4c:01.0/:4d:00.0
(core_hotunplug:3612) drmtest-DEBUG: Filter matched /dev/dri/card1 |
(core_hotunplug:3612) drmtest-DEBUG: Opened previously opened device: 
/dev/dri/card1
(core_hotunplug:3612) DEBUG: running device sysfs healthcheck
(core_hotunplug:3612) DEBUG: closing health checked device instance
(core_hotunplug:3612) DEBUG: reopening render device for health check
(core_hotunplug:3612) drmtest-DEBUG: Looking for devices to open using filter 
0: 
sys:/sys/devices/pci:4a/:4a:02.0/:4b:00.0/:4c:01.0/:4d:00.0
(core_hotunplug:3612) drmtest-DEBUG: Filter matched /dev/dri/card1 |
(core_hotunplug:3612) CRITICAL: Test assertion failure function 
local_drm_open_driver, file 
../../../usr/src/igt-gpu-tools/tests/core_hotunplug.c:130:
(core_hotunplug:3612) CRITICAL: Failed assertion: fd_drm >= 0
(core_hotunplug:3612) CRITICAL: file descriptor fd_drm failed

Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/8830
Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/500
Signed-off-by: Janusz Krzysztofik 
Cc: Petri Latvala 
---
 tests/core_hotunplug.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tests/core_hotunplug.c b/tests/core_hotunplug.c
index 30d9a6a576..b254447c71 100644
--- a/tests/core_hotunplug.c
+++ b/tests/core_hotunplug.c
@@ -501,6 +501,9 @@ static void node_healthcheck(struct hotunplug *priv, 
unsigned flags)
 
 static bool healthcheck(struct hotunplug *priv, bool recover)
 {
+   /* give udev some time to recreate device nodes before we continue */
+   sleep(1);
+
/* device name may have changed, rebuild IGT device list */
igt_devices_scan(true);
 
-- 
2.41.0



[Intel-gfx] [RFC PATCH] kunit: Fix test log size limit too low for some tests

2023-08-30 Thread Janusz Krzysztofik
Now we have memory space available to a kunit test case log exposed via
debugfs limited to 2048 bytes, while some parametrized test cases, e.g.,
drm_framebuffer.drm_test_framebuffer_create, need more.  For this reason,
debugfs results from affected test cases get truncated silently, and
external tools that rely on parsing of debugfs results can fail.

Increase kunit test case log size limit to 4096 bytes.

Signed-off-by: Janusz Krzysztofik 
---
 include/kunit/test.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/kunit/test.h b/include/kunit/test.h
index d33114097d0d0..d20eb1884edfa 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -34,7 +34,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running);
 struct kunit;
 
 /* Size of log associated with test. */
-#define KUNIT_LOG_SIZE 2048
+#define KUNIT_LOG_SIZE 4096
 
 /* Maximum size of parameter description string. */
 #define KUNIT_PARAM_DESC_SIZE 128
-- 
2.41.0



Re: [Intel-gfx] [RFC PATCH] kunit: Fix test log size limit too low for some tests

2023-08-30 Thread Janusz Krzysztofik
On Wednesday, 30 August 2023 11:23:43 CEST David Gow wrote:
> On Wed, 30 Aug 2023 at 15:55, Janusz Krzysztofik
>  wrote:
> >
> > Now we have memory space available to a kunit test case log exposed via
> > debugfs limited to 2048 bytes, while some parametrized test cases, e.g.,
> > drm_framebuffer.drm_test_framebuffer_create, need more.  For this reason,
> > debugfs results from affected test cases get truncated silently, and
> > external tools that rely on parsing of debugfs results can fail.
> >
> > Increase kunit test case log size limit to 4096 bytes.
> >
> > Signed-off-by: Janusz Krzysztofik 
> > ---
> 
> There's a patch series we're hoping to take for 6.7 which allows the
> log to grow to fit whatever's written into it, which should make this
> patch obsolete:
> https://lore.kernel.org/linux-kselftest/20230828104111.2394344-1...@opensource.cirrus.com/T/
> 
> Would that work for you?

Yeah, that's going to work perfectly for us, thank you.

Janusz

> 
> -- David
> 
> >  include/kunit/test.h | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/include/kunit/test.h b/include/kunit/test.h
> > index d33114097d0d0..d20eb1884edfa 100644
> > --- a/include/kunit/test.h
> > +++ b/include/kunit/test.h
> > @@ -34,7 +34,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running);
> >  struct kunit;
> >
> >  /* Size of log associated with test. */
> > -#define KUNIT_LOG_SIZE 2048
> > +#define KUNIT_LOG_SIZE 4096
> >
> >  /* Maximum size of parameter description string. */
> >  #define KUNIT_PARAM_DESC_SIZE 128
> > --
> > 2.41.0
> >
> 






[Intel-gfx] [PATCH i-g-t] tests/i915: Exercise coherency of mmapped frame buffers

2023-05-15 Thread Janusz Krzysztofik
Visible glitches have been observed when running graphics applications on
Linux under Xen hypervisor.  Those observations have been confirmed with
failures from kms_pwrite_crc IGT test that verifies data coherency of DRM
frame buffer objects using hardware CRC checksums calculated by display
controllers, exposed to userspace via debugfs.  Since not all applications
exhibit the issue, we need to exercise more methods than just pwrite in
order to identify all affected processing paths.

Create a new test focused on exercising coherency of future scanout
buffers populated over mmap.  Cover all available mmap methods and caching
modes expected to be device coherent.

Link: https://gitlab.freedesktop.org/drm/intel/-/issues/7648
Signed-off-by: Janusz Krzysztofik 
---
 tests/i915/kms_fb_coherency.c | 354 ++
 tests/meson.build |   1 +
 2 files changed, 355 insertions(+)
 create mode 100644 tests/i915/kms_fb_coherency.c

diff --git a/tests/i915/kms_fb_coherency.c b/tests/i915/kms_fb_coherency.c
new file mode 100644
index 00..9223f13b05
--- /dev/null
+++ b/tests/i915/kms_fb_coherency.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ *
+ * Derived from tests/i915/kms_pwrite_crc.c
+ * Copyright © 2014 Intel Corporation
+ */
+
+/**
+ * TEST: kms_fb_coherency
+ * Description: Exercise coherency of future scanout buffer objects
+ */
+
+#include "igt.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+
+
+typedef struct {
+   int drm_fd;
+   igt_display_t display;
+   struct igt_fb fb[2];
+   igt_output_t *output;
+   igt_plane_t *primary;
+   enum pipe pipe;
+   igt_crc_t ref_crc;
+   igt_pipe_crc_t *pipe_crc;
+   uint32_t devid;
+} data_t;
+
+static void prepare_crtc(data_t *data)
+{
+   igt_display_t *display = &data->display;
+   igt_output_t *output = data->output;
+   drmModeModeInfo *mode;
+
+   igt_display_reset(display);
+   /* select the pipe we want to use */
+   igt_output_set_pipe(output, data->pipe);
+
+   mode = igt_output_get_mode(output);
+
+   /* create a white reference fb and flip to it */
+   igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+   DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR,
+   1.0, 1.0, 1.0, &data->fb[0]);
+
+   data->primary = igt_output_get_plane_type(output, 
DRM_PLANE_TYPE_PRIMARY);
+
+   igt_plane_set_fb(data->primary, &data->fb[0]);
+   igt_display_commit(display);
+
+   if (data->pipe_crc)
+   igt_pipe_crc_free(data->pipe_crc);
+
+   data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
+ IGT_PIPE_CRC_SOURCE_AUTO);
+
+   /* get reference crc for the white fb */
+   igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc);
+}
+
+static struct igt_fb *prepare_fb(data_t *data)
+{
+   igt_output_t *output = data->output;
+   struct igt_fb *fb = &data->fb[1];
+   drmModeModeInfo *mode;
+
+   prepare_crtc(data);
+
+   mode = igt_output_get_mode(output);
+
+   /* create a non-white fb we can overwrite later */
+   igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+ DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR, fb);
+
+   /* flip to it to make it UC/WC and fully flushed */
+   drmModeSetPlane(data->drm_fd,
+   data->primary->drm_plane->plane_id,
+   output->config.crtc->crtc_id,
+   fb->fb_id, 0,
+   0, 0, fb->width, fb->height,
+   0, 0, fb->width << 16, fb->height << 16);
+
+   /* flip back the original white buffer */
+   drmModeSetPlane(data->drm_fd,
+   data->primary->drm_plane->plane_id,
+   output->config.crtc->crtc_id,
+   data->fb[0].fb_id, 0,
+   0, 0, fb->width, fb->height,
+   0, 0, fb->width << 16, fb->height << 16);
+
+   if (!gem_has_lmem(data->drm_fd)) {
+   uint32_t caching;
+
+   /* make sure caching mode has become UC/WT */
+   caching = gem_get_caching(data->drm_fd, fb->gem_handle);
+   igt_assert(caching == I915_CACHING_NONE ||
+  caching == I915_CACHING_DISPLAY);
+   }
+
+   return fb;
+}
+
+static igt_crc_t get_buf_crc(data_t *data, void *buf, igt_fb_t *fb)
+{
+   igt_crc_t crc;
+
+   /* use memset to make the mmapped fb all white */
+   memset(buf, 0xff, fb->size);
+   munmap(buf, fb->size);
+
+   /* and flip to it */
+   drmModeSetPlane(data->drm_f

Re: [Intel-gfx] [PATCH i-g-t] tests/i915: Exercise coherency of mmapped frame buffers

2023-05-16 Thread Janusz Krzysztofik
Hi Kamil,

Thanks for review.

On Monday, 15 May 2023 22:02:51 CEST Kamil Konieczny wrote:
> Hi Janusz,
> 
> On 2023-05-15 at 10:50:20 +0200, Janusz Krzysztofik wrote:
> > Visible glitches have been observed when running graphics applications on
> > Linux under Xen hypervisor.  Those observations have been confirmed with
> > failures from kms_pwrite_crc IGT test that verifies data coherency of DRM
> > frame buffer objects using hardware CRC checksums calculated by display
> > controllers, exposed to userspace via debugfs.  Since not all applications
> > exhibit the issue, we need to exercise more methods than just pwrite in
> > order to identify all affected processing paths.
> > 
> > Create a new test focused on exercising coherency of future scanout
> > buffers populated over mmap.  Cover all available mmap methods and caching
> > modes expected to be device coherent.
> > 
> 
> +cc kms dev Bhanuprakash Modem

OK.

> 
> > Link: https://gitlab.freedesktop.org/drm/intel/-/issues/7648
> > Signed-off-by: Janusz Krzysztofik 
> > ---
> >  tests/i915/kms_fb_coherency.c | 354 ++
> >  tests/meson.build |   1 +
> >  2 files changed, 355 insertions(+)
> >  create mode 100644 tests/i915/kms_fb_coherency.c
> > 
> > diff --git a/tests/i915/kms_fb_coherency.c b/tests/i915/kms_fb_coherency.c
> > new file mode 100644
> > index 00..9223f13b05
> > --- /dev/null
> > +++ b/tests/i915/kms_fb_coherency.c
> > @@ -0,0 +1,354 @@
> > +// SPDX-License-Identifier: MIT
> > +/*
> > + * Copyright © 2023 Intel Corporation
> > + *
> > + * Derived from tests/i915/kms_pwrite_crc.c
> > + * Copyright © 2014 Intel Corporation
> 
> imho you do not need above two lines, you already wrote this
> in description.

OK.

> 
> > + */
> > +
> > +/**
> > + * TEST: kms_fb_coherency
> > + * Description: Exercise coherency of future scanout buffer objects
> > + */
> > +
> > +#include "igt.h"
> 
> Put this after sys includes below.

Copy-pasted from kms_pwrite_crc.c.  I'll fix it.

> 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> 
> Here put any igt include(s).

Yes.

> 
> > +
> > +typedef struct {
> > +   int drm_fd;
> > +   igt_display_t display;
> > +   struct igt_fb fb[2];
> > +   igt_output_t *output;
> > +   igt_plane_t *primary;
> > +   enum pipe pipe;
> > +   igt_crc_t ref_crc;
> > +   igt_pipe_crc_t *pipe_crc;
> > +   uint32_t devid;
> > +} data_t;
> > +
> > +static void prepare_crtc(data_t *data)
> > +{
> > +   igt_display_t *display = &data->display;
> > +   igt_output_t *output = data->output;
> > +   drmModeModeInfo *mode;
> > +
> > +   igt_display_reset(display);
> > +   /* select the pipe we want to use */
> > +   igt_output_set_pipe(output, data->pipe);
> > +
> > +   mode = igt_output_get_mode(output);
> > +
> > +   /* create a white reference fb and flip to it */
> > +   igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
> > +   DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR,
> > +   1.0, 1.0, 1.0, &data->fb[0]);
> > +
> > +   data->primary = igt_output_get_plane_type(output, 
> > DRM_PLANE_TYPE_PRIMARY);
> > +
> > +   igt_plane_set_fb(data->primary, &data->fb[0]);
> > +   igt_display_commit(display);
> > +
> > +   if (data->pipe_crc)
> > +   igt_pipe_crc_free(data->pipe_crc);
> > +
> > +   data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
> > + IGT_PIPE_CRC_SOURCE_AUTO);
> > +
> > +   /* get reference crc for the white fb */
> > +   igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc);
> > +}
> > +
> > +static struct igt_fb *prepare_fb(data_t *data)
> > +{
> > +   igt_output_t *output = data->output;
> > +   struct igt_fb *fb = &data->fb[1];
> > +   drmModeModeInfo *mode;
> > +
> > +   prepare_crtc(data);
> > +
> > +   mode = igt_output_get_mode(output);
> > +
> > +   /* create a non-white fb we can overwrite later */
> > +   igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
> > + DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR, fb);
> > +
> > +   /* flip to it to make it UC/WC and fully flushed */
> > +   drmModeSetPlane(da

[Intel-gfx] [PATCH i-g-t v2] tests/i915: Exercise coherency of mmapped frame buffers

2023-05-16 Thread Janusz Krzysztofik
Visible glitches have been observed when running graphics applications on
Linux under Xen hypervisor.  Those observations have been confirmed with
failures from kms_pwrite_crc IGT test that verifies data coherency of DRM
frame buffer objects using hardware CRC checksums calculated by display
controllers, exposed to userspace via debugfs.  Since not all applications
exhibit the issue, we need to exercise more methods than just pwrite in
order to identify all affected processing paths.

Create a new test focused on exercising coherency of future scanout
buffers populated over mmap.  Cover all available mmap methods and caching
modes expected to be device coherent.

v2: Drop unused functions -- left-overs from unsuccessful negative subtest
attempts requiring consistent crc mismatches in non-coherent modes,
  - since all subtests now call igt_assert_crc_equal(), move it from
subtest bodies to an updated and renamed helper,
  - drop "derived from ..." info from copyrights comment (Kamil),
  - fix order of includes (Kamil),
  - fix whitespace (Kamil),
  - Cc: Bhanuprakash (Kamil).

Link: https://gitlab.freedesktop.org/drm/intel/-/issues/7648
Signed-off-by: Janusz Krzysztofik 
Cc: Bhanuprakash Modem 
---
 tests/i915/kms_fb_coherency.c | 305 ++
 tests/meson.build |   1 +
 2 files changed, 306 insertions(+)
 create mode 100644 tests/i915/kms_fb_coherency.c

diff --git a/tests/i915/kms_fb_coherency.c b/tests/i915/kms_fb_coherency.c
new file mode 100644
index 00..b3f055c2b1
--- /dev/null
+++ b/tests/i915/kms_fb_coherency.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+/**
+ * TEST: kms_fb_coherency
+ * Description: Exercise coherency of future scanout buffer objects
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt.h"
+
+typedef struct {
+   int drm_fd;
+   igt_display_t display;
+   struct igt_fb fb[2];
+   igt_output_t *output;
+   igt_plane_t *primary;
+   enum pipe pipe;
+   igt_crc_t ref_crc;
+   igt_pipe_crc_t *pipe_crc;
+   uint32_t devid;
+} data_t;
+
+static void prepare_crtc(data_t *data)
+{
+   igt_display_t *display = &data->display;
+   igt_output_t *output = data->output;
+   drmModeModeInfo *mode;
+
+   igt_display_reset(display);
+   /* select the pipe we want to use */
+   igt_output_set_pipe(output, data->pipe);
+
+   mode = igt_output_get_mode(output);
+
+   /* create a white reference fb and flip to it */
+   igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+   DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR,
+   1.0, 1.0, 1.0, &data->fb[0]);
+
+   data->primary = igt_output_get_plane_type(output, 
DRM_PLANE_TYPE_PRIMARY);
+
+   igt_plane_set_fb(data->primary, &data->fb[0]);
+   igt_display_commit(display);
+
+   if (data->pipe_crc)
+   igt_pipe_crc_free(data->pipe_crc);
+
+   data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
+ IGT_PIPE_CRC_SOURCE_AUTO);
+
+   /* get reference crc for the white fb */
+   igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc);
+}
+
+static struct igt_fb *prepare_fb(data_t *data)
+{
+   igt_output_t *output = data->output;
+   struct igt_fb *fb = &data->fb[1];
+   drmModeModeInfo *mode;
+
+   prepare_crtc(data);
+
+   mode = igt_output_get_mode(output);
+
+   /* create a non-white fb we can overwrite later */
+   igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+ DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR, fb);
+
+   /* flip to it to make it UC/WC and fully flushed */
+   drmModeSetPlane(data->drm_fd,
+   data->primary->drm_plane->plane_id,
+   output->config.crtc->crtc_id,
+   fb->fb_id, 0,
+   0, 0, fb->width, fb->height,
+   0, 0, fb->width << 16, fb->height << 16);
+
+   /* flip back the original white buffer */
+   drmModeSetPlane(data->drm_fd,
+   data->primary->drm_plane->plane_id,
+   output->config.crtc->crtc_id,
+   data->fb[0].fb_id, 0,
+   0, 0, fb->width, fb->height,
+   0, 0, fb->width << 16, fb->height << 16);
+
+   if (!gem_has_lmem(data->drm_fd)) {
+   uint32_t caching;
+
+   /* make sure caching mode has become UC/WT */
+   caching = gem_get_caching(data->drm_fd, fb->gem_handle);
+   igt_assert(caching == I915_CACHING_NONE ||
+  

Re: [Intel-gfx] [PATCH i-g-t v2] tests/i915: Exercise coherency of mmapped frame buffers

2023-05-16 Thread Janusz Krzysztofik
Hi Andrzej,

Thanks for review.

On Tuesday, 16 May 2023 16:08:26 CEST Andrzej Hajda wrote:
> On 16.05.2023 12:05, Janusz Krzysztofik wrote:
> > Visible glitches have been observed when running graphics applications on
> > Linux under Xen hypervisor.  Those observations have been confirmed with
> > failures from kms_pwrite_crc IGT test that verifies data coherency of DRM
> > frame buffer objects using hardware CRC checksums calculated by display
> > controllers, exposed to userspace via debugfs.  Since not all applications
> > exhibit the issue, we need to exercise more methods than just pwrite in
> > order to identify all affected processing paths.
> > 
> > Create a new test focused on exercising coherency of future scanout
> > buffers populated over mmap.  Cover all available mmap methods and caching
> > modes expected to be device coherent.
> > 
> > v2: Drop unused functions -- left-overs from unsuccessful negative subtest
> >  attempts requiring consistent crc mismatches in non-coherent modes,
> >- since all subtests now call igt_assert_crc_equal(), move it from
> >  subtest bodies to an updated and renamed helper,
> >- drop "derived from ..." info from copyrights comment (Kamil),
> >- fix order of includes (Kamil),
> >- fix whitespace (Kamil),
> >- Cc: Bhanuprakash (Kamil).
> > 
> > Link: https://gitlab.freedesktop.org/drm/intel/-/issues/7648
> > Signed-off-by: Janusz Krzysztofik 
> > Cc: Bhanuprakash Modem 
> > ---
> >   tests/i915/kms_fb_coherency.c | 305 ++
> >   tests/meson.build |   1 +
> >   2 files changed, 306 insertions(+)
> >   create mode 100644 tests/i915/kms_fb_coherency.c
> > 
> > diff --git a/tests/i915/kms_fb_coherency.c b/tests/i915/kms_fb_coherency.c
> > new file mode 100644
> > index 00..b3f055c2b1
> > --- /dev/null
> > +++ b/tests/i915/kms_fb_coherency.c
> > @@ -0,0 +1,305 @@
> > +// SPDX-License-Identifier: MIT
> > +/*
> > + * Copyright © 2023 Intel Corporation
> > + */
> > +
> > +/**
> > + * TEST: kms_fb_coherency
> > + * Description: Exercise coherency of future scanout buffer objects
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#include "igt.h"
> > +
> > +typedef struct {
> > +   int drm_fd;
> > +   igt_display_t display;
> > +   struct igt_fb fb[2];
> > +   igt_output_t *output;
> > +   igt_plane_t *primary;
> > +   enum pipe pipe;
> > +   igt_crc_t ref_crc;
> > +   igt_pipe_crc_t *pipe_crc;
> > +   uint32_t devid;
> > +} data_t;
> > +
> > +static void prepare_crtc(data_t *data)
> > +{
> > +   igt_display_t *display = &data->display;
> > +   igt_output_t *output = data->output;
> > +   drmModeModeInfo *mode;
> > +
> > +   igt_display_reset(display);
> > +   /* select the pipe we want to use */
> > +   igt_output_set_pipe(output, data->pipe);
> > +
> > +   mode = igt_output_get_mode(output);
> > +
> > +   /* create a white reference fb and flip to it */
> > +   igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
> > +   DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR,
> > +   1.0, 1.0, 1.0, &data->fb[0]);
> > +
> > +   data->primary = igt_output_get_plane_type(output, 
> > DRM_PLANE_TYPE_PRIMARY);
> > +
> > +   igt_plane_set_fb(data->primary, &data->fb[0]);
> > +   igt_display_commit(display);
> > +
> > +   if (data->pipe_crc)
> > +   igt_pipe_crc_free(data->pipe_crc);
> > +
> > +   data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
> > + IGT_PIPE_CRC_SOURCE_AUTO);
> > +
> > +   /* get reference crc for the white fb */
> > +   igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc);
> > +}
> > +
> > +static struct igt_fb *prepare_fb(data_t *data)
> > +{
> > +   igt_output_t *output = data->output;
> > +   struct igt_fb *fb = &data->fb[1];
> > +   drmModeModeInfo *mode;
> > +
> > +   prepare_crtc(data);
> > +
> > +   mode = igt_output_get_mode(output);
> > +
> > +   /* create a non-white fb we can overwrite later */
> > +   igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
> > + DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR, fb);
>

[Intel-gfx] [PATCH i-g-t v3] tests/i915: Exercise coherency of mmapped frame buffers

2023-05-19 Thread Janusz Krzysztofik
Visible glitches have been observed when running graphics applications on
Linux under Xen hypervisor.  Those observations have been confirmed with
failures from kms_pwrite_crc IGT test that verifies data coherency of DRM
frame buffer objects using hardware CRC checksums calculated by display
controllers, exposed to userspace via debugfs.  Since not all applications
exhibit the issue, we need to exercise more methods than just pwrite in
order to identify all affected processing paths.

Create a new test focused on exercising coherency of future scanout
buffers populated over mmap.  Cover all available mmap methods and caching
modes expected to be device coherent.

v3: Drop redundant prerequisite checks (Andrzej),
  - if (condition) return; construct gives shorter code than
if (!condition) continue; (Andrzej),
  - gem_has_lmem() implies gem_has_mmap_offset(), flatten related nested
conditions.
v2: Drop unused functions -- left-overs from unsuccessful negative subtest
attempts requiring consistent crc mismatches in non-coherent modes,
  - since all subtests now call igt_assert_crc_equal(), move it from
subtest bodies to an updated and renamed helper,
  - drop "derived from ..." info from copyrights comment (Kamil),
  - fix order of includes (Kamil),
  - fix whitespace (Kamil),
  - Cc: Bhanuprakash (Kamil).

Link: https://gitlab.freedesktop.org/drm/intel/-/issues/7648
Cc: Bhanuprakash Modem 
Reviewed-by: Andrzej Hajda  # v2
Signed-off-by: Janusz Krzysztofik 
---
Hi Andrzej,

Your requested optimisations applied.  I've introduced one more
optimisation -- see changelog.  Please confirm your R-b still applies.

Thanks,
Janusz


 tests/i915/kms_fb_coherency.c | 288 ++
 tests/meson.build |   1 +
 2 files changed, 289 insertions(+)
 create mode 100644 tests/i915/kms_fb_coherency.c

diff --git a/tests/i915/kms_fb_coherency.c b/tests/i915/kms_fb_coherency.c
new file mode 100644
index 00..b530bf5dcd
--- /dev/null
+++ b/tests/i915/kms_fb_coherency.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+/**
+ * TEST: kms_fb_coherency
+ * Description: Exercise coherency of future scanout buffer objects
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "igt.h"
+
+typedef struct {
+   int drm_fd;
+   igt_display_t display;
+   struct igt_fb fb[2];
+   igt_output_t *output;
+   igt_plane_t *primary;
+   enum pipe pipe;
+   igt_crc_t ref_crc;
+   igt_pipe_crc_t *pipe_crc;
+   uint32_t devid;
+} data_t;
+
+static void prepare_crtc(data_t *data)
+{
+   igt_display_t *display = &data->display;
+   igt_output_t *output = data->output;
+   drmModeModeInfo *mode;
+
+   igt_display_reset(display);
+   /* select the pipe we want to use */
+   igt_output_set_pipe(output, data->pipe);
+
+   mode = igt_output_get_mode(output);
+
+   /* create a white reference fb and flip to it */
+   igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+   DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR,
+   1.0, 1.0, 1.0, &data->fb[0]);
+
+   data->primary = igt_output_get_plane_type(output, 
DRM_PLANE_TYPE_PRIMARY);
+
+   igt_plane_set_fb(data->primary, &data->fb[0]);
+   igt_display_commit(display);
+
+   if (data->pipe_crc)
+   igt_pipe_crc_free(data->pipe_crc);
+
+   data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
+ IGT_PIPE_CRC_SOURCE_AUTO);
+
+   /* get reference crc for the white fb */
+   igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc);
+}
+
+static struct igt_fb *prepare_fb(data_t *data)
+{
+   igt_output_t *output = data->output;
+   struct igt_fb *fb = &data->fb[1];
+   drmModeModeInfo *mode;
+
+   prepare_crtc(data);
+
+   mode = igt_output_get_mode(output);
+
+   /* create a non-white fb we can overwrite later */
+   igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+ DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR, fb);
+
+   /* flip to it to make it UC/WC and fully flushed */
+   drmModeSetPlane(data->drm_fd,
+   data->primary->drm_plane->plane_id,
+   output->config.crtc->crtc_id,
+   fb->fb_id, 0,
+   0, 0, fb->width, fb->height,
+   0, 0, fb->width << 16, fb->height << 16);
+
+   /* flip back the original white buffer */
+   drmModeSetPlane(data->drm_fd,
+   data->primary->drm_plane->plane_id,
+   output->config.crtc->crtc_id,
+   data-&g

Re: [Intel-gfx] [PATCH i-g-t v3] tests/i915: Exercise coherency of mmapped frame buffers

2023-05-19 Thread Janusz Krzysztofik
On Friday, 19 May 2023 12:28:49 CEST Andrzej Hajda wrote:
> On 19.05.2023 11:43, Janusz Krzysztofik wrote:
> > Visible glitches have been observed when running graphics applications on
> > Linux under Xen hypervisor.  Those observations have been confirmed with
> > failures from kms_pwrite_crc IGT test that verifies data coherency of DRM
> > frame buffer objects using hardware CRC checksums calculated by display
> > controllers, exposed to userspace via debugfs.  Since not all applications
> > exhibit the issue, we need to exercise more methods than just pwrite in
> > order to identify all affected processing paths.
> > 
> > Create a new test focused on exercising coherency of future scanout
> > buffers populated over mmap.  Cover all available mmap methods and caching
> > modes expected to be device coherent.
> > 
> > v3: Drop redundant prerequisite checks (Andrzej),
> >- if (condition) return; construct gives shorter code than
> >  if (!condition) continue; (Andrzej),
> >- gem_has_lmem() implies gem_has_mmap_offset(), flatten related nested
> >  conditions.
> > v2: Drop unused functions -- left-overs from unsuccessful negative subtest
> >  attempts requiring consistent crc mismatches in non-coherent modes,
> >- since all subtests now call igt_assert_crc_equal(), move it from
> >  subtest bodies to an updated and renamed helper,
> >- drop "derived from ..." info from copyrights comment (Kamil),
> >- fix order of includes (Kamil),
> >- fix whitespace (Kamil),
> >- Cc: Bhanuprakash (Kamil).
> > 
> > Link: https://gitlab.freedesktop.org/drm/intel/-/issues/7648
> > Cc: Bhanuprakash Modem 
> > Reviewed-by: Andrzej Hajda  # v2
> > Signed-off-by: Janusz Krzysztofik 
> > ---
> > Hi Andrzej,
> > 
> > Your requested optimisations applied.  I've introduced one more
> > optimisation -- see changelog.  Please confirm your R-b still applies.
> 
> Yes, it applies :)

Thank you, Andrzej, pushed.

Janusz

> 
> Regards
> Andrzej
> 
> > 
> > Thanks,
> > Janusz
> > 
> > 
> >   tests/i915/kms_fb_coherency.c | 288 ++
> >   tests/meson.build |   1 +
> >   2 files changed, 289 insertions(+)
> >   create mode 100644 tests/i915/kms_fb_coherency.c
> > 
> > diff --git a/tests/i915/kms_fb_coherency.c b/tests/i915/kms_fb_coherency.c
> > new file mode 100644
> > index 00..b530bf5dcd
> > --- /dev/null
> > +++ b/tests/i915/kms_fb_coherency.c
> > @@ -0,0 +1,288 @@
> > +// SPDX-License-Identifier: MIT
> > +/*
> > + * Copyright © 2023 Intel Corporation
> > + */
> > +
> > +/**
> > + * TEST: kms_fb_coherency
> > + * Description: Exercise coherency of future scanout buffer objects
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#include "igt.h"
> > +
> > +typedef struct {
> > +   int drm_fd;
> > +   igt_display_t display;
> > +   struct igt_fb fb[2];
> > +   igt_output_t *output;
> > +   igt_plane_t *primary;
> > +   enum pipe pipe;
> > +   igt_crc_t ref_crc;
> > +   igt_pipe_crc_t *pipe_crc;
> > +   uint32_t devid;
> > +} data_t;
> > +
> > +static void prepare_crtc(data_t *data)
> > +{
> > +   igt_display_t *display = &data->display;
> > +   igt_output_t *output = data->output;
> > +   drmModeModeInfo *mode;
> > +
> > +   igt_display_reset(display);
> > +   /* select the pipe we want to use */
> > +   igt_output_set_pipe(output, data->pipe);
> > +
> > +   mode = igt_output_get_mode(output);
> > +
> > +   /* create a white reference fb and flip to it */
> > +   igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
> > +   DRM_FORMAT_XRGB, DRM_FORMAT_MOD_LINEAR,
> > +   1.0, 1.0, 1.0, &data->fb[0]);
> > +
> > +   data->primary = igt_output_get_plane_type(output, 
> > DRM_PLANE_TYPE_PRIMARY);
> > +
> > +   igt_plane_set_fb(data->primary, &data->fb[0]);
> > +   igt_display_commit(display);
> > +
> > +   if (data->pipe_crc)
> > +   igt_pipe_crc_free(data->pipe_crc);
> > +
> > +   data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
> > + IGT_PIPE_CRC_SOURCE_AUTO);
> > +
> > +   /* get reference crc for the white fb */
> &g

Re: [Intel-gfx] [RESUBMIT][PATCH] x86/mm: Fix PAT bit missing from page protection modify mask

2023-06-05 Thread Janusz Krzysztofik
(fixed misspelled Cc: email address of intel-gfx list)

On Friday, 2 June 2023 16:53:30 CEST Juergen Gross wrote:
> On 02.06.23 16:48, Juergen Gross wrote:
> > On 02.06.23 16:43, Borislav Petkov wrote:
> >> On Thu, Jun 01, 2023 at 10:47:39AM +0200, Juergen Gross wrote:
> >>> As described in the commit message, this only works on bare metal due to 
the
> >>> PAT bit not being needed for WC mappings.
> >>>
> >>> Making this patch Xen specific would try to cure the symptoms without 
fixing
> >>> the underlying problem: _PAGE_PAT should be regarded the same way as the 
bits
> >>> for caching mode (_PAGE_CHG_MASK).
> >>
> >> So why isn't _PAGE_PAT part of _PAGE_CHG_MASK?
> > 
> > This would result in problems for large pages: _PAGE_PSE is at the same
> > position as _PAGE_PAT (large pages are using _PAGE_PAT_LARGE instead).
> > 
> > Yes, x86 ABI is a mess.
> 
> Oh, wait: I originally thought _PAGE_CHG_MASK would be used for large pages,
> too. There is _HPAGE_CHG_MASK for that purpose.

Since _HPAGE_CHG_MASK has the _PAGE_PSE aka _PAGE_PAT bit already set, while 
_PAGE_CHK_MASK has not, the real question is not about large pages processing, 
I believe, which won't change whether we add _PAGE_PAT to _PAGE_CHG_MASK or 
not.

If we extend _PAGE_CHG_MASK with _PAGE_PAT bit then its value will be not any 
different from _HPAGE_CHG_MASK.  Then, one may ask why _HPAGE_CHG_MASK, with 
_PAGE_PSE aka PAGE_PAT bit set unlike in _PAGE_CHG_MASK, was introduced once 
for use with large pages, and _PAGE_CHG_MASK left intact for use with standard 
pages, if we now think that adding that bit to _PAGE_CHG_MASK won't break 
processing of standard pages.

If we are sure that adding _PAGE_PAT to _PAGE_CHG_MASK won't break any of its 
users then let's go for it.

Thanks,
Janusz

> 
> So adding _PAGE_PAT to _PAGE_CHG_MASK and _PAGE_PAT_LARGE to _HPAGE_CHG_MASK
> should do the job. At least I hope so.
> 
> 
> Juergen
> 






[Intel-gfx] [PATCH i-g-t 00/17] Fix IGT Kunit implementation issues

2023-09-08 Thread Janusz Krzysztofik
Janusz Krzysztofik (17):
  lib/kunit: Drop unused file stream
  lib/kunit: Stop loading kunit module explicitly
  lib/kunit: Fix struct kmod_module kunit_kmod not freed
  lib/kunit: Optimize calls to igt_success/skip/fail()
  lib/kunit: Fix illegal igt_fail() calls inside subtest body
  lib/ktap: Make sure we fail on premature cancel
  lib/ktap: Don't ignore interrupt signals
  lib/kunit: Cancel KTP parser on module load failure
  lib/ktap: Drop is_running flag
  lib/ktap: Read /dev/kmsg in blocking mode
  lib/kunit: Fail / skip on kernel taint
  lib/ktap: Use IGT linked lists for storing KTAP results
  lib/ktap: Reimplement KTAP parser
  lib/kunit: Load test modules in background
  lib/kunit: Parse KTAP report from the main process thread
  lib/kunit: Strip "_test" or "_kunit" suffix from subtest names
  lib/kunit: Omit suite name prefix if the same as subtest name

 lib/igt_kmod.c  | 284 
 lib/igt_ktap.c  | 833 
 lib/igt_ktap.h  |  28 +-
 lib/tests/igt_ktap_parser.c | 235 ++
 lib/tests/meson.build   |   1 +
 tests/drm_mm.c  |  42 +-
 6 files changed, 728 insertions(+), 695 deletions(-)
 create mode 100644 lib/tests/igt_ktap_parser.c

-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 01/17] lib/kunit: Drop unused file stream

2023-09-08 Thread Janusz Krzysztofik
In the process of reviewing patches that introduced kunit support, I asked
once if we could use line buffered input instead of explicitly looking for
newlines in KTAP data.  While my idea was wrong because reading raw data
from /dev/kmsg already returns full log records that always end with a
newline, conversion of /dev/kmsg file descriptor to a file stream with
freopen() was added to the code.  However, that file stream has never been
used for line buffered input.  While the file stream is passed to
functions that actually read the data, there it is converted back to a
file descriptor with fileno() and the data is read with read().

Drop the unnecessary conversions and teach functions to accept and process
just the file descriptor of /dev/kmsg.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 12 +-
 lib/igt_ktap.c | 62 +++---
 lib/igt_ktap.h |  2 +-
 3 files changed, 31 insertions(+), 45 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 6205871791..97667a896f 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -758,7 +758,6 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
 {
struct igt_ktest tst;
struct kmod_module *kunit_kmod;
-   FILE *f;
bool is_builtin;
int ret;
struct ktap_test_results *results;
@@ -774,7 +773,6 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
 
if (igt_ktest_begin(&tst) != 0) {
igt_warn("Unable to begin ktest for %s\n", module_name);
-
igt_ktest_fini(&tst);
igt_fail(IGT_EXIT_ABORT);
}
@@ -791,14 +789,6 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
goto unload;
}
 
-   f = fdopen(tst.kmsg, "r");
-
-   if (f == NULL) {
-   igt_warn("Could not turn /dev/kmsg file descriptor into a FILE 
pointer\n");
-   fail = true;
-   goto unload;
-   }
-
/* The KUnit module is required for running any KUnit tests */
ret = igt_kmod_load("kunit", NULL);
if (ret) {
@@ -814,7 +804,7 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
 
is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
 
-   results = ktap_parser_start(f, is_builtin);
+   results = ktap_parser_start(tst.kmsg, is_builtin);
 
ret = igt_kmod_load(module_name, opts);
if (ret) {
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index ecdcb8d83d..123a40d183 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -16,7 +16,7 @@
 #define DELIMITER "-"
 
 struct ktap_parser_args {
-   FILE *fp;
+   int fd;
bool is_builtin;
volatile bool is_running;
int ret;
@@ -24,7 +24,7 @@ struct ktap_parser_args {
 
 static struct ktap_test_results results;
 
-static int log_to_end(enum igt_log_level level, FILE *f,
+static int log_to_end(enum igt_log_level level, int fd,
  char *record, const char *format, ...) 
__attribute__((format(printf, 4, 5)));
 
 /**
@@ -39,12 +39,11 @@ static int log_to_end(enum igt_log_level level, FILE *f,
  *
  * Returns: 0 for success, or -2 if there's an error reading from the file
  */
-static int log_to_end(enum igt_log_level level, FILE *f,
+static int log_to_end(enum igt_log_level level, int fd,
  char *record, const char *format, ...)
 {
va_list args;
const char *lend;
-   int f_fd = fileno(f);
 
/* Cutoff after newline character, in order to not display garbage */
char *cutoff = strchr(record, '\n');
@@ -61,7 +60,7 @@ static int log_to_end(enum igt_log_level level, FILE *f,
while (*lend == '\0') {
igt_log(IGT_LOG_DOMAIN, level, "%s", record);
 
-   while (read(f_fd, record, BUF_LEN) < 0) {
+   while (read(fd, record, BUF_LEN) < 0) {
if (!READ_ONCE(ktap_args.is_running)) {
igt_warn("ktap parser stopped\n");
return -2;
@@ -157,8 +156,8 @@ static int tap_version_present(char* record, bool 
print_info)
 
 /**
  * find_next_tap_subtest:
- * @fp: FILE pointer
- * @record: buffer used to read fp
+ * @fd: file descriptor
+ * @record: buffer used to read fd
  * @is_builtin: whether KUnit is built-in or not
  *
  * Returns:
@@ -167,11 +166,10 @@ static int tap_version_present(char* record, bool 
print_info)
  * -2 if there are problems while reading the file.
  * any other value corresponds to the amount of cases of the next (sub)test
  */
-static int find_next_tap_subtest(FILE *fp, char *record, char *test_name, bool 
is_builtin)
+static int find_next_tap_subtest(int fd, char *record, char *test_name, bool 
is_builtin)
 {
const char *test_lookup_str, *

[Intel-gfx] [PATCH i-g-t 02/17] lib/kunit: Stop loading kunit module explicitly

2023-09-08 Thread Janusz Krzysztofik
Since kmod functions we use for module loading can process module
dependencies, there is no need to load the "kunit" module explicitly
before loading a kunit test module.  For the same reason we already don't
unload the "kunit" module explicitly on cleanup.  Drop the unnecessary
operation.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 6 --
 1 file changed, 6 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 97667a896f..faf31afabc 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -789,12 +789,6 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
goto unload;
}
 
-   /* The KUnit module is required for running any KUnit tests */
-   ret = igt_kmod_load("kunit", NULL);
-   if (ret) {
-   skip = ret;
-   goto unload;
-   }
ret = kmod_module_new_from_name(kmod_ctx(), "kunit", &kunit_kmod);
if (ret) {
igt_warn("Unable to load KUnit\n");
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 04/17] lib/kunit: Optimize calls to igt_success/skip/fail()

2023-09-08 Thread Janusz Krzysztofik
Calling igt_success() explicitly at the end of subtest body is not needed.
Other calls to igt_success() can be usually avoided by inverting test
result checks.  Optimize the code that now calls igt_success().

Moreover, using more advanced variants of igt_skip() and igt_fail() where
applicable makes the code more compact.  Go for it.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 14 +++---
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 34ddec3fad..1d1cd51170 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -814,12 +814,8 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
if (READ_ONCE(results->head) != NULL) {
pthread_mutex_lock(&results->mutex);
 
-   igt_dynamic(results->head->test_name) {
-   if (READ_ONCE(results->head->passed))
-   igt_success();
-   else
-   igt_fail(IGT_EXIT_FAILURE);
-   }
+   igt_dynamic(results->head->test_name)
+   igt_assert(READ_ONCE(results->head->passed));
 
temp = results->head;
results->head = results->head->next;
@@ -834,8 +830,7 @@ unload:
 
igt_ktest_fini(&tst);
 
-   if (skip)
-   igt_skip("Skipping test, as probing KUnit module returned %d", 
skip);
+   igt_skip_on_f(skip, "Skipping test, as probing KUnit module failed\n");
 
if (fail)
igt_fail(IGT_EXIT_ABORT);
@@ -844,9 +839,6 @@ unload:
 
if (ret != 0)
igt_fail(IGT_EXIT_ABORT);
-
-   if (ret == 0)
-   igt_success();
 }
 
 void igt_kunit(const char *module_name, const char *name, const char *opts)
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 05/17] lib/kunit: Fix illegal igt_fail() calls inside subtest body

2023-09-08 Thread Janusz Krzysztofik
In a body of a subtest with dynamic sub-subtests, it is illegal to call
igt_fail() and its variants from outside of a dynamic sub-subtest body.
On the other hand, it is perfectly legal to call either igt_skip() and
friends or __igt_abort() or its variant from there.

In the current implementation of igt_kunit(), there are several places
where igt_fail() is called despite being illegal.  Moreover, it is called
with IGT_EXIT_ABORT as an argument with no good reason for using such
aggressive method that forces CI to trigger system reboot (in most cases
igt_runner can decide if abort is required).

Follow igt_kselftests() pattern more closely, where similar setup and
cleanup operations are performed but their potential errors are processed
in a more friendly way.  Move common cleanup and their corresponding setup
steps out of the subtest body.  Place the latter as requirements in a
preceding igt_fixture section.  Replace remaining illegal igt_fail() calls
with more friendly skips.  Let igt_runner decide if abort is needed.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 75 +++---
 1 file changed, 22 insertions(+), 53 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 1d1cd51170..78b8eb8f53 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -754,59 +754,27 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
  *
  * Returns: IGT default codes
  */
-static void __igt_kunit(const char *module_name, const char *opts)
+static void __igt_kunit(struct igt_ktest *tst, const char *opts)
 {
-   struct igt_ktest tst;
struct kmod_module *kunit_kmod;
bool is_builtin;
int ret;
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
-   int skip = 0;
-   bool fail = false;
-
-   /* get normalized module name */
-   if (igt_ktest_init(&tst, module_name) != 0) {
-   igt_warn("Unable to initialize ktest for %s\n", module_name);
-   igt_fail(IGT_EXIT_ABORT);
-   }
-
-   if (igt_ktest_begin(&tst) != 0) {
-   igt_warn("Unable to begin ktest for %s\n", module_name);
-   igt_ktest_fini(&tst);
-   igt_fail(IGT_EXIT_ABORT);
-   }
 
-   if (tst.kmsg < 0) {
-   igt_warn("Could not open /dev/kmsg\n");
-   fail = true;
-   goto unload;
-   }
+   igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n");
 
-   if (lseek(tst.kmsg, 0, SEEK_END)) {
-   igt_warn("Could not seek the end of /dev/kmsg\n");
-   fail = true;
-   goto unload;
-   }
-
-   ret = kmod_module_new_from_name(kmod_ctx(), "kunit", &kunit_kmod);
-   if (ret) {
-   igt_warn("Unable to load KUnit\n");
-   skip = ret;
-   goto unload;
-   }
+   igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
 
+   igt_skip_on(kmod_module_new_from_name(kmod_ctx(), "kunit", 
&kunit_kmod));
is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
kmod_module_unref(kunit_kmod);
 
-   results = ktap_parser_start(tst.kmsg, is_builtin);
+   results = ktap_parser_start(tst->kmsg, is_builtin);
 
-   ret = igt_kmod_load(module_name, opts);
-   if (ret) {
-   skip = ret;
-   igt_warn("Unable to load %s module\n", module_name);
-   ret = ktap_parser_stop();
-   goto unload;
+   if (igt_debug_on(igt_kmod_load(tst->module_name, opts) < 0)) {
+   igt_ignore_warn(ktap_parser_stop());
+   igt_skip("Unable to load %s module\n", tst->module_name);
}
 
while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != 
NULL)
@@ -825,24 +793,21 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
}
}
 
-unload:
-   igt_ktest_end(&tst);
-
-   igt_ktest_fini(&tst);
-
-   igt_skip_on_f(skip, "Skipping test, as probing KUnit module failed\n");
-
-   if (fail)
-   igt_fail(IGT_EXIT_ABORT);
-
ret = ktap_parser_stop();
 
-   if (ret != 0)
-   igt_fail(IGT_EXIT_ABORT);
+   igt_skip_on_f(ret, "KTAP parser failed\n");
 }
 
 void igt_kunit(const char *module_name, const char *name, const char *opts)
 {
+   struct igt_ktest tst;
+
+   if (igt_ktest_init(&tst, module_name) != 0)
+   return;
+
+   igt_fixture
+   igt_require(igt_ktest_begin(&tst) == 0);
+
/*
 * We need to use igt_subtest here, as otherwise it may crash with:
 *  skipping is allowed only in fixtures, subtests or igt_simple_main
@@ -854,7 +819,11 @@ void igt_kunit(const char *module_name, const char 

[Intel-gfx] [PATCH i-g-t 03/17] lib/kunit: Fix struct kmod_module kunit_kmod not freed

2023-09-08 Thread Janusz Krzysztofik
We obtain a kmod_module structure for kunit module in order to check if
it is modular or built-in, then we never release that structure.  Fix it.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index faf31afabc..34ddec3fad 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -797,6 +797,7 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
}
 
is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
+   kmod_module_unref(kunit_kmod);
 
results = ktap_parser_start(tst.kmsg, is_builtin);
 
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 06/17] lib/ktap: Make sure we fail on premature cancel

2023-09-08 Thread Janusz Krzysztofik
After loading a kunit test module that executes some kunit test cases, we
evaluate overall result of an IGT subtest that corresponds to that module
based on an error code returned by kunit_parser_stop() helper, obtained
from a .ret field of a ktap_args structure.  That code is now assigned to
that structure field right before completion of the KTAP parser thread
start routine.  If the thread is canceled for some reason then the return
code will be undefined.

Initialize the return code on KTAP parser startup with a value that
indicates a failure, then change it to success when so indicated by result
of KTAP parsing.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_ktap.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 123a40d183..84fb13218f 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -579,9 +579,7 @@ igt_ktap_parser_start:
 igt_ktap_parser_end:
results.still_running = false;
 
-   if (failed_tests || !found_tests)
-   ktap_args.ret = IGT_EXIT_FAILURE;
-   else
+   if (found_tests && !failed_tests)
ktap_args.ret = IGT_EXIT_SUCCESS;
 
return NULL;
@@ -598,6 +596,7 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
ktap_args.fd = fd;
ktap_args.is_builtin = is_builtin;
ktap_args.is_running = true;
+   ktap_args.ret = IGT_EXIT_FAILURE;
pthread_create(&ktap_parser_thread, NULL, igt_ktap_parser, NULL);
 
return &results;
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 07/17] lib/ktap: Don't ignore interrupt signals

2023-09-08 Thread Janusz Krzysztofik
While reading KTAP data from /dev/kmsg we now ignore interrupt signals
that may occur during read() and we continue reading the data.  No
explanation has been provided on what that could be needed for.

Always return with an error code to the caller when read() fails with
errno == EINTR, so igt_runner has no problems with killing us promptly
on timeout.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_ktap.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 84fb13218f..3cfb55ec97 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -67,7 +67,7 @@ static int log_to_end(enum igt_log_level level, int fd,
}
 
if (errno == EINTR)
-   continue;
+   return -2;
 
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
@@ -189,7 +189,7 @@ static int find_next_tap_subtest(int fd, char *record, char 
*test_name, bool is_
}
 
if (errno == EINTR)
-   continue;
+   return -2;
 
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
@@ -233,7 +233,7 @@ static int find_next_tap_subtest(int fd, char *record, char 
*test_name, bool is_
}
 
if (errno == EINTR)
-   continue;
+   return -2;
 
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
@@ -388,7 +388,7 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
}
 
if (errno == EINTR)
-   continue;
+   return -1;
 
if (errno == EAGAIN)
/* No records available */
@@ -541,7 +541,7 @@ igt_ktap_parser_start:
continue;
 
if (errno == EINTR)
-   continue;
+   goto igt_ktap_parser_end;
 
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. You may 
want to increase log_buf_len in kmcdline\n");
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 10/17] lib/ktap: Read /dev/kmsg in blocking mode

2023-09-08 Thread Janusz Krzysztofik
We obtain KTAP report from /dev/kmsg.  That file is now opened from
igt_ktest_begin(), a function originally designed for i915 selftests and
now reused with kunit tests.  The original intention of opening that file
was to dump kernel messages to stderr on selftest error.  For that
purpose, the file is now opened in non-blocking mode so we don't end up
waiting for more kernel messages than already available.  Since our ktap
parser code reuses the file descriptor, we now have to loop over
EAGAIN responses, waiting for more KTAP data.  Since we have no sleeps
inside those loops, extremely high CPU usage can be observed.

Simplify reading KTAP reports by first switching the file descriptor back
to blocking mode.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c |  7 -
 lib/igt_ktap.c | 81 ++
 2 files changed, 28 insertions(+), 60 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index fb0bd21ee5..020df286b8 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "igt_aux.h"
@@ -758,12 +759,16 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 {
struct kmod_module *kunit_kmod;
bool is_builtin;
-   int ret;
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
+   int flags, ret;
 
igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n");
 
+   flags = fcntl(tst->kmsg, F_GETFL, 0) & ~O_NONBLOCK;
+   igt_skip_on_f(fcntl(tst->kmsg, F_SETFL, flags) == -1,
+ "Could not set /dev/kmsg to blocking mode\n");
+
igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
 
igt_skip_on(kmod_module_new_from_name(kmod_ctx(), "kunit", 
&kunit_kmod));
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index fe77b62680..165f6b2cce 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -59,20 +59,12 @@ static int log_to_end(enum igt_log_level level, int fd,
while (*lend == '\0') {
igt_log(IGT_LOG_DOMAIN, level, "%s", record);
 
-   while (read(fd, record, BUF_LEN) < 0) {
-   if (errno == EINTR)
-   return -2;
-
-   if (errno == EPIPE) {
+   if (read(fd, record, BUF_LEN) < 0) {
+   if (errno == EPIPE)
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
-   return -2;
-   }
+   else if (errno != EINTR)
+   igt_warn("an error occurred while reading kmsg: 
%m\n");
 
-   if (errno == EAGAIN)
-   /* No records available */
-   continue;
-
-   igt_warn("kmsg truncated: unknown error (%m)\n");
return -2;
}
 
@@ -176,20 +168,12 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
return -1;
 
if (is_builtin) {
-   while (read(fd, record, BUF_LEN) < 0) {
-   if (errno == EINTR)
-   return -2;
-
-   if (errno == EPIPE) {
+   if (read(fd, record, BUF_LEN) < 0) {
+   if (errno == EPIPE)
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
-   return -2;
-   }
+   else if (errno != EINTR)
+   igt_warn("an error occurred while reading kmsg: 
%m\n");
 
-   if (errno == EAGAIN)
-   /* No records available */
-   continue;
-
-   igt_warn("kmsg truncated: unknown error (%m)\n");
return -2;
}
}
@@ -215,20 +199,12 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
if (cutoff)
cutoff[0] = '\0';
 
-   while (read(fd, record, BUF_LEN) < 0) {
-   if (errno == EINTR)
-   return -2;
-
-   if (errno == EPIPE) {
+   if (read(fd, record, BUF_LEN) < 0) {
+   if (errno == EPIPE)
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
-   return -2;
-   }
+   else if (errno !=

[Intel-gfx] [PATCH i-g-t 08/17] lib/kunit: Cancel KTP parser on module load failure

2023-09-08 Thread Janusz Krzysztofik
For our KTAP parser to be running in parallel with kunit test module
loading, we now start it in a separate thread before we load the module.
If the module loading fails then we join the KTAP parser thread right
after that failure.  If the KTAP thread sleeps for some reason then we
can fail to break the test immediately.

Cancel the KTAP parser thread right after module load error and before
joining it.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 1 +
 lib/igt_ktap.c | 6 ++
 lib/igt_ktap.h | 1 +
 3 files changed, 8 insertions(+)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 78b8eb8f53..fb0bd21ee5 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -773,6 +773,7 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
results = ktap_parser_start(tst->kmsg, is_builtin);
 
if (igt_debug_on(igt_kmod_load(tst->module_name, opts) < 0)) {
+   ktap_parser_cancel();
igt_ignore_warn(ktap_parser_stop());
igt_skip("Unable to load %s module\n", tst->module_name);
}
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 3cfb55ec97..1e75b2ec23 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -602,6 +602,12 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
return &results;
 }
 
+void ktap_parser_cancel(void)
+{
+   ktap_args.is_running = false;
+   pthread_cancel(ktap_parser_thread);
+}
+
 int ktap_parser_stop(void)
 {
ktap_args.is_running = false;
diff --git a/lib/igt_ktap.h b/lib/igt_ktap.h
index ea57c2bb9b..991800e912 100644
--- a/lib/igt_ktap.h
+++ b/lib/igt_ktap.h
@@ -45,6 +45,7 @@ struct ktap_test_results {
 
 
 struct ktap_test_results *ktap_parser_start(int fd, bool is_builtin);
+void ktap_parser_cancel(void);
 int ktap_parser_stop(void);
 
 #endif /* IGT_KTAP_H */
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 09/17] lib/ktap: Drop is_running flag

2023-09-08 Thread Janusz Krzysztofik
Since we now call pthread_cancel() when we want to stop KTAP parser before
it completes, and we take care of returning failure in that case as a
result of KTAP parsing, we no longer need to check a flag that indicates
whether we should continue parsing or return a failure.  Drop that flag.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_ktap.c | 32 
 1 file changed, 32 deletions(-)

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 1e75b2ec23..fe77b62680 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -18,7 +18,6 @@
 struct ktap_parser_args {
int fd;
bool is_builtin;
-   volatile bool is_running;
int ret;
 } ktap_args;
 
@@ -61,11 +60,6 @@ static int log_to_end(enum igt_log_level level, int fd,
igt_log(IGT_LOG_DOMAIN, level, "%s", record);
 
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -2;
-   }
-
if (errno == EINTR)
return -2;
 
@@ -183,11 +177,6 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
 
if (is_builtin) {
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -2;
-   }
-
if (errno == EINTR)
return -2;
 
@@ -227,11 +216,6 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
cutoff[0] = '\0';
 
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -2;
-   }
-
if (errno == EINTR)
return -2;
 
@@ -382,11 +366,6 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
 
for (int i = 0; i < test_count; i++) {
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -1;
-   }
-
if (errno == EINTR)
return -1;
 
@@ -523,19 +502,11 @@ void *igt_ktap_parser(void *unused)
failed_tests = false;
found_tests = false;
 
-   if (!READ_ONCE(ktap_args.is_running))
-   goto igt_ktap_parser_end;
-
 igt_ktap_parser_start:
test_name[0] = '\0';
test_name[BUF_LEN] = '\0';
 
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   goto igt_ktap_parser_end;
-   }
-
if (errno == EAGAIN)
/* No records available */
continue;
@@ -595,7 +566,6 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
 
ktap_args.fd = fd;
ktap_args.is_builtin = is_builtin;
-   ktap_args.is_running = true;
ktap_args.ret = IGT_EXIT_FAILURE;
pthread_create(&ktap_parser_thread, NULL, igt_ktap_parser, NULL);
 
@@ -604,13 +574,11 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
 
 void ktap_parser_cancel(void)
 {
-   ktap_args.is_running = false;
pthread_cancel(ktap_parser_thread);
 }
 
 int ktap_parser_stop(void)
 {
-   ktap_args.is_running = false;
pthread_join(ktap_parser_thread, NULL);
return ktap_args.ret;
 }
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 11/17] lib/kunit: Fail / skip on kernel taint

2023-09-08 Thread Janusz Krzysztofik
Similar to how igt_kselftest() handles kernel taints, fail current dynamic
sub-subtest and skip remaining ones when a kernel taint is detected during
execution of kunit test cases.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 020df286b8..988ac164cb 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -761,6 +761,7 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
bool is_builtin;
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
+   unsigned long taints;
int flags, ret;
 
igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n");
@@ -785,12 +786,20 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != 
NULL)
{
+   if (igt_kernel_tainted(&taints)) {
+   ktap_parser_cancel();
+   break;
+   }
+
if (READ_ONCE(results->head) != NULL) {
pthread_mutex_lock(&results->mutex);
 
-   igt_dynamic(results->head->test_name)
+   igt_dynamic(results->head->test_name) {
igt_assert(READ_ONCE(results->head->passed));
 
+   igt_fail_on(igt_kernel_tainted(&taints));
+   }
+
temp = results->head;
results->head = results->head->next;
free(temp);
@@ -801,6 +810,7 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
ret = ktap_parser_stop();
 
+   igt_skip_on(igt_kernel_tainted(&taints));
igt_skip_on_f(ret, "KTAP parser failed\n");
 }
 
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 12/17] lib/ktap: Use IGT linked lists for storing KTAP results

2023-09-08 Thread Janusz Krzysztofik
For code simplicity and clarity, use existing IGT linked lists library
instead of open coding a custom implementation of a list of KTAP results.

While being at it, flatten the code by inverting a check for pending
results.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 28 
 lib/igt_ktap.c | 25 +
 lib/igt_ktap.h |  6 --
 3 files changed, 25 insertions(+), 34 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 988ac164cb..c692954911 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -760,7 +760,6 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
struct kmod_module *kunit_kmod;
bool is_builtin;
struct ktap_test_results *results;
-   struct ktap_test_results_element *temp;
unsigned long taints;
int flags, ret;
 
@@ -784,28 +783,33 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
igt_skip("Unable to load %s module\n", tst->module_name);
}
 
-   while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != 
NULL)
+   while (READ_ONCE(results->still_running) || 
!igt_list_empty(&results->list))
{
+   struct ktap_test_results_element *result;
+
if (igt_kernel_tainted(&taints)) {
ktap_parser_cancel();
break;
}
 
-   if (READ_ONCE(results->head) != NULL) {
-   pthread_mutex_lock(&results->mutex);
+   pthread_mutex_lock(&results->mutex);
+   if (igt_list_empty(&results->list)) {
+   pthread_mutex_unlock(&results->mutex);
+   continue;
+   }
 
-   igt_dynamic(results->head->test_name) {
-   igt_assert(READ_ONCE(results->head->passed));
+   result = igt_list_first_entry(&results->list, result, link);
 
-   igt_fail_on(igt_kernel_tainted(&taints));
-   }
+   igt_list_del(&result->link);
+   pthread_mutex_unlock(&results->mutex);
 
-   temp = results->head;
-   results->head = results->head->next;
-   free(temp);
+   igt_dynamic(result->test_name) {
+   igt_assert(READ_ONCE(result->passed));
 
-   pthread_mutex_unlock(&results->mutex);
+   igt_fail_on(igt_kernel_tainted(&taints));
}
+
+   free(result);
}
 
ret = ktap_parser_stop();
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 165f6b2cce..5e9967f980 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -12,6 +12,7 @@
 #include "igt_aux.h"
 #include "igt_core.h"
 #include "igt_ktap.h"
+#include "igt_list.h"
 
 #define DELIMITER "-"
 
@@ -335,7 +336,7 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
   bool *found_tests, bool is_builtin)
 {
char record[BUF_LEN + 1];
-   struct ktap_test_results_element *r, *temp;
+   struct ktap_test_results_element *r;
int internal_test_count;
char test_name[BUF_LEN + 1];
char base_test_name_for_next_level[BUF_LEN + 1];
@@ -403,17 +404,9 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
r->test_name[BUF_LEN] = '\0';
 
r->passed = false;
-   r->next = NULL;
 
pthread_mutex_lock(&results.mutex);
-   if (results.head == NULL) {
-   results.head = r;
-   } else {
-   temp = results.head;
-   while (temp->next != NULL)
-   temp = temp->next;
-   temp->next = r;
-   }
+   igt_list_add_tail(&r->link, &results.list);
pthread_mutex_unlock(&results.mutex);
 
test_name[0] = '\0';
@@ -431,17 +424,9 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
r->test_name[BUF_LEN] = '\0';
 
r->passed = true;
-   r->next = NULL;
 
pthread_mutex_lock(&results.mutex);
-   if (results.head == NULL) {
-   results.head = r;
-   } else {
-   temp = results.hea

[Intel-gfx] [PATCH i-g-t 13/17] lib/ktap: Reimplement KTAP parser

2023-09-08 Thread Janusz Krzysztofik
Current implementation of KTAP parser suffers from several issues:
- in most cases, kernel messages that are not part of KTAP output but
  happen to appear in between break the parser,
- results from parametrized test cases, not preceded with a "1..N" test
  plan, break the parser,
- skips are not supported, reported as success,
- IGT results from all 3 kunit test nesting levels, i.e., from
  parametrized subtests (should those were fixed to work correctly), test
  cases and test suites, are reported individually as if all those items
  were executed sequentially, all at the same level of nesting, which can
  be confusing to igt_runner,
- the parser is not only parsing the data, but also handles data input
  from a /dev/kmsg like source, which is integrated into it, making it
  hard if not impossible to feed KTAP data from different sources,
  including mock sources,
- since the parser has been designed for running it in a separate thread,
  it's not possible to use igt_skip() nor igt_fail() and friends
  immediately when a result is available, only pass it to the main thread
  over a buffer.  As a consequence, it is virtually impossible to
  synchronize IGT output with KTAP output.

Fixing the existing parser occurred more complicated than re-implementing
it from scratch.  This patch provides a new implementation.

Only results from kunit test cases are reported as results of IGT dynamic
sub-subtests.  Results from individual parametrized subtests have been
considered problematic since many of them provide multi-word descriptions
in place of single-word subtest names.  If a parametrized test case fails
then full KTAP output from its subtests, potentially mixed with
accompanying kernel messages, is available in dmesg for analysis so users
can still find out which individual subtests succeeded and which failed.

Results from test suites level are also omitted in faith that IGT can
handle aggregation of results from individual kunit test cases reported as
IGT dynamic sub-subtests and report those aggregated results correctly as
results from an IGT dynamic subtest.  That 1:1 mapping of kunit test
suites to IGT dynamic subtests now works perfectly for modules that
provide only one test suite, which is the case for all kunit test modules
now existing under drivers/gpu/drm, and the most common case among all
kunit test modules in the whole kernel tree.

New igt_ktap functions can be called directly from igt_kunit subtest body,
but for this patch, the old igt_ktap_parser() function that runs in a
separate thread has been preserved, only modified to use the new
implementation and translate results from those new functions to legacy
format.  Unlike the former implementation, translation of kunit names to
IGT names is handled outside the parser itself, though for now it is still
performed inside the legacy igt_ktap_parser() function.

For better readability of the patch, no longer used functions have been
left untouched, only tagged with __maybe_unused to shut up compiler
warnings / errors.  Kunit library functions will be modified to use the
new igt_ktap interface, and those old ktap functions removed by follow-
up patches.

A test with example subtests that feed igt_ktap_parse() function with some
example data and verifies correctness of their parsing is also provided.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_ktap.c  | 422 
 lib/igt_ktap.h  |  15 ++
 lib/tests/igt_ktap_parser.c | 235 
 lib/tests/meson.build   |   1 +
 4 files changed, 634 insertions(+), 39 deletions(-)
 create mode 100644 lib/tests/igt_ktap_parser.c

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 5e9967f980..d46a2433e5 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: MIT
 /*
  * Copyright © 2023 Isabella Basso do Amaral 
+ * Copyright © 2023 Intel Corporation
  */
 
 #include 
@@ -8,12 +9,310 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
 #include "igt_aux.h"
 #include "igt_core.h"
 #include "igt_ktap.h"
 #include "igt_list.h"
 
+enum ktap_phase {
+   KTAP_START,
+   SUITE_COUNT,
+   SUITE_START,
+   SUITE_NAME,
+   CASE_COUNT,
+   CASE_NAME,
+   SUB_RESULT,
+   CASE_RESULT,
+   SUITE_RESULT,
+};
+
+struct igt_ktap_results {
+   enum ktap_phase expect;
+   unsigned int suite_count;
+   unsigned int suite_last;
+   char *suite_name;
+   unsigned int case_count;
+   unsigned int case_last;
+   char *case_name;
+   unsigned int sub_last;
+   struct igt_list_head *results;
+};
+
+/**
+ * igt_ktap_parse:
+ *
+ * This function parses a line of text for KTAP report data
+ * and passes results back to IGT kunit layer.
+ */
+int igt_ktap_parse(const char *buf, struct igt_ktap_results *ktap)
+{
+   char *suite_name = NULL, *case_name = NULL, *msg = NU

[Intel-gfx] [PATCH i-g-t 15/17] lib/kunit: Parse KTAP report from the main process thread

2023-09-08 Thread Janusz Krzysztofik
There was an attempt to parse KTAP reports in the background while a kunit
test module is loading.  However, since dynamic sub-subtests can be
executed only from the main thread, that attempt was not quite successful,
as IGT results from all executed kunit test cases were generated only
after loading of kunit test module completed.

Now that the parser maintains its state and we can call it separately for
each input line of a KTAP report, it is perfectly possible to call the
parser from the main thread while the module is loading in the background,
and convert results from kunit test cases immediately to results of IGT
dynamic sub-subtests by running an igt_dynamic() section for each result
as soon as returned by the parser.

Drop igt_ktap_parser() thread and execute igt_dynamic() for each kunit
result obtained from igt_ktap_parse() called from the main thread.

Also, drop no longer needed functions from igt_ktap soruces.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 158 +++---
 lib/igt_ktap.c | 568 -
 lib/igt_ktap.h |  22 --
 3 files changed, 123 insertions(+), 625 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index bbde3929f2..46a6f81e73 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2016 Intel Corporation
+ * Copyright © 2016-2023 Intel Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -26,7 +26,10 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
+#include 
 
 #include "igt_aux.h"
 #include "igt_core.h"
@@ -762,6 +765,54 @@ static void *modprobe_task(void *arg)
return NULL;
 }
 
+static int kunit_kmsg_result_get(struct igt_list_head *results,
+int fd, struct igt_ktap_results *ktap)
+{
+   char record[BUF_LEN + 1], *buf;
+   int ret;
+
+   while (igt_list_empty(results) &&
+  (ret = read(fd, record, BUF_LEN), ret > 0)) {
+   /* skip kmsg continuation lines */
+   if (igt_debug_on(*record == ' '))
+   continue;
+
+   /* NULL-terminate the record */
+   record[ret] = '\0';
+
+   /* detect start of log message, continue if not found */
+   buf = strchrnul(record, ';');
+   if (igt_debug_on(*buf == '\0'))
+   continue;
+   buf++;
+
+   ret = igt_ktap_parse(buf, ktap);
+   if (ret != -EINPROGRESS)
+   break;
+   }
+
+   return ret;
+}
+
+static void kunit_result_free(struct igt_ktap_result *r,
+ char **suite_name, char **case_name)
+{
+   igt_list_del(&r->link);
+
+   if (r->suite_name != *suite_name) {
+   free(*suite_name);
+   *suite_name = r->suite_name;
+   }
+
+   if (r->case_name != *case_name) {
+   free(*case_name);
+   *case_name = r->case_name;
+   }
+
+   free(r->msg);
+   free(r);
+}
+
 /**
  * igt_kunit:
  * @module_name: the name of the module
@@ -774,10 +825,11 @@ static void *modprobe_task(void *arg)
 static void __igt_kunit(struct igt_ktest *tst, const char *opts)
 {
struct modprobe_data modprobe = { tst->kmod, opts, 0, };
-   struct kmod_module *kunit_kmod;
-   bool is_builtin;
-   struct ktap_test_results *results;
+   char *suite_name = NULL, *case_name = NULL;
+   struct igt_ktap_result *r, *rn;
+   struct igt_ktap_results *ktap;
pthread_t modprobe_thread;
+   IGT_LIST_HEAD(results);
unsigned long taints;
int flags, ret;
 
@@ -787,49 +839,76 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
igt_skip_on_f(fcntl(tst->kmsg, F_SETFL, flags) == -1,
  "Could not set /dev/kmsg to blocking mode\n");
 
-   igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
-
-   igt_skip_on(kmod_module_new_from_name(kmod_ctx(), "kunit", 
&kunit_kmod));
-   is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
-   kmod_module_unref(kunit_kmod);
+   ktap = igt_ktap_alloc(&results);
+   igt_require(ktap);
 
-   results = ktap_parser_start(tst->kmsg, is_builtin);
+   igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
 
if (igt_debug_on(pthread_create(&modprobe_thread, NULL,
modprobe_task, &modprobe))) {
-   ktap_parser_cancel();
-   igt_ignore_warn(ktap_parser_stop());
+   igt_ktap_free(ktap);
igt_skip("Failed to create a modprobe thread\n");
}
 
-   while (READ_ONCE(results->

[Intel-gfx] [PATCH i-g-t 16/17] lib/kunit: Strip "_test" or "_kunit" suffix from subtest names

2023-09-08 Thread Janusz Krzysztofik
If a user (an IGT test) doesn't provide a subtest name when calling
igt_kunit() then we now use the requested kernel module name as IGT
subtest name.  Since names of kunit test modules usually end with a
"_test" or "_kunit" suffix, those parts of the names don't carry any
useful information.  Strip those suffixes from IGT subtest names.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 26 ++
 tests/drm_mm.c | 42 +-
 2 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 46a6f81e73..ddd5499f5e 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -944,8 +944,29 @@ void igt_kunit(const char *module_name, const char *name, 
const char *opts)
if (igt_ktest_init(&tst, module_name) != 0)
return;
 
-   igt_fixture
+   /*
+* If the caller (an IGT test) provides no subtest name then we
+* take the module name, drop the trailing "_test" or "_kunit"
+* suffix, if any, and use the result as our IGT subtest name.
+*/
+   if (!name) {
+   name = strdup(module_name);
+   if (name) {
+   char *suffix = strstr(name, "_test");
+
+   if (!suffix)
+   suffix = strstr(name, "_kunit");
+
+   if (suffix)
+   *suffix = '\0';
+   }
+   }
+
+   igt_fixture {
+   igt_require(name);
+
igt_require(igt_ktest_begin(&tst) == 0);
+   }
 
/*
 * We need to use igt_subtest here, as otherwise it may crash with:
@@ -954,9 +975,6 @@ void igt_kunit(const char *module_name, const char *name, 
const char *opts)
 * proper namespace for dynamic subtests, with is required for CI
 * and for documentation.
 */
-   if (name == NULL)
-   name = module_name;
-
igt_subtest_with_dynamic(name)
__igt_kunit(&tst, opts);
 
diff --git a/tests/drm_mm.c b/tests/drm_mm.c
index 9a8b3f3fcb..e6ba224745 100644
--- a/tests/drm_mm.c
+++ b/tests/drm_mm.c
@@ -29,123 +29,123 @@
  * Feature: mapping
  * Run type: FULL
  *
- * SUBTEST: drm_mm_test
+ * SUBTEST: drm_mm
  *
- * SUBTEST: drm_mm_test@align
+ * SUBTEST: drm_mm@align
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@align32
+ * SUBTEST: drm_mm@align32
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@align64
+ * SUBTEST: drm_mm@align64
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@bottomup
+ * SUBTEST: drm_mm@bottomup
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@color
+ * SUBTEST: drm_mm@color
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@color_evict
+ * SUBTEST: drm_mm@color_evict
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@color_evict_range
+ * SUBTEST: drm_mm@color_evict_range
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@debug
+ * SUBTEST: drm_mm@debug
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@evict
+ * SUBTEST: drm_mm@evict
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@evict_range
+ * SUBTEST: drm_mm@evict_range
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@frag
+ * SUBTEST: drm_mm@frag
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@highest
+ * SUBTEST: drm_mm@highest
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: dr

[Intel-gfx] [PATCH i-g-t 14/17] lib/kunit: Load test modules in background

2023-09-08 Thread Janusz Krzysztofik
For igt_runner to be able to correlate a stream of IGT results from
dynamic sub-subtests that correspond to individual kunit test cases, read
by the igt_runner from stdout / stderr of the test process, with a stream
of kernel messages read from /dev/kmsg, we need both result streams being
fed with data in parallel.  While our KTAP parser is currently started in
the background and reads KTAP results from /dev/kmsg in parallel with
execution of kunit tests performed by the kernel while we are loading a
kunit test module, results from the parser are then only stored as
intermediate data and not processed any further until the module loading
completes.  As a consequence, there is no synchronization between the two
streams.

Call the function that loads the kunit test module from a separate thread
and process the intermediate results immediately, as soon as available
from the background parser, without waiting for completion of module
loading.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 35 +--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index c692954911..bbde3929f2 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "igt_aux.h"
@@ -746,6 +747,21 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
kmod_module_info_free_list(pre);
 }
 
+struct modprobe_data {
+   struct kmod_module *kmod;
+   const char *opts;
+   int err;
+};
+
+static void *modprobe_task(void *arg)
+{
+   struct modprobe_data *data = arg;
+
+   data->err = modprobe(data->kmod, data->opts);
+
+   return NULL;
+}
+
 /**
  * igt_kunit:
  * @module_name: the name of the module
@@ -757,9 +773,11 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
  */
 static void __igt_kunit(struct igt_ktest *tst, const char *opts)
 {
+   struct modprobe_data modprobe = { tst->kmod, opts, 0, };
struct kmod_module *kunit_kmod;
bool is_builtin;
struct ktap_test_results *results;
+   pthread_t modprobe_thread;
unsigned long taints;
int flags, ret;
 
@@ -777,18 +795,25 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
results = ktap_parser_start(tst->kmsg, is_builtin);
 
-   if (igt_debug_on(igt_kmod_load(tst->module_name, opts) < 0)) {
+   if (igt_debug_on(pthread_create(&modprobe_thread, NULL,
+   modprobe_task, &modprobe))) {
ktap_parser_cancel();
igt_ignore_warn(ktap_parser_stop());
-   igt_skip("Unable to load %s module\n", tst->module_name);
+   igt_skip("Failed to create a modprobe thread\n");
}
 
while (READ_ONCE(results->still_running) || 
!igt_list_empty(&results->list))
{
struct ktap_test_results_element *result;
 
+   if (!pthread_tryjoin_np(modprobe_thread, NULL) && modprobe.err) 
{
+   ktap_parser_cancel();
+   break;
+   }
+
if (igt_kernel_tainted(&taints)) {
ktap_parser_cancel();
+   pthread_cancel(modprobe_thread);
break;
}
 
@@ -806,14 +831,20 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
igt_dynamic(result->test_name) {
igt_assert(READ_ONCE(result->passed));
 
+   if (!pthread_tryjoin_np(modprobe_thread, NULL))
+   igt_assert_eq(modprobe.err, 0);
+
igt_fail_on(igt_kernel_tainted(&taints));
}
 
free(result);
}
 
+   pthread_join(modprobe_thread, NULL);
+
ret = ktap_parser_stop();
 
+   igt_skip_on(modprobe.err);
igt_skip_on(igt_kernel_tainted(&taints));
igt_skip_on_f(ret, "KTAP parser failed\n");
 }
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 17/17] lib/kunit: Omit suite name prefix if the same as subtest name

2023-09-08 Thread Janusz Krzysztofik
Kunit test modules usually contain one test suite, named after the module
name with the trailing "_test" or "_kunit" suffix omitted.  Since we
follow the same convention when we derive subtest names from module names,
there is a great chance that those two names match.  Take this into
account when composing names for IGT dynamic sub-subtest names and drop
the leading test suite name component when it is the same as subtest name.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index ddd5499f5e..bd4305482b 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -822,7 +822,8 @@ static void kunit_result_free(struct igt_ktap_result *r,
  *
  * Returns: IGT default codes
  */
-static void __igt_kunit(struct igt_ktest *tst, const char *opts)
+static void
+__igt_kunit(struct igt_ktest *tst, const char *name, const char *opts)
 {
struct modprobe_data modprobe = { tst->kmod, opts, 0, };
char *suite_name = NULL, *case_name = NULL;
@@ -866,7 +867,11 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
r = igt_list_first_entry(&results, r, link);
 
-   igt_dynamic_f("%s-%s", r->suite_name, r->case_name) {
+   igt_dynamic_f("%s%s%s",
+ strcmp(r->suite_name, name) ?  r->suite_name : "",
+ strcmp(r->suite_name, name) ? "-" : "",
+ r->case_name) {
+
if (r->code == IGT_EXIT_INVALID) {
/* parametrized test case, get actual result */
kunit_result_free(r, &suite_name, &case_name);
@@ -976,7 +981,7 @@ void igt_kunit(const char *module_name, const char *name, 
const char *opts)
 * and for documentation.
 */
igt_subtest_with_dynamic(name)
-   __igt_kunit(&tst, opts);
+   __igt_kunit(&tst, name, opts);
 
igt_ktest_end(&tst);
 
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 00/17] Fix IGT Kunit implementation issues

2023-09-08 Thread Janusz Krzysztofik
v2: Fix incorrect and missing includes in the test source file,
  - add license and copyright clauses to the test source file.

Janusz Krzysztofik (17):
  lib/kunit: Drop unused file stream
  lib/kunit: Stop loading kunit module explicitly
  lib/kunit: Fix struct kmod_module kunit_kmod not freed
  lib/kunit: Optimize calls to igt_success/skip/fail()
  lib/kunit: Fix illegal igt_fail() calls inside subtest body
  lib/ktap: Make sure we fail on premature cancel
  lib/ktap: Don't ignore interrupt signals
  lib/kunit: Cancel KTP parser on module load failure
  lib/ktap: Drop is_running flag
  lib/ktap: Read /dev/kmsg in blocking mode
  lib/kunit: Fail / skip on kernel taint
  lib/ktap: Use IGT linked lists for storing KTAP results
  lib/ktap: Reimplement KTAP parser
  lib/kunit: Load test modules in background
  lib/kunit: Parse KTAP report from the main process thread
  lib/kunit: Strip "_test" or "_kunit" suffix from subtest names
  lib/kunit: Omit suite name prefix if the same as subtest name

 lib/igt_kmod.c  | 284 
 lib/igt_ktap.c  | 833 
 lib/igt_ktap.h  |  28 +-
 lib/tests/igt_ktap_parser.c | 246 +++
 lib/tests/meson.build   |   1 +
 tests/drm_mm.c  |  42 +-
 6 files changed, 739 insertions(+), 695 deletions(-)
 create mode 100644 lib/tests/igt_ktap_parser.c

-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 01/17] lib/kunit: Drop unused file stream

2023-09-08 Thread Janusz Krzysztofik
In the process of reviewing patches that introduced kunit support, I asked
once if we could use line buffered input instead of explicitly looking for
newlines in KTAP data.  While my idea was wrong because reading raw data
from /dev/kmsg already returns full log records that always end with a
newline, conversion of /dev/kmsg file descriptor to a file stream with
freopen() was added to the code.  However, that file stream has never been
used for line buffered input.  While the file stream is passed to
functions that actually read the data, there it is converted back to a
file descriptor with fileno() and the data is read with read().

Drop the unnecessary conversions and teach functions to accept and process
just the file descriptor of /dev/kmsg.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 12 +-
 lib/igt_ktap.c | 62 +++---
 lib/igt_ktap.h |  2 +-
 3 files changed, 31 insertions(+), 45 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 6205871791..97667a896f 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -758,7 +758,6 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
 {
struct igt_ktest tst;
struct kmod_module *kunit_kmod;
-   FILE *f;
bool is_builtin;
int ret;
struct ktap_test_results *results;
@@ -774,7 +773,6 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
 
if (igt_ktest_begin(&tst) != 0) {
igt_warn("Unable to begin ktest for %s\n", module_name);
-
igt_ktest_fini(&tst);
igt_fail(IGT_EXIT_ABORT);
}
@@ -791,14 +789,6 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
goto unload;
}
 
-   f = fdopen(tst.kmsg, "r");
-
-   if (f == NULL) {
-   igt_warn("Could not turn /dev/kmsg file descriptor into a FILE 
pointer\n");
-   fail = true;
-   goto unload;
-   }
-
/* The KUnit module is required for running any KUnit tests */
ret = igt_kmod_load("kunit", NULL);
if (ret) {
@@ -814,7 +804,7 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
 
is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
 
-   results = ktap_parser_start(f, is_builtin);
+   results = ktap_parser_start(tst.kmsg, is_builtin);
 
ret = igt_kmod_load(module_name, opts);
if (ret) {
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index ecdcb8d83d..123a40d183 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -16,7 +16,7 @@
 #define DELIMITER "-"
 
 struct ktap_parser_args {
-   FILE *fp;
+   int fd;
bool is_builtin;
volatile bool is_running;
int ret;
@@ -24,7 +24,7 @@ struct ktap_parser_args {
 
 static struct ktap_test_results results;
 
-static int log_to_end(enum igt_log_level level, FILE *f,
+static int log_to_end(enum igt_log_level level, int fd,
  char *record, const char *format, ...) 
__attribute__((format(printf, 4, 5)));
 
 /**
@@ -39,12 +39,11 @@ static int log_to_end(enum igt_log_level level, FILE *f,
  *
  * Returns: 0 for success, or -2 if there's an error reading from the file
  */
-static int log_to_end(enum igt_log_level level, FILE *f,
+static int log_to_end(enum igt_log_level level, int fd,
  char *record, const char *format, ...)
 {
va_list args;
const char *lend;
-   int f_fd = fileno(f);
 
/* Cutoff after newline character, in order to not display garbage */
char *cutoff = strchr(record, '\n');
@@ -61,7 +60,7 @@ static int log_to_end(enum igt_log_level level, FILE *f,
while (*lend == '\0') {
igt_log(IGT_LOG_DOMAIN, level, "%s", record);
 
-   while (read(f_fd, record, BUF_LEN) < 0) {
+   while (read(fd, record, BUF_LEN) < 0) {
if (!READ_ONCE(ktap_args.is_running)) {
igt_warn("ktap parser stopped\n");
return -2;
@@ -157,8 +156,8 @@ static int tap_version_present(char* record, bool 
print_info)
 
 /**
  * find_next_tap_subtest:
- * @fp: FILE pointer
- * @record: buffer used to read fp
+ * @fd: file descriptor
+ * @record: buffer used to read fd
  * @is_builtin: whether KUnit is built-in or not
  *
  * Returns:
@@ -167,11 +166,10 @@ static int tap_version_present(char* record, bool 
print_info)
  * -2 if there are problems while reading the file.
  * any other value corresponds to the amount of cases of the next (sub)test
  */
-static int find_next_tap_subtest(FILE *fp, char *record, char *test_name, bool 
is_builtin)
+static int find_next_tap_subtest(int fd, char *record, char *test_name, bool 
is_builtin)
 {
const char *test_lookup_str, *

[Intel-gfx] [PATCH i-g-t v2 03/17] lib/kunit: Fix struct kmod_module kunit_kmod not freed

2023-09-08 Thread Janusz Krzysztofik
We obtain a kmod_module structure for kunit module in order to check if
it is modular or built-in, then we never release that structure.  Fix it.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index faf31afabc..34ddec3fad 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -797,6 +797,7 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
}
 
is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
+   kmod_module_unref(kunit_kmod);
 
results = ktap_parser_start(tst.kmsg, is_builtin);
 
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 02/17] lib/kunit: Stop loading kunit module explicitly

2023-09-08 Thread Janusz Krzysztofik
Since kmod functions we use for module loading can process module
dependencies, there is no need to load the "kunit" module explicitly
before loading a kunit test module.  For the same reason we already don't
unload the "kunit" module explicitly on cleanup.  Drop the unnecessary
operation.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 6 --
 1 file changed, 6 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 97667a896f..faf31afabc 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -789,12 +789,6 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
goto unload;
}
 
-   /* The KUnit module is required for running any KUnit tests */
-   ret = igt_kmod_load("kunit", NULL);
-   if (ret) {
-   skip = ret;
-   goto unload;
-   }
ret = kmod_module_new_from_name(kmod_ctx(), "kunit", &kunit_kmod);
if (ret) {
igt_warn("Unable to load KUnit\n");
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 04/17] lib/kunit: Optimize calls to igt_success/skip/fail()

2023-09-08 Thread Janusz Krzysztofik
Calling igt_success() explicitly at the end of subtest body is not needed.
Other calls to igt_success() can be usually avoided by inverting test
result checks.  Optimize the code that now calls igt_success().

Moreover, using more advanced variants of igt_skip() and igt_fail() where
applicable makes the code more compact.  Go for it.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 14 +++---
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 34ddec3fad..1d1cd51170 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -814,12 +814,8 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
if (READ_ONCE(results->head) != NULL) {
pthread_mutex_lock(&results->mutex);
 
-   igt_dynamic(results->head->test_name) {
-   if (READ_ONCE(results->head->passed))
-   igt_success();
-   else
-   igt_fail(IGT_EXIT_FAILURE);
-   }
+   igt_dynamic(results->head->test_name)
+   igt_assert(READ_ONCE(results->head->passed));
 
temp = results->head;
results->head = results->head->next;
@@ -834,8 +830,7 @@ unload:
 
igt_ktest_fini(&tst);
 
-   if (skip)
-   igt_skip("Skipping test, as probing KUnit module returned %d", 
skip);
+   igt_skip_on_f(skip, "Skipping test, as probing KUnit module failed\n");
 
if (fail)
igt_fail(IGT_EXIT_ABORT);
@@ -844,9 +839,6 @@ unload:
 
if (ret != 0)
igt_fail(IGT_EXIT_ABORT);
-
-   if (ret == 0)
-   igt_success();
 }
 
 void igt_kunit(const char *module_name, const char *name, const char *opts)
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 05/17] lib/kunit: Fix illegal igt_fail() calls inside subtest body

2023-09-08 Thread Janusz Krzysztofik
In a body of a subtest with dynamic sub-subtests, it is illegal to call
igt_fail() and its variants from outside of a dynamic sub-subtest body.
On the other hand, it is perfectly legal to call either igt_skip() and
friends or __igt_abort() or its variant from there.

In the current implementation of igt_kunit(), there are several places
where igt_fail() is called despite being illegal.  Moreover, it is called
with IGT_EXIT_ABORT as an argument with no good reason for using such
aggressive method that forces CI to trigger system reboot (in most cases
igt_runner can decide if abort is required).

Follow igt_kselftests() pattern more closely, where similar setup and
cleanup operations are performed but their potential errors are processed
in a more friendly way.  Move common cleanup and their corresponding setup
steps out of the subtest body.  Place the latter as requirements in a
preceding igt_fixture section.  Replace remaining illegal igt_fail() calls
with more friendly skips.  Let igt_runner decide if abort is needed.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 75 +++---
 1 file changed, 22 insertions(+), 53 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 1d1cd51170..78b8eb8f53 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -754,59 +754,27 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
  *
  * Returns: IGT default codes
  */
-static void __igt_kunit(const char *module_name, const char *opts)
+static void __igt_kunit(struct igt_ktest *tst, const char *opts)
 {
-   struct igt_ktest tst;
struct kmod_module *kunit_kmod;
bool is_builtin;
int ret;
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
-   int skip = 0;
-   bool fail = false;
-
-   /* get normalized module name */
-   if (igt_ktest_init(&tst, module_name) != 0) {
-   igt_warn("Unable to initialize ktest for %s\n", module_name);
-   igt_fail(IGT_EXIT_ABORT);
-   }
-
-   if (igt_ktest_begin(&tst) != 0) {
-   igt_warn("Unable to begin ktest for %s\n", module_name);
-   igt_ktest_fini(&tst);
-   igt_fail(IGT_EXIT_ABORT);
-   }
 
-   if (tst.kmsg < 0) {
-   igt_warn("Could not open /dev/kmsg\n");
-   fail = true;
-   goto unload;
-   }
+   igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n");
 
-   if (lseek(tst.kmsg, 0, SEEK_END)) {
-   igt_warn("Could not seek the end of /dev/kmsg\n");
-   fail = true;
-   goto unload;
-   }
-
-   ret = kmod_module_new_from_name(kmod_ctx(), "kunit", &kunit_kmod);
-   if (ret) {
-   igt_warn("Unable to load KUnit\n");
-   skip = ret;
-   goto unload;
-   }
+   igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
 
+   igt_skip_on(kmod_module_new_from_name(kmod_ctx(), "kunit", 
&kunit_kmod));
is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
kmod_module_unref(kunit_kmod);
 
-   results = ktap_parser_start(tst.kmsg, is_builtin);
+   results = ktap_parser_start(tst->kmsg, is_builtin);
 
-   ret = igt_kmod_load(module_name, opts);
-   if (ret) {
-   skip = ret;
-   igt_warn("Unable to load %s module\n", module_name);
-   ret = ktap_parser_stop();
-   goto unload;
+   if (igt_debug_on(igt_kmod_load(tst->module_name, opts) < 0)) {
+   igt_ignore_warn(ktap_parser_stop());
+   igt_skip("Unable to load %s module\n", tst->module_name);
}
 
while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != 
NULL)
@@ -825,24 +793,21 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
}
}
 
-unload:
-   igt_ktest_end(&tst);
-
-   igt_ktest_fini(&tst);
-
-   igt_skip_on_f(skip, "Skipping test, as probing KUnit module failed\n");
-
-   if (fail)
-   igt_fail(IGT_EXIT_ABORT);
-
ret = ktap_parser_stop();
 
-   if (ret != 0)
-   igt_fail(IGT_EXIT_ABORT);
+   igt_skip_on_f(ret, "KTAP parser failed\n");
 }
 
 void igt_kunit(const char *module_name, const char *name, const char *opts)
 {
+   struct igt_ktest tst;
+
+   if (igt_ktest_init(&tst, module_name) != 0)
+   return;
+
+   igt_fixture
+   igt_require(igt_ktest_begin(&tst) == 0);
+
/*
 * We need to use igt_subtest here, as otherwise it may crash with:
 *  skipping is allowed only in fixtures, subtests or igt_simple_main
@@ -854,7 +819,11 @@ void igt_kunit(const char *module_name, const char 

[Intel-gfx] [PATCH i-g-t v2 06/17] lib/ktap: Make sure we fail on premature cancel

2023-09-08 Thread Janusz Krzysztofik
After loading a kunit test module that executes some kunit test cases, we
evaluate overall result of an IGT subtest that corresponds to that module
based on an error code returned by kunit_parser_stop() helper, obtained
from a .ret field of a ktap_args structure.  That code is now assigned to
that structure field right before completion of the KTAP parser thread
start routine.  If the thread is canceled for some reason then the return
code will be undefined.

Initialize the return code on KTAP parser startup with a value that
indicates a failure, then change it to success when so indicated by result
of KTAP parsing.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_ktap.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 123a40d183..84fb13218f 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -579,9 +579,7 @@ igt_ktap_parser_start:
 igt_ktap_parser_end:
results.still_running = false;
 
-   if (failed_tests || !found_tests)
-   ktap_args.ret = IGT_EXIT_FAILURE;
-   else
+   if (found_tests && !failed_tests)
ktap_args.ret = IGT_EXIT_SUCCESS;
 
return NULL;
@@ -598,6 +596,7 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
ktap_args.fd = fd;
ktap_args.is_builtin = is_builtin;
ktap_args.is_running = true;
+   ktap_args.ret = IGT_EXIT_FAILURE;
pthread_create(&ktap_parser_thread, NULL, igt_ktap_parser, NULL);
 
return &results;
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 07/17] lib/ktap: Don't ignore interrupt signals

2023-09-08 Thread Janusz Krzysztofik
While reading KTAP data from /dev/kmsg we now ignore interrupt signals
that may occur during read() and we continue reading the data.  No
explanation has been provided on what that could be needed for.

Always return with an error code to the caller when read() fails with
errno == EINTR, so igt_runner has no problems with killing us promptly
on timeout.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_ktap.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 84fb13218f..3cfb55ec97 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -67,7 +67,7 @@ static int log_to_end(enum igt_log_level level, int fd,
}
 
if (errno == EINTR)
-   continue;
+   return -2;
 
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
@@ -189,7 +189,7 @@ static int find_next_tap_subtest(int fd, char *record, char 
*test_name, bool is_
}
 
if (errno == EINTR)
-   continue;
+   return -2;
 
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
@@ -233,7 +233,7 @@ static int find_next_tap_subtest(int fd, char *record, char 
*test_name, bool is_
}
 
if (errno == EINTR)
-   continue;
+   return -2;
 
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
@@ -388,7 +388,7 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
}
 
if (errno == EINTR)
-   continue;
+   return -1;
 
if (errno == EAGAIN)
/* No records available */
@@ -541,7 +541,7 @@ igt_ktap_parser_start:
continue;
 
if (errno == EINTR)
-   continue;
+   goto igt_ktap_parser_end;
 
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. You may 
want to increase log_buf_len in kmcdline\n");
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 08/17] lib/kunit: Cancel KTP parser on module load failure

2023-09-08 Thread Janusz Krzysztofik
For our KTAP parser to be running in parallel with kunit test module
loading, we now start it in a separate thread before we load the module.
If the module loading fails then we join the KTAP parser thread right
after that failure.  If the KTAP thread sleeps for some reason then we
can fail to break the test immediately.

Cancel the KTAP parser thread right after module load error and before
joining it.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 1 +
 lib/igt_ktap.c | 6 ++
 lib/igt_ktap.h | 1 +
 3 files changed, 8 insertions(+)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 78b8eb8f53..fb0bd21ee5 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -773,6 +773,7 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
results = ktap_parser_start(tst->kmsg, is_builtin);
 
if (igt_debug_on(igt_kmod_load(tst->module_name, opts) < 0)) {
+   ktap_parser_cancel();
igt_ignore_warn(ktap_parser_stop());
igt_skip("Unable to load %s module\n", tst->module_name);
}
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 3cfb55ec97..1e75b2ec23 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -602,6 +602,12 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
return &results;
 }
 
+void ktap_parser_cancel(void)
+{
+   ktap_args.is_running = false;
+   pthread_cancel(ktap_parser_thread);
+}
+
 int ktap_parser_stop(void)
 {
ktap_args.is_running = false;
diff --git a/lib/igt_ktap.h b/lib/igt_ktap.h
index ea57c2bb9b..991800e912 100644
--- a/lib/igt_ktap.h
+++ b/lib/igt_ktap.h
@@ -45,6 +45,7 @@ struct ktap_test_results {
 
 
 struct ktap_test_results *ktap_parser_start(int fd, bool is_builtin);
+void ktap_parser_cancel(void);
 int ktap_parser_stop(void);
 
 #endif /* IGT_KTAP_H */
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 09/17] lib/ktap: Drop is_running flag

2023-09-08 Thread Janusz Krzysztofik
Since we now call pthread_cancel() when we want to stop KTAP parser before
it completes, and we take care of returning failure in that case as a
result of KTAP parsing, we no longer need to check a flag that indicates
whether we should continue parsing or return a failure.  Drop that flag.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_ktap.c | 32 
 1 file changed, 32 deletions(-)

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 1e75b2ec23..fe77b62680 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -18,7 +18,6 @@
 struct ktap_parser_args {
int fd;
bool is_builtin;
-   volatile bool is_running;
int ret;
 } ktap_args;
 
@@ -61,11 +60,6 @@ static int log_to_end(enum igt_log_level level, int fd,
igt_log(IGT_LOG_DOMAIN, level, "%s", record);
 
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -2;
-   }
-
if (errno == EINTR)
return -2;
 
@@ -183,11 +177,6 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
 
if (is_builtin) {
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -2;
-   }
-
if (errno == EINTR)
return -2;
 
@@ -227,11 +216,6 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
cutoff[0] = '\0';
 
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -2;
-   }
-
if (errno == EINTR)
return -2;
 
@@ -382,11 +366,6 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
 
for (int i = 0; i < test_count; i++) {
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -1;
-   }
-
if (errno == EINTR)
return -1;
 
@@ -523,19 +502,11 @@ void *igt_ktap_parser(void *unused)
failed_tests = false;
found_tests = false;
 
-   if (!READ_ONCE(ktap_args.is_running))
-   goto igt_ktap_parser_end;
-
 igt_ktap_parser_start:
test_name[0] = '\0';
test_name[BUF_LEN] = '\0';
 
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   goto igt_ktap_parser_end;
-   }
-
if (errno == EAGAIN)
/* No records available */
continue;
@@ -595,7 +566,6 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
 
ktap_args.fd = fd;
ktap_args.is_builtin = is_builtin;
-   ktap_args.is_running = true;
ktap_args.ret = IGT_EXIT_FAILURE;
pthread_create(&ktap_parser_thread, NULL, igt_ktap_parser, NULL);
 
@@ -604,13 +574,11 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
 
 void ktap_parser_cancel(void)
 {
-   ktap_args.is_running = false;
pthread_cancel(ktap_parser_thread);
 }
 
 int ktap_parser_stop(void)
 {
-   ktap_args.is_running = false;
pthread_join(ktap_parser_thread, NULL);
return ktap_args.ret;
 }
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 10/17] lib/ktap: Read /dev/kmsg in blocking mode

2023-09-08 Thread Janusz Krzysztofik
We obtain KTAP report from /dev/kmsg.  That file is now opened from
igt_ktest_begin(), a function originally designed for i915 selftests and
now reused with kunit tests.  The original intention of opening that file
was to dump kernel messages to stderr on selftest error.  For that
purpose, the file is now opened in non-blocking mode so we don't end up
waiting for more kernel messages than already available.  Since our ktap
parser code reuses the file descriptor, we now have to loop over
EAGAIN responses, waiting for more KTAP data.  Since we have no sleeps
inside those loops, extremely high CPU usage can be observed.

Simplify reading KTAP reports by first switching the file descriptor back
to blocking mode.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c |  7 -
 lib/igt_ktap.c | 81 ++
 2 files changed, 28 insertions(+), 60 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index fb0bd21ee5..020df286b8 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "igt_aux.h"
@@ -758,12 +759,16 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 {
struct kmod_module *kunit_kmod;
bool is_builtin;
-   int ret;
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
+   int flags, ret;
 
igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n");
 
+   flags = fcntl(tst->kmsg, F_GETFL, 0) & ~O_NONBLOCK;
+   igt_skip_on_f(fcntl(tst->kmsg, F_SETFL, flags) == -1,
+ "Could not set /dev/kmsg to blocking mode\n");
+
igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
 
igt_skip_on(kmod_module_new_from_name(kmod_ctx(), "kunit", 
&kunit_kmod));
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index fe77b62680..165f6b2cce 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -59,20 +59,12 @@ static int log_to_end(enum igt_log_level level, int fd,
while (*lend == '\0') {
igt_log(IGT_LOG_DOMAIN, level, "%s", record);
 
-   while (read(fd, record, BUF_LEN) < 0) {
-   if (errno == EINTR)
-   return -2;
-
-   if (errno == EPIPE) {
+   if (read(fd, record, BUF_LEN) < 0) {
+   if (errno == EPIPE)
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
-   return -2;
-   }
+   else if (errno != EINTR)
+   igt_warn("an error occurred while reading kmsg: 
%m\n");
 
-   if (errno == EAGAIN)
-   /* No records available */
-   continue;
-
-   igt_warn("kmsg truncated: unknown error (%m)\n");
return -2;
}
 
@@ -176,20 +168,12 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
return -1;
 
if (is_builtin) {
-   while (read(fd, record, BUF_LEN) < 0) {
-   if (errno == EINTR)
-   return -2;
-
-   if (errno == EPIPE) {
+   if (read(fd, record, BUF_LEN) < 0) {
+   if (errno == EPIPE)
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
-   return -2;
-   }
+   else if (errno != EINTR)
+   igt_warn("an error occurred while reading kmsg: 
%m\n");
 
-   if (errno == EAGAIN)
-   /* No records available */
-   continue;
-
-   igt_warn("kmsg truncated: unknown error (%m)\n");
return -2;
}
}
@@ -215,20 +199,12 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
if (cutoff)
cutoff[0] = '\0';
 
-   while (read(fd, record, BUF_LEN) < 0) {
-   if (errno == EINTR)
-   return -2;
-
-   if (errno == EPIPE) {
+   if (read(fd, record, BUF_LEN) < 0) {
+   if (errno == EPIPE)
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
-   return -2;
-   }
+   else if (errno !=

[Intel-gfx] [PATCH i-g-t v2 12/17] lib/ktap: Use IGT linked lists for storing KTAP results

2023-09-08 Thread Janusz Krzysztofik
For code simplicity and clarity, use existing IGT linked lists library
instead of open coding a custom implementation of a list of KTAP results.

While being at it, flatten the code by inverting a check for pending
results.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 28 
 lib/igt_ktap.c | 25 +
 lib/igt_ktap.h |  6 --
 3 files changed, 25 insertions(+), 34 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 988ac164cb..c692954911 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -760,7 +760,6 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
struct kmod_module *kunit_kmod;
bool is_builtin;
struct ktap_test_results *results;
-   struct ktap_test_results_element *temp;
unsigned long taints;
int flags, ret;
 
@@ -784,28 +783,33 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
igt_skip("Unable to load %s module\n", tst->module_name);
}
 
-   while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != 
NULL)
+   while (READ_ONCE(results->still_running) || 
!igt_list_empty(&results->list))
{
+   struct ktap_test_results_element *result;
+
if (igt_kernel_tainted(&taints)) {
ktap_parser_cancel();
break;
}
 
-   if (READ_ONCE(results->head) != NULL) {
-   pthread_mutex_lock(&results->mutex);
+   pthread_mutex_lock(&results->mutex);
+   if (igt_list_empty(&results->list)) {
+   pthread_mutex_unlock(&results->mutex);
+   continue;
+   }
 
-   igt_dynamic(results->head->test_name) {
-   igt_assert(READ_ONCE(results->head->passed));
+   result = igt_list_first_entry(&results->list, result, link);
 
-   igt_fail_on(igt_kernel_tainted(&taints));
-   }
+   igt_list_del(&result->link);
+   pthread_mutex_unlock(&results->mutex);
 
-   temp = results->head;
-   results->head = results->head->next;
-   free(temp);
+   igt_dynamic(result->test_name) {
+   igt_assert(READ_ONCE(result->passed));
 
-   pthread_mutex_unlock(&results->mutex);
+   igt_fail_on(igt_kernel_tainted(&taints));
}
+
+   free(result);
}
 
ret = ktap_parser_stop();
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 165f6b2cce..5e9967f980 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -12,6 +12,7 @@
 #include "igt_aux.h"
 #include "igt_core.h"
 #include "igt_ktap.h"
+#include "igt_list.h"
 
 #define DELIMITER "-"
 
@@ -335,7 +336,7 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
   bool *found_tests, bool is_builtin)
 {
char record[BUF_LEN + 1];
-   struct ktap_test_results_element *r, *temp;
+   struct ktap_test_results_element *r;
int internal_test_count;
char test_name[BUF_LEN + 1];
char base_test_name_for_next_level[BUF_LEN + 1];
@@ -403,17 +404,9 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
r->test_name[BUF_LEN] = '\0';
 
r->passed = false;
-   r->next = NULL;
 
pthread_mutex_lock(&results.mutex);
-   if (results.head == NULL) {
-   results.head = r;
-   } else {
-   temp = results.head;
-   while (temp->next != NULL)
-   temp = temp->next;
-   temp->next = r;
-   }
+   igt_list_add_tail(&r->link, &results.list);
pthread_mutex_unlock(&results.mutex);
 
test_name[0] = '\0';
@@ -431,17 +424,9 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
r->test_name[BUF_LEN] = '\0';
 
r->passed = true;
-   r->next = NULL;
 
pthread_mutex_lock(&results.mutex);
-   if (results.head == NULL) {
-   results.head = r;
-   } else {
-   temp = results.hea

[Intel-gfx] [PATCH i-g-t v2 13/17] lib/ktap: Reimplement KTAP parser

2023-09-08 Thread Janusz Krzysztofik
Current implementation of KTAP parser suffers from several issues:
- in most cases, kernel messages that are not part of KTAP output but
  happen to appear in between break the parser,
- results from parametrized test cases, not preceded with a "1..N" test
  plan, break the parser,
- skips are not supported, reported as success,
- IGT results from all 3 kunit test nesting levels, i.e., from
  parametrized subtests (should those were fixed to work correctly), test
  cases and test suites, are reported individually as if all those items
  were executed sequentially, all at the same level of nesting, which can
  be confusing to igt_runner,
- the parser is not only parsing the data, but also handles data input
  from a /dev/kmsg like source, which is integrated into it, making it
  hard if not impossible to feed KTAP data from different sources,
  including mock sources,
- since the parser has been designed for running it in a separate thread,
  it's not possible to use igt_skip() nor igt_fail() and friends
  immediately when a result is available, only pass it to the main thread
  over a buffer.  As a consequence, it is virtually impossible to
  synchronize IGT output with KTAP output.

Fixing the existing parser occurred more complicated than re-implementing
it from scratch.  This patch provides a new implementation.

Only results from kunit test cases are reported as results of IGT dynamic
sub-subtests.  Results from individual parametrized subtests have been
considered problematic since many of them provide multi-word descriptions
in place of single-word subtest names.  If a parametrized test case fails
then full KTAP output from its subtests, potentially mixed with
accompanying kernel messages, is available in dmesg for analysis so users
can still find out which individual subtests succeeded and which failed.

Results from test suites level are also omitted in faith that IGT can
handle aggregation of results from individual kunit test cases reported as
IGT dynamic sub-subtests and report those aggregated results correctly as
results from an IGT dynamic subtest.  That 1:1 mapping of kunit test
suites to IGT dynamic subtests now works perfectly for modules that
provide only one test suite, which is the case for all kunit test modules
now existing under drivers/gpu/drm, and the most common case among all
kunit test modules in the whole kernel tree.

New igt_ktap functions can be called directly from igt_kunit subtest body,
but for this patch, the old igt_ktap_parser() function that runs in a
separate thread has been preserved, only modified to use the new
implementation and translate results from those new functions to legacy
format.  Unlike the former implementation, translation of kunit names to
IGT names is handled outside the parser itself, though for now it is still
performed inside the legacy igt_ktap_parser() function.

For better readability of the patch, no longer used functions have been
left untouched, only tagged with __maybe_unused to shut up compiler
warnings / errors.  Kunit library functions will be modified to use the
new igt_ktap interface, and those old ktap functions removed by follow-
up patches.

A test with example subtests that feed igt_ktap_parse() function with some
example data and verifies correctness of their parsing is also provided.

v2: Fix incorrect and missing includes in the test source file,
  - add license and copyright clauses to the test source file.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_ktap.c  | 422 
 lib/igt_ktap.h  |  15 ++
 lib/tests/igt_ktap_parser.c | 246 +
 lib/tests/meson.build   |   1 +
 4 files changed, 645 insertions(+), 39 deletions(-)
 create mode 100644 lib/tests/igt_ktap_parser.c

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 5e9967f980..d46a2433e5 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: MIT
 /*
  * Copyright © 2023 Isabella Basso do Amaral 
+ * Copyright © 2023 Intel Corporation
  */
 
 #include 
@@ -8,12 +9,310 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
 #include "igt_aux.h"
 #include "igt_core.h"
 #include "igt_ktap.h"
 #include "igt_list.h"
 
+enum ktap_phase {
+   KTAP_START,
+   SUITE_COUNT,
+   SUITE_START,
+   SUITE_NAME,
+   CASE_COUNT,
+   CASE_NAME,
+   SUB_RESULT,
+   CASE_RESULT,
+   SUITE_RESULT,
+};
+
+struct igt_ktap_results {
+   enum ktap_phase expect;
+   unsigned int suite_count;
+   unsigned int suite_last;
+   char *suite_name;
+   unsigned int case_count;
+   unsigned int case_last;
+   char *case_name;
+   unsigned int sub_last;
+   struct igt_list_head *results;
+};
+
+/**
+ * igt_ktap_parse:
+ *
+ * This function parses a line of text for KTAP report data
+ * and passes results back to IGT kunit layer.
+ */
+int 

[Intel-gfx] [PATCH i-g-t v2 14/17] lib/kunit: Load test modules in background

2023-09-08 Thread Janusz Krzysztofik
For igt_runner to be able to correlate a stream of IGT results from
dynamic sub-subtests that correspond to individual kunit test cases, read
by the igt_runner from stdout / stderr of the test process, with a stream
of kernel messages read from /dev/kmsg, we need both result streams being
fed with data in parallel.  While our KTAP parser is currently started in
the background and reads KTAP results from /dev/kmsg in parallel with
execution of kunit tests performed by the kernel while we are loading a
kunit test module, results from the parser are then only stored as
intermediate data and not processed any further until the module loading
completes.  As a consequence, there is no synchronization between the two
streams.

Call the function that loads the kunit test module from a separate thread
and process the intermediate results immediately, as soon as available
from the background parser, without waiting for completion of module
loading.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 35 +--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index c692954911..bbde3929f2 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "igt_aux.h"
@@ -746,6 +747,21 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
kmod_module_info_free_list(pre);
 }
 
+struct modprobe_data {
+   struct kmod_module *kmod;
+   const char *opts;
+   int err;
+};
+
+static void *modprobe_task(void *arg)
+{
+   struct modprobe_data *data = arg;
+
+   data->err = modprobe(data->kmod, data->opts);
+
+   return NULL;
+}
+
 /**
  * igt_kunit:
  * @module_name: the name of the module
@@ -757,9 +773,11 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
  */
 static void __igt_kunit(struct igt_ktest *tst, const char *opts)
 {
+   struct modprobe_data modprobe = { tst->kmod, opts, 0, };
struct kmod_module *kunit_kmod;
bool is_builtin;
struct ktap_test_results *results;
+   pthread_t modprobe_thread;
unsigned long taints;
int flags, ret;
 
@@ -777,18 +795,25 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
results = ktap_parser_start(tst->kmsg, is_builtin);
 
-   if (igt_debug_on(igt_kmod_load(tst->module_name, opts) < 0)) {
+   if (igt_debug_on(pthread_create(&modprobe_thread, NULL,
+   modprobe_task, &modprobe))) {
ktap_parser_cancel();
igt_ignore_warn(ktap_parser_stop());
-   igt_skip("Unable to load %s module\n", tst->module_name);
+   igt_skip("Failed to create a modprobe thread\n");
}
 
while (READ_ONCE(results->still_running) || 
!igt_list_empty(&results->list))
{
struct ktap_test_results_element *result;
 
+   if (!pthread_tryjoin_np(modprobe_thread, NULL) && modprobe.err) 
{
+   ktap_parser_cancel();
+   break;
+   }
+
if (igt_kernel_tainted(&taints)) {
ktap_parser_cancel();
+   pthread_cancel(modprobe_thread);
break;
}
 
@@ -806,14 +831,20 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
igt_dynamic(result->test_name) {
igt_assert(READ_ONCE(result->passed));
 
+   if (!pthread_tryjoin_np(modprobe_thread, NULL))
+   igt_assert_eq(modprobe.err, 0);
+
igt_fail_on(igt_kernel_tainted(&taints));
}
 
free(result);
}
 
+   pthread_join(modprobe_thread, NULL);
+
ret = ktap_parser_stop();
 
+   igt_skip_on(modprobe.err);
igt_skip_on(igt_kernel_tainted(&taints));
igt_skip_on_f(ret, "KTAP parser failed\n");
 }
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 15/17] lib/kunit: Parse KTAP report from the main process thread

2023-09-08 Thread Janusz Krzysztofik
There was an attempt to parse KTAP reports in the background while a kunit
test module is loading.  However, since dynamic sub-subtests can be
executed only from the main thread, that attempt was not quite successful,
as IGT results from all executed kunit test cases were generated only
after loading of kunit test module completed.

Now that the parser maintains its state and we can call it separately for
each input line of a KTAP report, it is perfectly possible to call the
parser from the main thread while the module is loading in the background,
and convert results from kunit test cases immediately to results of IGT
dynamic sub-subtests by running an igt_dynamic() section for each result
as soon as returned by the parser.

Drop igt_ktap_parser() thread and execute igt_dynamic() for each kunit
result obtained from igt_ktap_parse() called from the main thread.

Also, drop no longer needed functions from igt_ktap soruces.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 158 +++---
 lib/igt_ktap.c | 568 -
 lib/igt_ktap.h |  22 --
 3 files changed, 123 insertions(+), 625 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index bbde3929f2..46a6f81e73 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2016 Intel Corporation
+ * Copyright © 2016-2023 Intel Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -26,7 +26,10 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
+#include 
 
 #include "igt_aux.h"
 #include "igt_core.h"
@@ -762,6 +765,54 @@ static void *modprobe_task(void *arg)
return NULL;
 }
 
+static int kunit_kmsg_result_get(struct igt_list_head *results,
+int fd, struct igt_ktap_results *ktap)
+{
+   char record[BUF_LEN + 1], *buf;
+   int ret;
+
+   while (igt_list_empty(results) &&
+  (ret = read(fd, record, BUF_LEN), ret > 0)) {
+   /* skip kmsg continuation lines */
+   if (igt_debug_on(*record == ' '))
+   continue;
+
+   /* NULL-terminate the record */
+   record[ret] = '\0';
+
+   /* detect start of log message, continue if not found */
+   buf = strchrnul(record, ';');
+   if (igt_debug_on(*buf == '\0'))
+   continue;
+   buf++;
+
+   ret = igt_ktap_parse(buf, ktap);
+   if (ret != -EINPROGRESS)
+   break;
+   }
+
+   return ret;
+}
+
+static void kunit_result_free(struct igt_ktap_result *r,
+ char **suite_name, char **case_name)
+{
+   igt_list_del(&r->link);
+
+   if (r->suite_name != *suite_name) {
+   free(*suite_name);
+   *suite_name = r->suite_name;
+   }
+
+   if (r->case_name != *case_name) {
+   free(*case_name);
+   *case_name = r->case_name;
+   }
+
+   free(r->msg);
+   free(r);
+}
+
 /**
  * igt_kunit:
  * @module_name: the name of the module
@@ -774,10 +825,11 @@ static void *modprobe_task(void *arg)
 static void __igt_kunit(struct igt_ktest *tst, const char *opts)
 {
struct modprobe_data modprobe = { tst->kmod, opts, 0, };
-   struct kmod_module *kunit_kmod;
-   bool is_builtin;
-   struct ktap_test_results *results;
+   char *suite_name = NULL, *case_name = NULL;
+   struct igt_ktap_result *r, *rn;
+   struct igt_ktap_results *ktap;
pthread_t modprobe_thread;
+   IGT_LIST_HEAD(results);
unsigned long taints;
int flags, ret;
 
@@ -787,49 +839,76 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
igt_skip_on_f(fcntl(tst->kmsg, F_SETFL, flags) == -1,
  "Could not set /dev/kmsg to blocking mode\n");
 
-   igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
-
-   igt_skip_on(kmod_module_new_from_name(kmod_ctx(), "kunit", 
&kunit_kmod));
-   is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
-   kmod_module_unref(kunit_kmod);
+   ktap = igt_ktap_alloc(&results);
+   igt_require(ktap);
 
-   results = ktap_parser_start(tst->kmsg, is_builtin);
+   igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
 
if (igt_debug_on(pthread_create(&modprobe_thread, NULL,
modprobe_task, &modprobe))) {
-   ktap_parser_cancel();
-   igt_ignore_warn(ktap_parser_stop());
+   igt_ktap_free(ktap);
igt_skip("Failed to create a modprobe thread\n");
}
 
-   while (READ_ONCE(results->

[Intel-gfx] [PATCH i-g-t v2 11/17] lib/kunit: Fail / skip on kernel taint

2023-09-08 Thread Janusz Krzysztofik
Similar to how igt_kselftest() handles kernel taints, fail current dynamic
sub-subtest and skip remaining ones when a kernel taint is detected during
execution of kunit test cases.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 020df286b8..988ac164cb 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -761,6 +761,7 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
bool is_builtin;
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
+   unsigned long taints;
int flags, ret;
 
igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n");
@@ -785,12 +786,20 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != 
NULL)
{
+   if (igt_kernel_tainted(&taints)) {
+   ktap_parser_cancel();
+   break;
+   }
+
if (READ_ONCE(results->head) != NULL) {
pthread_mutex_lock(&results->mutex);
 
-   igt_dynamic(results->head->test_name)
+   igt_dynamic(results->head->test_name) {
igt_assert(READ_ONCE(results->head->passed));
 
+   igt_fail_on(igt_kernel_tainted(&taints));
+   }
+
temp = results->head;
results->head = results->head->next;
free(temp);
@@ -801,6 +810,7 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
ret = ktap_parser_stop();
 
+   igt_skip_on(igt_kernel_tainted(&taints));
igt_skip_on_f(ret, "KTAP parser failed\n");
 }
 
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v2 16/17] lib/kunit: Strip "_test" or "_kunit" suffix from subtest names

2023-09-08 Thread Janusz Krzysztofik
If a user (an IGT test) doesn't provide a subtest name when calling
igt_kunit() then we now use the requested kernel module name as IGT
subtest name.  Since names of kunit test modules usually end with a
"_test" or "_kunit" suffix, those parts of the names don't carry any
useful information.  Strip those suffixes from IGT subtest names.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 26 ++
 tests/drm_mm.c | 42 +-
 2 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 46a6f81e73..ddd5499f5e 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -944,8 +944,29 @@ void igt_kunit(const char *module_name, const char *name, 
const char *opts)
if (igt_ktest_init(&tst, module_name) != 0)
return;
 
-   igt_fixture
+   /*
+* If the caller (an IGT test) provides no subtest name then we
+* take the module name, drop the trailing "_test" or "_kunit"
+* suffix, if any, and use the result as our IGT subtest name.
+*/
+   if (!name) {
+   name = strdup(module_name);
+   if (name) {
+   char *suffix = strstr(name, "_test");
+
+   if (!suffix)
+   suffix = strstr(name, "_kunit");
+
+   if (suffix)
+   *suffix = '\0';
+   }
+   }
+
+   igt_fixture {
+   igt_require(name);
+
igt_require(igt_ktest_begin(&tst) == 0);
+   }
 
/*
 * We need to use igt_subtest here, as otherwise it may crash with:
@@ -954,9 +975,6 @@ void igt_kunit(const char *module_name, const char *name, 
const char *opts)
 * proper namespace for dynamic subtests, with is required for CI
 * and for documentation.
 */
-   if (name == NULL)
-   name = module_name;
-
igt_subtest_with_dynamic(name)
__igt_kunit(&tst, opts);
 
diff --git a/tests/drm_mm.c b/tests/drm_mm.c
index 9a8b3f3fcb..e6ba224745 100644
--- a/tests/drm_mm.c
+++ b/tests/drm_mm.c
@@ -29,123 +29,123 @@
  * Feature: mapping
  * Run type: FULL
  *
- * SUBTEST: drm_mm_test
+ * SUBTEST: drm_mm
  *
- * SUBTEST: drm_mm_test@align
+ * SUBTEST: drm_mm@align
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@align32
+ * SUBTEST: drm_mm@align32
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@align64
+ * SUBTEST: drm_mm@align64
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@bottomup
+ * SUBTEST: drm_mm@bottomup
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@color
+ * SUBTEST: drm_mm@color
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@color_evict
+ * SUBTEST: drm_mm@color_evict
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@color_evict_range
+ * SUBTEST: drm_mm@color_evict_range
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@debug
+ * SUBTEST: drm_mm@debug
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@evict
+ * SUBTEST: drm_mm@evict
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@evict_range
+ * SUBTEST: drm_mm@evict_range
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@frag
+ * SUBTEST: drm_mm@frag
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@highest
+ * SUBTEST: drm_mm@highest
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: dr

[Intel-gfx] [PATCH i-g-t v2 17/17] lib/kunit: Omit suite name prefix if the same as subtest name

2023-09-08 Thread Janusz Krzysztofik
Kunit test modules usually contain one test suite, named after the module
name with the trailing "_test" or "_kunit" suffix omitted.  Since we
follow the same convention when we derive subtest names from module names,
there is a great chance that those two names match.  Take this into
account when composing names for IGT dynamic sub-subtest names and drop
the leading test suite name component when it is the same as subtest name.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index ddd5499f5e..bd4305482b 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -822,7 +822,8 @@ static void kunit_result_free(struct igt_ktap_result *r,
  *
  * Returns: IGT default codes
  */
-static void __igt_kunit(struct igt_ktest *tst, const char *opts)
+static void
+__igt_kunit(struct igt_ktest *tst, const char *name, const char *opts)
 {
struct modprobe_data modprobe = { tst->kmod, opts, 0, };
char *suite_name = NULL, *case_name = NULL;
@@ -866,7 +867,11 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
r = igt_list_first_entry(&results, r, link);
 
-   igt_dynamic_f("%s-%s", r->suite_name, r->case_name) {
+   igt_dynamic_f("%s%s%s",
+ strcmp(r->suite_name, name) ?  r->suite_name : "",
+ strcmp(r->suite_name, name) ? "-" : "",
+ r->case_name) {
+
if (r->code == IGT_EXIT_INVALID) {
/* parametrized test case, get actual result */
kunit_result_free(r, &suite_name, &case_name);
@@ -976,7 +981,7 @@ void igt_kunit(const char *module_name, const char *name, 
const char *opts)
 * and for documentation.
 */
igt_subtest_with_dynamic(name)
-   __igt_kunit(&tst, opts);
+   __igt_kunit(&tst, name, opts);
 
igt_ktest_end(&tst);
 
-- 
2.41.0



Re: [Intel-gfx] [PATCH i-g-t v2 05/17] lib/kunit: Fix illegal igt_fail() calls inside subtest body

2023-09-11 Thread Janusz Krzysztofik
Hi Mauro,

Thanks for review.

On Monday, 11 September 2023 10:52:51 CEST Mauro Carvalho Chehab wrote:
> On Fri,  8 Sep 2023 14:32:39 +0200
> Janusz Krzysztofik  wrote:
> 
> > In a body of a subtest with dynamic sub-subtests, it is illegal to call
> > igt_fail() and its variants from outside of a dynamic sub-subtest body.
> > On the other hand, it is perfectly legal to call either igt_skip() and
> > friends or __igt_abort() or its variant from there.
> > 
> > In the current implementation of igt_kunit(), there are several places
> > where igt_fail() is called despite being illegal.  Moreover, it is called
> > with IGT_EXIT_ABORT as an argument with no good reason for using such
> > aggressive method that forces CI to trigger system reboot (in most cases
> > igt_runner can decide if abort is required).
> > 
> > Follow igt_kselftests() pattern more closely, where similar setup and
> > cleanup operations are performed but their potential errors are processed
> > in a more friendly way.  Move common cleanup and their corresponding setup
> > steps out of the subtest body.  Place the latter as requirements in a
> > preceding igt_fixture section.  Replace remaining illegal igt_fail() calls
> > with more friendly skips.  Let igt_runner decide if abort is needed.
> > 
> > Signed-off-by: Janusz Krzysztofik 
> > ---
> >  lib/igt_kmod.c | 75 +++---
> >  1 file changed, 22 insertions(+), 53 deletions(-)
> > 
> > diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
> > index 1d1cd51170..78b8eb8f53 100644
> > --- a/lib/igt_kmod.c
> > +++ b/lib/igt_kmod.c
...
> > @@ -825,24 +793,21 @@ static void __igt_kunit(const char *module_name, 
> > const char *opts)
> > }
> > }
> >  
> > -unload:
> > -   igt_ktest_end(&tst);
> > -
> > -   igt_ktest_fini(&tst);
> > -
> > -   igt_skip_on_f(skip, "Skipping test, as probing KUnit module failed\n");
> > -
> > -   if (fail)
> > -   igt_fail(IGT_EXIT_ABORT);
> > -
> > ret = ktap_parser_stop();
> >  
> > -   if (ret != 0)
> > -   igt_fail(IGT_EXIT_ABORT);
> > +   igt_skip_on_f(ret, "KTAP parser failed\n");
> >  }
> >  
> >  void igt_kunit(const char *module_name, const char *name, const char *opts)
> >  {
> > +   struct igt_ktest tst;
> > +
> > +   if (igt_ktest_init(&tst, module_name) != 0)
> > +   return;
> 
> Shouldn't it be calling igt_skip() here too?

Maybe yes.  I've chosen to follow the algorithm used in igt_kselftest.  There 
was an igt_skip() variant there initially but in 2017 that was converted to 
the current return only by Peter with IGT commit 9f92893b11e8 ("lib/igt_kmod: 
Don't call igt_assert or igt_require without a fixture").  However, 
justification for dropping igt_require() instead of calling it from an 
igt_fixture section may not apply to kunit modules:

"If kmod_module_new_from_name fails, ... return normally from igt_kselftest, 
matching behaviour when the module loading is successful but it doesn't 
contain selftests."

While i915 could be built with no selftests included, a kunit module without 
any tests doesn't make sense, then silent return may be not what we need.

Thanks,
Janusz

> 
> > +
> > +   igt_fixture
> > +   igt_require(igt_ktest_begin(&tst) == 0);
> > +
> > /*
> >  * We need to use igt_subtest here, as otherwise it may crash with:
> >  *  skipping is allowed only in fixtures, subtests or igt_simple_main
> > @@ -854,7 +819,11 @@ void igt_kunit(const char *module_name, const char 
> > *name, const char *opts)
> > name = module_name;
> >  
> > igt_subtest_with_dynamic(name)
> > -   __igt_kunit(module_name, opts);
> > +   __igt_kunit(&tst, opts);
> > +
> > +   igt_ktest_end(&tst);
> > +
> > +   igt_ktest_fini(&tst);
> >  }
> >  
> >  static int open_parameters(const char *module_name)
> 






[Intel-gfx] [PATCH] drm/tests: Fix incorrect argument in drm_test_mm_insert_range

2023-09-11 Thread Janusz Krzysztofik
While drm_mm test was converted form igt selftest to kunit, unexpected
value of "end" argument equal "start" was introduced to one of calls to a
function that executes the drm_test_mm_insert_range for specific start/end
pair of arguments.  As a consequence, DRM_MM_BUG_ON(end <= start) is
triggered.  Fix it by restoring the original value.

Fixes: fc8d29e298cf ("drm: selftest: convert drm_mm selftest to KUnit")
Signed-off-by: Janusz Krzysztofik 
Cc: "Maíra Canal" 
Cc: Arthur Grillo 
Cc: Javier Martinez Canillas 
Cc: Daniel Latypov 
Cc: sta...@vger.kernel.org # v6.1+
---
 drivers/gpu/drm/tests/drm_mm_test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/tests/drm_mm_test.c 
b/drivers/gpu/drm/tests/drm_mm_test.c
index 186b28dc70380..05d5e7af6d250 100644
--- a/drivers/gpu/drm/tests/drm_mm_test.c
+++ b/drivers/gpu/drm/tests/drm_mm_test.c
@@ -939,7 +939,7 @@ static void drm_test_mm_insert_range(struct kunit *test)
KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, 
count, size, 0, max - 1));
KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, 
count, size, 0, max / 2));
KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, 
count, size,
-   max / 2, 
max / 2));
+   max / 2, 
max));
KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, 
count, size,
max / 4 + 
1, 3 * max / 4 - 1));
 
-- 
2.41.0



Re: [Intel-gfx] [PATCH i-g-t v2 05/17] lib/kunit: Fix illegal igt_fail() calls inside subtest body

2023-09-13 Thread Janusz Krzysztofik
On Monday, 11 September 2023 13:57:29 CEST Mauro Carvalho Chehab wrote:
> On Mon, 11 Sep 2023 11:28:32 +0200
> Janusz Krzysztofik  wrote:
> 
> > Hi Mauro,
> > 
> > Thanks for review.
> > 
> > On Monday, 11 September 2023 10:52:51 CEST Mauro Carvalho Chehab wrote:
> > > On Fri,  8 Sep 2023 14:32:39 +0200
> > > Janusz Krzysztofik  wrote:
> > >   
> > > > In a body of a subtest with dynamic sub-subtests, it is illegal to 
call
> > > > igt_fail() and its variants from outside of a dynamic sub-subtest 
body.
> > > > On the other hand, it is perfectly legal to call either igt_skip() and
> > > > friends or __igt_abort() or its variant from there.
> > > > 
> > > > In the current implementation of igt_kunit(), there are several places
> > > > where igt_fail() is called despite being illegal.  Moreover, it is 
called
> > > > with IGT_EXIT_ABORT as an argument with no good reason for using such
> > > > aggressive method that forces CI to trigger system reboot (in most 
cases
> > > > igt_runner can decide if abort is required).
> > > > 
> > > > Follow igt_kselftests() pattern more closely, where similar setup and
> > > > cleanup operations are performed but their potential errors are 
processed
> > > > in a more friendly way.  Move common cleanup and their corresponding 
setup
> > > > steps out of the subtest body.  Place the latter as requirements in a
> > > > preceding igt_fixture section.  Replace remaining illegal igt_fail() 
calls
> > > > with more friendly skips.  Let igt_runner decide if abort is needed.
> > > > 
> > > > Signed-off-by: Janusz Krzysztofik 
> > > > ---
> > > >  lib/igt_kmod.c | 75 ++
+---
> > > >  1 file changed, 22 insertions(+), 53 deletions(-)
> > > > 
> > > > diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
> > > > index 1d1cd51170..78b8eb8f53 100644
> > > > --- a/lib/igt_kmod.c
> > > > +++ b/lib/igt_kmod.c  
> > ...
> > > > @@ -825,24 +793,21 @@ static void __igt_kunit(const char *module_name, 
const char *opts)
> > > > }
> > > > }
> > > >  
> > > > -unload:
> > > > -   igt_ktest_end(&tst);
> > > > -
> > > > -   igt_ktest_fini(&tst);
> > > > -
> > > > -   igt_skip_on_f(skip, "Skipping test, as probing KUnit module 
failed\n");
> > > > -
> > > > -   if (fail)
> > > > -   igt_fail(IGT_EXIT_ABORT);
> > > > -
> > > > ret = ktap_parser_stop();
> > > >  
> > > > -   if (ret != 0)
> > > > -   igt_fail(IGT_EXIT_ABORT);
> > > > +   igt_skip_on_f(ret, "KTAP parser failed\n");
> > > >  }
> > > >  
> > > >  void igt_kunit(const char *module_name, const char *name, const char 
*opts)
> > > >  {
> > > > +   struct igt_ktest tst;
> > > > +
> > > > +   if (igt_ktest_init(&tst, module_name) != 0)
> > > > +   return;  
> > > 
> > > Shouldn't it be calling igt_skip() here too?  
> > 
> > Maybe yes.  I've chosen to follow the algorithm used in igt_kselftest.  
There 
> > was an igt_skip() variant there initially but in 2017 that was converted 
to 
> > the current return only by Peter with IGT commit 9f92893b11e8 ("lib/
igt_kmod: 
> > Don't call igt_assert or igt_require without a fixture").  However, 
> > justification for dropping igt_require() instead of calling it from an 
> > igt_fixture section may not apply to kunit modules:
> > 
> > "If kmod_module_new_from_name fails, ... return normally from 
igt_kselftest, 
> > matching behaviour when the module loading is successful but it doesn't 
> > contain selftests."
> > 
> > While i915 could be built with no selftests included, a kunit module 
without 
> > any tests doesn't make sense, then silent return may be not what we need.
> 
> Yeah, selftests are handled on a different way with regards to module
> probe, so I guess we need the igt_skip there if modprobe fails.

After having a closer look at it, I think that igt_ktest_init() has nothing to 
do with actual modprobe, and it can fail only on either no memory or if 
module_name == NULL.  Anyway, I'll make the subtest skip if it fails.

> Well, you can probably simulate it by renaming a Kunit module
> and see how IGT will handle that with the current code and with
> igt_skip().

Yes, I've tired, and my results have confirmed my conclusions from code 
review.  But more important, I've found an issue in patch 15/17, "Parse KTAP 
report from the main process thread", that can cause first read() to wait 
infinitely, unless interrupted, if modprobe fails.  I've already developed a 
working fix that interrupts that read() on modprobe failure, and I'll include 
it in next version of the series.

Thanks,
Janusz

> 
> (Btw, I intend to review the other patches on this series, but need
> some time to do tests, as some changes here are not trivial)
> 
> Regards,
> Mauro
> 






Re: [Intel-gfx] [PATCH i-g-t v2 07/17] lib/ktap: Don't ignore interrupt signals

2023-09-13 Thread Janusz Krzysztofik
On Monday, 11 September 2023 11:01:42 CEST Mauro Carvalho Chehab wrote:
> On Fri,  8 Sep 2023 14:32:41 +0200
> Janusz Krzysztofik  wrote:
> 
> > While reading KTAP data from /dev/kmsg we now ignore interrupt signals
> > that may occur during read() and we continue reading the data.  No
> > explanation has been provided on what that could be needed for.
> 
> The reason is that kunit module load takes seconds, as it only finishes
> loading after all tests are executed.
> 
> So, interrupting IGT won't interrupt the tests, and kmsg will still
> be filled by test results.
> 
> IMO, the right thing to do here is to ignore interrupts, as otherwise
> the logs for the next test will be polluted by the KTAP messages and
> the Kernel will be kept on an unstable state, as running tests while
> kUnit tests are running is not supported.

Well, not really.  Please have a look at the following two log excerpts.  The 
first one is from a complete, not interrupted execution of drm_mm test:

Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com sudo[15594]: jkrzyszt : 
TTY=pts/14 ; PWD=/home/jkrzyszt/build/igt ; USER=root ; COMMAND=./tests/drm_mm
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com sudo[15594]: 
pam_unix(sudo:session): session opened for user root(uid=0) by 
jkrzyszt(uid=1000)
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: Console: switching to 
colour dummy device 80x25
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
executing
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
starting subtest drm_mm_test
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: # drm_mm: Testing 
DRM range manager, with random_seed=0x5b01fc53 max_iterations=8192 max_prime=128
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: KTAP version 1
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: # Subtest: drm_mm
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: 1..19
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 1 
drm_test_mm_init
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 2 
drm_test_mm_debug
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
starting dynamic subtest drm_mm-drm_test_mm_init
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
finished subtest drm_mm-drm_test_mm_init, SUCCESS
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
starting dynamic subtest drm_mm-drm_test_mm_debug
Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
finished subtest drm_mm-drm_test_mm_debug, SUCCESS
Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 3 
drm_test_mm_reserve
Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 4 
drm_test_mm_insert
Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
starting dynamic subtest drm_mm-drm_test_mm_reserve
Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
finished subtest drm_mm-drm_test_mm_reserve, SUCCESS
Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
starting dynamic subtest drm_mm-drm_test_mm_insert
Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
finished subtest drm_mm-drm_test_mm_insert, SUCCESS
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 5 
drm_test_mm_replace
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 6 
drm_test_mm_insert_range
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
starting dynamic subtest drm_mm-drm_test_mm_replace
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
finished subtest drm_mm-drm_test_mm_replace, SUCCESS
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
starting dynamic subtest drm_mm-drm_test_mm_insert_range
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
finished subtest drm_mm-drm_test_mm_insert_range, SUCCESS
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com kernel: # 
drm_test_mm_frag: bottom-up fragmented insert of 1 and 2 insertions 
took 6009658 and 13648333 nsecs
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com kernel: # 
drm_test_mm_frag: top-down fragmented insert of 1 and 2 insertions took 
6518544 and 13824246 nsecs
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 7 
drm_test_mm_frag
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 8 
drm_test_mm_align
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 9 
drm_test_mm_align32
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 10 
drm_test_mm_align64
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
starting dynamic subtest drm_mm-drm_test_mm_frag
Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
finished subtes

Re: [Intel-gfx] [PATCH i-g-t v2 07/17] lib/ktap: Don't ignore interrupt signals

2023-09-15 Thread Janusz Krzysztofik
On Friday, 15 September 2023 14:25:24 CEST Mauro Carvalho Chehab wrote:
> On Wed, 13 Sep 2023 16:04:10 +0200
> Janusz Krzysztofik  wrote:
> 
> > On Monday, 11 September 2023 11:01:42 CEST Mauro Carvalho Chehab wrote:
> > > On Fri,  8 Sep 2023 14:32:41 +0200
> > > Janusz Krzysztofik  wrote:
> > >   
> > > > While reading KTAP data from /dev/kmsg we now ignore interrupt signals
> > > > that may occur during read() and we continue reading the data.  No
> > > > explanation has been provided on what that could be needed for.  
> > > 
> > > The reason is that kunit module load takes seconds, as it only finishes
> > > loading after all tests are executed.
> > > 
> > > So, interrupting IGT won't interrupt the tests, and kmsg will still
> > > be filled by test results.
> > > 
> > > IMO, the right thing to do here is to ignore interrupts, as otherwise
> > > the logs for the next test will be polluted by the KTAP messages and
> > > the Kernel will be kept on an unstable state, as running tests while
> > > kUnit tests are running is not supported.  
> > 
> > Well, not really.  Please have a look at the following two log excerpts.  
> > The 
> > first one is from a complete, not interrupted execution of drm_mm test:
> > 
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com sudo[15594]: jkrzyszt : 
> > TTY=pts/14 ; PWD=/home/jkrzyszt/build/igt ; USER=root ; 
> > COMMAND=./tests/drm_mm
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com sudo[15594]: 
> > pam_unix(sudo:session): session opened for user root(uid=0) by 
> > jkrzyszt(uid=1000)
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: Console: 
> > switching to colour dummy device 80x25
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > executing
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > starting subtest drm_mm_test
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: # drm_mm: 
> > Testing DRM range manager, with random_seed=0x5b01fc53 max_iterations=8192 
> > max_prime=128
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: KTAP version 1
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: # Subtest: 
> > drm_mm
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: 1..19
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 1 
> > drm_test_mm_init
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 2 
> > drm_test_mm_debug
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > starting dynamic subtest drm_mm-drm_test_mm_init
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > finished subtest drm_mm-drm_test_mm_init, SUCCESS
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > starting dynamic subtest drm_mm-drm_test_mm_debug
> > Sep 13 15:14:39 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > finished subtest drm_mm-drm_test_mm_debug, SUCCESS
> > Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 3 
> > drm_test_mm_reserve
> > Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 4 
> > drm_test_mm_insert
> > Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > starting dynamic subtest drm_mm-drm_test_mm_reserve
> > Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > finished subtest drm_mm-drm_test_mm_reserve, SUCCESS
> > Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > starting dynamic subtest drm_mm-drm_test_mm_insert
> > Sep 13 15:14:46 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > finished subtest drm_mm-drm_test_mm_insert, SUCCESS
> > Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 5 
> > drm_test_mm_replace
> > Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com kernel: ok 6 
> > drm_test_mm_insert_range
> > Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > starting dynamic subtest drm_mm-drm_test_mm_replace
> > Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > finished subtest drm_mm-drm_test_mm_replace, SUCCESS
> > Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > starting dynamic subtest drm_mm-drm_test_mm_insert_range
> > Sep 13 15:14:55 jkrzyszt-mobl2.ger.corp.intel.com unknown: [IGT] drm_mm: 
> > finished subtest drm_mm-drm_test_

Re: [Intel-gfx] [PATCH i-g-t v2 13/17] lib/ktap: Reimplement KTAP parser

2023-09-15 Thread Janusz Krzysztofik
Hi Mauro,

On Friday, 15 September 2023 14:28:49 CEST Mauro Carvalho Chehab wrote:
> On Fri,  8 Sep 2023 14:32:47 +0200
> Janusz Krzysztofik  wrote:
> 
> Forgot to mention on my past review:
> 
> > +  &n, &len) == 1 && len == strlen(buf))) {
> > +   /*
> > +* TODO: drop the following workaround as soon as
> > +* kernel side issue of missing lines with top level
> > +* KTAP version and test suite plan is fixed.
> > +*/
> 
> Please add a link to lore with the thread discussing the issue upstream,
> as it can be helpful while this workaround is here.
> 
> Also, I would place the workaround on a separate patch, to make
> easier to revert it when upstream fixes it.

Thanks for pointing that out.  Since we already have those kernel changes 
included in v6.6-rc1, then in drm-tip, I'll drop the workaround now.

Thanks,
Janusz





Re: [Intel-gfx] [PATCH i-g-t v2 13/17] lib/ktap: Reimplement KTAP parser

2023-09-15 Thread Janusz Krzysztofik
On Friday, 15 September 2023 15:09:58 CEST Janusz Krzysztofik wrote:
> Hi Mauro,
> 
> On Friday, 15 September 2023 14:28:49 CEST Mauro Carvalho Chehab wrote:
> > On Fri,  8 Sep 2023 14:32:47 +0200
> > Janusz Krzysztofik  wrote:
> > 
> > Forgot to mention on my past review:
> > 
> > > +&n, &len) == 1 && len == 
strlen(buf))) {
> > > + /*
> > > +  * TODO: drop the following workaround as soon as
> > > +  * kernel side issue of missing lines with top level
> > > +  * KTAP version and test suite plan is fixed.
> > > +  */
> > 
> > Please add a link to lore with the thread discussing the issue upstream,
> > as it can be helpful while this workaround is here.
> > 
> > Also, I would place the workaround on a separate patch, to make
> > easier to revert it when upstream fixes it.
> 
> Thanks for pointing that out.  Since we already have those kernel changes 
> included in v6.6-rc1, then in drm-tip, I'll drop the workaround now.

Or would you like, Mauro, to keep the workaround for CI testing of linux-xe 
not yet updated to v6.6-rc1?

Thanks,
Janusz

> 
> Thanks,
> Janusz
> 






Re: [Intel-gfx] [PATCH] drm/tests: Fix incorrect argument in drm_test_mm_insert_range

2023-09-15 Thread Janusz Krzysztofik
Hi Maíra,

Thanks for review.

On Friday, 15 September 2023 16:01:31 CEST Maira Canal wrote:
> Hi,
> 
> On 9/11/23 10:03, Janusz Krzysztofik wrote:
> > While drm_mm test was converted form igt selftest to kunit, unexpected
> > value of "end" argument equal "start" was introduced to one of calls to a
> > function that executes the drm_test_mm_insert_range for specific start/end
> > pair of arguments.  As a consequence, DRM_MM_BUG_ON(end <= start) is
> > triggered.  Fix it by restoring the original value.
> > 
> > Fixes: fc8d29e298cf ("drm: selftest: convert drm_mm selftest to KUnit")
> > Signed-off-by: Janusz Krzysztofik 
> 
> Reviewed-by: Maíra Canal 
> 
> Do you need me to push it to drm-misc-fixes?

Yes, please do if you can.

Thanks,
Janusz

> 
> Best Regards,
> - Maíra
> 
> > Cc: "Maíra Canal" 
> > Cc: Arthur Grillo 
> > Cc: Javier Martinez Canillas 
> > Cc: Daniel Latypov 
> > Cc: sta...@vger.kernel.org # v6.1+
> > ---
> >   drivers/gpu/drm/tests/drm_mm_test.c | 2 +-
> >   1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/tests/drm_mm_test.c 
> > b/drivers/gpu/drm/tests/drm_mm_test.c
> > index 186b28dc70380..05d5e7af6d250 100644
> > --- a/drivers/gpu/drm/tests/drm_mm_test.c
> > +++ b/drivers/gpu/drm/tests/drm_mm_test.c
> > @@ -939,7 +939,7 @@ static void drm_test_mm_insert_range(struct kunit *test)
> > KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, 
> > count, size, 0, max - 1));
> > KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, 
> > count, size, 0, max / 2));
> > KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, 
> > count, size,
> > -   max / 2, 
> > max / 2));
> > +   max / 2, 
> > max));
> > KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, 
> > count, size,
> > max / 4 + 
> > 1, 3 * max / 4 - 1));
> >   
> 






[Intel-gfx] [PATCH i-g-t v3 00/17] Fix IGT Kunit implementation issues

2023-09-18 Thread Janusz Krzysztofik
v3: Also call igt_skip() on igt_ktest_init() failure (Mauro), but then,
initialize local tst structure when declaring it to avoid freeing a
random pointer from igt_ktest_fini() when only listing subtests,
  - call igt_ktest_end() from igt_fixture so it is not unnecessarily
called when only listing subtests,
  - drop EINTR handling completely as not applicable since SIGINT default
signal handler kills the whole process anyway,
  - update commit description to also mention read error handling fix,
  - interrupt blocking read() on modprobe failure.
v2: Fix incorrect and missing includes in the test source file,
  - add license and copyright clauses to the test source file.

Janusz Krzysztofik (17):
  lib/kunit: Drop unused file stream
  lib/kunit: Stop loading kunit module explicitly
  lib/kunit: Fix struct kmod_module kunit_kmod not freed
  lib/kunit: Optimize calls to igt_success/skip/fail()
  lib/kunit: Fix illegal igt_fail() calls inside subtest body
  lib/ktap: Make sure we fail on premature cancel
  lib/ktap: Drop checks for EINTR on read() failures
  lib/kunit: Cancel KTP parser on module load failure
  lib/ktap: Drop is_running flag
  lib/ktap: Read /dev/kmsg in blocking mode
  lib/kunit: Fail / skip on kernel taint
  lib/ktap: Use IGT linked lists for storing KTAP results
  lib/ktap: Reimplement KTAP parser
  lib/kunit: Load test modules in background
  lib/kunit: Parse KTAP report from the main process thread
  lib/kunit: Strip "_test" or "_kunit" suffix from subtest names
  lib/kunit: Omit suite name prefix if the same as subtest name

 lib/igt_kmod.c  | 320 ++
 lib/igt_ktap.c  | 833 
 lib/igt_ktap.h  |  28 +-
 lib/tests/igt_ktap_parser.c | 246 +++
 lib/tests/meson.build   |   1 +
 tests/drm_mm.c  |  42 +-
 6 files changed, 775 insertions(+), 695 deletions(-)
 create mode 100644 lib/tests/igt_ktap_parser.c

-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v3 01/17] lib/kunit: Drop unused file stream

2023-09-18 Thread Janusz Krzysztofik
In the process of reviewing patches that introduced kunit support, I asked
once if we could use line buffered input instead of explicitly looking for
newlines in kmsg data.  While my idea was wrong because each read of raw
data from /dev/kmsg always returns one full log record that always ends
with a newline, conversion of /dev/kmsg file descriptor to a file stream
with freopen() was added to the code.  However, that file stream has never
been used for line buffered input.  While the file stream is passed to
functions that actually read the data, there it is converted back to a
file descriptor with fileno() and raw data is read with read().

Drop the unnecessary conversions and teach functions to accept and process
just the file descriptor of /dev/kmsg.

Signed-off-by: Janusz Krzysztofik 
Acked-by: Mauro Carvalho Chehab 
---
 lib/igt_kmod.c | 12 +-
 lib/igt_ktap.c | 62 +++---
 lib/igt_ktap.h |  2 +-
 3 files changed, 31 insertions(+), 45 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 6205871791..97667a896f 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -758,7 +758,6 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
 {
struct igt_ktest tst;
struct kmod_module *kunit_kmod;
-   FILE *f;
bool is_builtin;
int ret;
struct ktap_test_results *results;
@@ -774,7 +773,6 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
 
if (igt_ktest_begin(&tst) != 0) {
igt_warn("Unable to begin ktest for %s\n", module_name);
-
igt_ktest_fini(&tst);
igt_fail(IGT_EXIT_ABORT);
}
@@ -791,14 +789,6 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
goto unload;
}
 
-   f = fdopen(tst.kmsg, "r");
-
-   if (f == NULL) {
-   igt_warn("Could not turn /dev/kmsg file descriptor into a FILE 
pointer\n");
-   fail = true;
-   goto unload;
-   }
-
/* The KUnit module is required for running any KUnit tests */
ret = igt_kmod_load("kunit", NULL);
if (ret) {
@@ -814,7 +804,7 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
 
is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
 
-   results = ktap_parser_start(f, is_builtin);
+   results = ktap_parser_start(tst.kmsg, is_builtin);
 
ret = igt_kmod_load(module_name, opts);
if (ret) {
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index ecdcb8d83d..123a40d183 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -16,7 +16,7 @@
 #define DELIMITER "-"
 
 struct ktap_parser_args {
-   FILE *fp;
+   int fd;
bool is_builtin;
volatile bool is_running;
int ret;
@@ -24,7 +24,7 @@ struct ktap_parser_args {
 
 static struct ktap_test_results results;
 
-static int log_to_end(enum igt_log_level level, FILE *f,
+static int log_to_end(enum igt_log_level level, int fd,
  char *record, const char *format, ...) 
__attribute__((format(printf, 4, 5)));
 
 /**
@@ -39,12 +39,11 @@ static int log_to_end(enum igt_log_level level, FILE *f,
  *
  * Returns: 0 for success, or -2 if there's an error reading from the file
  */
-static int log_to_end(enum igt_log_level level, FILE *f,
+static int log_to_end(enum igt_log_level level, int fd,
  char *record, const char *format, ...)
 {
va_list args;
const char *lend;
-   int f_fd = fileno(f);
 
/* Cutoff after newline character, in order to not display garbage */
char *cutoff = strchr(record, '\n');
@@ -61,7 +60,7 @@ static int log_to_end(enum igt_log_level level, FILE *f,
while (*lend == '\0') {
igt_log(IGT_LOG_DOMAIN, level, "%s", record);
 
-   while (read(f_fd, record, BUF_LEN) < 0) {
+   while (read(fd, record, BUF_LEN) < 0) {
if (!READ_ONCE(ktap_args.is_running)) {
igt_warn("ktap parser stopped\n");
return -2;
@@ -157,8 +156,8 @@ static int tap_version_present(char* record, bool 
print_info)
 
 /**
  * find_next_tap_subtest:
- * @fp: FILE pointer
- * @record: buffer used to read fp
+ * @fd: file descriptor
+ * @record: buffer used to read fd
  * @is_builtin: whether KUnit is built-in or not
  *
  * Returns:
@@ -167,11 +166,10 @@ static int tap_version_present(char* record, bool 
print_info)
  * -2 if there are problems while reading the file.
  * any other value corresponds to the amount of cases of the next (sub)test
  */
-static int find_next_tap_subtest(FILE *fp, char *record, char *test_name, bool 
is_builtin)
+static int find_next_tap_subtest(int fd, char *record, char *test_name, bool 
is_builtin)
 {
cons

[Intel-gfx] [PATCH i-g-t v3 02/17] lib/kunit: Stop loading kunit module explicitly

2023-09-18 Thread Janusz Krzysztofik
Since kmod functions we use for module loading can process module
dependencies, there is no need to load the "kunit" module explicitly
before loading a kunit test module.  For the same reason we already don't
unload the "kunit" module explicitly on cleanup.  Drop the unnecessary
operation.

Signed-off-by: Janusz Krzysztofik 
Acked-by: Mauro Carvalho Chehab 
---
 lib/igt_kmod.c | 6 --
 1 file changed, 6 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 97667a896f..faf31afabc 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -789,12 +789,6 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
goto unload;
}
 
-   /* The KUnit module is required for running any KUnit tests */
-   ret = igt_kmod_load("kunit", NULL);
-   if (ret) {
-   skip = ret;
-   goto unload;
-   }
ret = kmod_module_new_from_name(kmod_ctx(), "kunit", &kunit_kmod);
if (ret) {
igt_warn("Unable to load KUnit\n");
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v3 04/17] lib/kunit: Optimize calls to igt_success/skip/fail()

2023-09-18 Thread Janusz Krzysztofik
Calling igt_success() explicitly at the end of subtest body is not needed.
Other calls to igt_success() can be usually avoided by inverting test
result checks.  Optimize the code that now calls igt_success().

Moreover, using more advanced variants of igt_skip() and igt_fail() where
applicable makes the code more compact.  Go for it.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Mauro Carvalho Chehab 
---
 lib/igt_kmod.c | 14 +++---
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 34ddec3fad..1d1cd51170 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -814,12 +814,8 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
if (READ_ONCE(results->head) != NULL) {
pthread_mutex_lock(&results->mutex);
 
-   igt_dynamic(results->head->test_name) {
-   if (READ_ONCE(results->head->passed))
-   igt_success();
-   else
-   igt_fail(IGT_EXIT_FAILURE);
-   }
+   igt_dynamic(results->head->test_name)
+   igt_assert(READ_ONCE(results->head->passed));
 
temp = results->head;
results->head = results->head->next;
@@ -834,8 +830,7 @@ unload:
 
igt_ktest_fini(&tst);
 
-   if (skip)
-   igt_skip("Skipping test, as probing KUnit module returned %d", 
skip);
+   igt_skip_on_f(skip, "Skipping test, as probing KUnit module failed\n");
 
if (fail)
igt_fail(IGT_EXIT_ABORT);
@@ -844,9 +839,6 @@ unload:
 
if (ret != 0)
igt_fail(IGT_EXIT_ABORT);
-
-   if (ret == 0)
-   igt_success();
 }
 
 void igt_kunit(const char *module_name, const char *name, const char *opts)
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v3 03/17] lib/kunit: Fix struct kmod_module kunit_kmod not freed

2023-09-18 Thread Janusz Krzysztofik
We obtain a kmod_module structure for kunit module in order to check if
it is modular or built-in, then we never release that structure.  Fix it.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Mauro Carvalho Chehab 
---
 lib/igt_kmod.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index faf31afabc..34ddec3fad 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -797,6 +797,7 @@ static void __igt_kunit(const char *module_name, const char 
*opts)
}
 
is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
+   kmod_module_unref(kunit_kmod);
 
results = ktap_parser_start(tst.kmsg, is_builtin);
 
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v3 05/17] lib/kunit: Fix illegal igt_fail() calls inside subtest body

2023-09-18 Thread Janusz Krzysztofik
In a body of a subtest with dynamic sub-subtests, it is illegal to call
igt_fail() and its variants from outside of a dynamic sub-subtest body.
On the other hand, it is perfectly legal to call either igt_skip() and
friends or __igt_abort() or its variant from there.

In the current implementation of igt_kunit(), there are several places
where igt_fail() is called despite being illegal.  Moreover, it is called
with IGT_EXIT_ABORT as an argument with no good reason for using such
aggressive method that forces CI to trigger system reboot (in most cases
igt_runner can decide if abort is required).

Follow igt_kselftests() pattern more closely, where similar setup and
cleanup operations are performed but their potential errors are processed
in a more friendly way.  Move common cleanup and their corresponding setup
steps out of the subtest body.  Place the latter as requirements in a
preceding igt_fixture section.  Replace remaining illegal igt_fail() calls
with more friendly skips.  Let igt_runner decide if abort is needed.

v2: Also call igt_skip() on igt_ktest_init() failure (Mauro), but then,
initialize local tst structure when declaring it to avoid freeing a
random pointer from igt_ktest_fini() when only listing subtests,
  - call igt_ktest_end() from igt_fixture so it is not unnecessarily
called when only listing subtests.

Signed-off-by: Janusz Krzysztofik 
Cc: Mauro Carvalho Chehab 
---
 lib/igt_kmod.c | 76 +++---
 1 file changed, 23 insertions(+), 53 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 1d1cd51170..063e4c12db 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -754,59 +754,27 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
  *
  * Returns: IGT default codes
  */
-static void __igt_kunit(const char *module_name, const char *opts)
+static void __igt_kunit(struct igt_ktest *tst, const char *opts)
 {
-   struct igt_ktest tst;
struct kmod_module *kunit_kmod;
bool is_builtin;
int ret;
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
-   int skip = 0;
-   bool fail = false;
-
-   /* get normalized module name */
-   if (igt_ktest_init(&tst, module_name) != 0) {
-   igt_warn("Unable to initialize ktest for %s\n", module_name);
-   igt_fail(IGT_EXIT_ABORT);
-   }
 
-   if (igt_ktest_begin(&tst) != 0) {
-   igt_warn("Unable to begin ktest for %s\n", module_name);
-   igt_ktest_fini(&tst);
-   igt_fail(IGT_EXIT_ABORT);
-   }
+   igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n");
 
-   if (tst.kmsg < 0) {
-   igt_warn("Could not open /dev/kmsg\n");
-   fail = true;
-   goto unload;
-   }
-
-   if (lseek(tst.kmsg, 0, SEEK_END)) {
-   igt_warn("Could not seek the end of /dev/kmsg\n");
-   fail = true;
-   goto unload;
-   }
-
-   ret = kmod_module_new_from_name(kmod_ctx(), "kunit", &kunit_kmod);
-   if (ret) {
-   igt_warn("Unable to load KUnit\n");
-   skip = ret;
-   goto unload;
-   }
+   igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
 
+   igt_skip_on(kmod_module_new_from_name(kmod_ctx(), "kunit", 
&kunit_kmod));
is_builtin = kmod_module_get_initstate(kunit_kmod) == 
KMOD_MODULE_BUILTIN;
kmod_module_unref(kunit_kmod);
 
-   results = ktap_parser_start(tst.kmsg, is_builtin);
+   results = ktap_parser_start(tst->kmsg, is_builtin);
 
-   ret = igt_kmod_load(module_name, opts);
-   if (ret) {
-   skip = ret;
-   igt_warn("Unable to load %s module\n", module_name);
-   ret = ktap_parser_stop();
-   goto unload;
+   if (igt_debug_on(igt_kmod_load(tst->module_name, opts) < 0)) {
+   igt_ignore_warn(ktap_parser_stop());
+   igt_skip("Unable to load %s module\n", tst->module_name);
}
 
while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != 
NULL)
@@ -825,24 +793,21 @@ static void __igt_kunit(const char *module_name, const 
char *opts)
}
}
 
-unload:
-   igt_ktest_end(&tst);
-
-   igt_ktest_fini(&tst);
-
-   igt_skip_on_f(skip, "Skipping test, as probing KUnit module failed\n");
-
-   if (fail)
-   igt_fail(IGT_EXIT_ABORT);
-
ret = ktap_parser_stop();
 
-   if (ret != 0)
-   igt_fail(IGT_EXIT_ABORT);
+   igt_skip_on_f(ret, "KTAP parser failed\n");
 }
 
 void igt_kunit(const char *module_name, const char *name, const char *opts)
 {
+   struct igt_ktest tst = { .kmsg = -1, };
+
+
+   igt_fixture {
+   igt_s

[Intel-gfx] [PATCH i-g-t v3 06/17] lib/ktap: Make sure we fail on premature cancel

2023-09-18 Thread Janusz Krzysztofik
After loading a kunit test module that executes some kunit test cases, we
evaluate overall result of an IGT subtest that corresponds to that module
based on an error code returned by kunit_parser_stop() helper, obtained
from a .ret field of a ktap_args structure.  That code is now assigned to
that structure field right before completion of the KTAP parser thread
start routine.  If the thread is canceled for some reason then the return
code will be undefined.

Initialize the return code on KTAP parser startup with a value that
indicates a failure, then change it to success when so indicated by result
of KTAP parsing.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Mauro Carvalho Chehab 
---
 lib/igt_ktap.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 123a40d183..84fb13218f 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -579,9 +579,7 @@ igt_ktap_parser_start:
 igt_ktap_parser_end:
results.still_running = false;
 
-   if (failed_tests || !found_tests)
-   ktap_args.ret = IGT_EXIT_FAILURE;
-   else
+   if (found_tests && !failed_tests)
ktap_args.ret = IGT_EXIT_SUCCESS;
 
return NULL;
@@ -598,6 +596,7 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
ktap_args.fd = fd;
ktap_args.is_builtin = is_builtin;
ktap_args.is_running = true;
+   ktap_args.ret = IGT_EXIT_FAILURE;
pthread_create(&ktap_parser_thread, NULL, igt_ktap_parser, NULL);
 
return &results;
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v3 07/17] lib/ktap: Drop checks for EINTR on read() failures

2023-09-18 Thread Janusz Krzysztofik
While reading KTAP data from /dev/kmsg we now ignore EINTR failures that
may occur during read() and we continue reading the data.  No explanation
has been provided on what that could be needed for.

Since we use default SIGINT signal handler, read() should never fail with
errno set to EINTR on user interrupt, only the whole process should be
terminated.  Drop checks for errno == EINTR as not applicable.

v2: Drop handling of EINTR completely, update commit message and
descripion.

Signed-off-by: Janusz Krzysztofik 
Cc: Mauro Carvalho Chehab 
---
 lib/igt_ktap.c | 15 ---
 1 file changed, 15 deletions(-)

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 84fb13218f..ce07f9aed7 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -66,9 +66,6 @@ static int log_to_end(enum igt_log_level level, int fd,
return -2;
}
 
-   if (errno == EINTR)
-   continue;
-
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
return -2;
@@ -188,9 +185,6 @@ static int find_next_tap_subtest(int fd, char *record, char 
*test_name, bool is_
return -2;
}
 
-   if (errno == EINTR)
-   continue;
-
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
return -2;
@@ -232,9 +226,6 @@ static int find_next_tap_subtest(int fd, char *record, char 
*test_name, bool is_
return -2;
}
 
-   if (errno == EINTR)
-   continue;
-
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
return -2;
@@ -387,9 +378,6 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
return -1;
}
 
-   if (errno == EINTR)
-   continue;
-
if (errno == EAGAIN)
/* No records available */
continue;
@@ -540,9 +528,6 @@ igt_ktap_parser_start:
/* No records available */
continue;
 
-   if (errno == EINTR)
-   continue;
-
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. You may 
want to increase log_buf_len in kmcdline\n");
goto igt_ktap_parser_end;
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v3 08/17] lib/kunit: Cancel KTP parser on module load failure

2023-09-18 Thread Janusz Krzysztofik
For our KTAP parser to be running in parallel with kunit test module
loading, we now start it in a separate thread before we load the module.
If the module loading fails then we join the KTAP parser thread right
after that failure.  If the KTAP thread sleeps for some reason then we
can fail to break the test immediately.

Cancel the KTAP parser thread right after module load error and before
joining it.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Mauro Carvalho Chehab 
---
 lib/igt_kmod.c | 1 +
 lib/igt_ktap.c | 6 ++
 lib/igt_ktap.h | 1 +
 3 files changed, 8 insertions(+)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 063e4c12db..7392276401 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -773,6 +773,7 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
results = ktap_parser_start(tst->kmsg, is_builtin);
 
if (igt_debug_on(igt_kmod_load(tst->module_name, opts) < 0)) {
+   ktap_parser_cancel();
igt_ignore_warn(ktap_parser_stop());
igt_skip("Unable to load %s module\n", tst->module_name);
}
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index ce07f9aed7..0db42d1243 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -587,6 +587,12 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
return &results;
 }
 
+void ktap_parser_cancel(void)
+{
+   ktap_args.is_running = false;
+   pthread_cancel(ktap_parser_thread);
+}
+
 int ktap_parser_stop(void)
 {
ktap_args.is_running = false;
diff --git a/lib/igt_ktap.h b/lib/igt_ktap.h
index ea57c2bb9b..991800e912 100644
--- a/lib/igt_ktap.h
+++ b/lib/igt_ktap.h
@@ -45,6 +45,7 @@ struct ktap_test_results {
 
 
 struct ktap_test_results *ktap_parser_start(int fd, bool is_builtin);
+void ktap_parser_cancel(void);
 int ktap_parser_stop(void);
 
 #endif /* IGT_KTAP_H */
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v3 09/17] lib/ktap: Drop is_running flag

2023-09-18 Thread Janusz Krzysztofik
Since we now call pthread_cancel() when we want to stop KTAP parser before
it completes, and we take care of returning failure in that case as a
result of KTAP parsing, we no longer need to check a flag that indicates
whether we should continue parsing or return a failure.  Drop that flag.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Mauro Carvalho Chehab 
---
 lib/igt_ktap.c | 32 
 1 file changed, 32 deletions(-)

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 0db42d1243..5bc5e003d7 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -18,7 +18,6 @@
 struct ktap_parser_args {
int fd;
bool is_builtin;
-   volatile bool is_running;
int ret;
 } ktap_args;
 
@@ -61,11 +60,6 @@ static int log_to_end(enum igt_log_level level, int fd,
igt_log(IGT_LOG_DOMAIN, level, "%s", record);
 
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -2;
-   }
-
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
return -2;
@@ -180,11 +174,6 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
 
if (is_builtin) {
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -2;
-   }
-
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
return -2;
@@ -221,11 +210,6 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
cutoff[0] = '\0';
 
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -2;
-   }
-
if (errno == EPIPE) {
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
return -2;
@@ -373,11 +357,6 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
 
for (int i = 0; i < test_count; i++) {
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   return -1;
-   }
-
if (errno == EAGAIN)
/* No records available */
continue;
@@ -511,19 +490,11 @@ void *igt_ktap_parser(void *unused)
failed_tests = false;
found_tests = false;
 
-   if (!READ_ONCE(ktap_args.is_running))
-   goto igt_ktap_parser_end;
-
 igt_ktap_parser_start:
test_name[0] = '\0';
test_name[BUF_LEN] = '\0';
 
while (read(fd, record, BUF_LEN) < 0) {
-   if (!READ_ONCE(ktap_args.is_running)) {
-   igt_warn("ktap parser stopped\n");
-   goto igt_ktap_parser_end;
-   }
-
if (errno == EAGAIN)
/* No records available */
continue;
@@ -580,7 +551,6 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
 
ktap_args.fd = fd;
ktap_args.is_builtin = is_builtin;
-   ktap_args.is_running = true;
ktap_args.ret = IGT_EXIT_FAILURE;
pthread_create(&ktap_parser_thread, NULL, igt_ktap_parser, NULL);
 
@@ -589,13 +559,11 @@ struct ktap_test_results *ktap_parser_start(int fd, bool 
is_builtin)
 
 void ktap_parser_cancel(void)
 {
-   ktap_args.is_running = false;
pthread_cancel(ktap_parser_thread);
 }
 
 int ktap_parser_stop(void)
 {
-   ktap_args.is_running = false;
pthread_join(ktap_parser_thread, NULL);
return ktap_args.ret;
 }
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v3 10/17] lib/ktap: Read /dev/kmsg in blocking mode

2023-09-18 Thread Janusz Krzysztofik
We obtain KTAP report from /dev/kmsg.  That file is now opened from
igt_ktest_begin(), a function originally designed for i915 selftests and
now reused with kunit tests.  The original intention of opening that file
was to dump kernel messages to stderr on selftest error.  For that
purpose, the file is now opened in non-blocking mode so we don't end up
waiting for more kernel messages than already available.  Since our ktap
parser code reuses the file descriptor, we now have to loop over
EAGAIN responses, waiting for more KTAP data.  Since we have no sleeps
inside those loops, extremely high CPU usage can be observed.

Simplify reading KTAP reports by first switching the file descriptor back
to blocking mode.

While being at it, fix read errors other than EPIPE likely unintentionally
ignored when reading first line of KTAP data.

v2: Drop EINTR handling as not applicable since SIGINT default signal
handler kills the whole process anyway,
  - update commit description to also mention read error handling fix.

Signed-off-by: Janusz Krzysztofik 
Acked-by: Mauro Carvalho Chehab  # v1
---
 lib/igt_kmod.c |  7 +-
 lib/igt_ktap.c | 66 +-
 2 files changed, 28 insertions(+), 45 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 7392276401..96240543a7 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "igt_aux.h"
@@ -758,12 +759,16 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 {
struct kmod_module *kunit_kmod;
bool is_builtin;
-   int ret;
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
+   int flags, ret;
 
igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n");
 
+   flags = fcntl(tst->kmsg, F_GETFL, 0) & ~O_NONBLOCK;
+   igt_skip_on_f(fcntl(tst->kmsg, F_SETFL, flags) == -1,
+ "Could not set /dev/kmsg to blocking mode\n");
+
igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
 
igt_skip_on(kmod_module_new_from_name(kmod_ctx(), "kunit", 
&kunit_kmod));
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 5bc5e003d7..282e44176e 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -59,17 +59,12 @@ static int log_to_end(enum igt_log_level level, int fd,
while (*lend == '\0') {
igt_log(IGT_LOG_DOMAIN, level, "%s", record);
 
-   while (read(fd, record, BUF_LEN) < 0) {
-   if (errno == EPIPE) {
+   if (read(fd, record, BUF_LEN) < 0) {
+   if (errno == EPIPE)
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
-   return -2;
-   }
-
-   if (errno == EAGAIN)
-   /* No records available */
-   continue;
+   else
+   igt_warn("an error occurred while reading kmsg: 
%m\n");
 
-   igt_warn("kmsg truncated: unknown error (%m)\n");
return -2;
}
 
@@ -173,17 +168,12 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
return -1;
 
if (is_builtin) {
-   while (read(fd, record, BUF_LEN) < 0) {
-   if (errno == EPIPE) {
+   if (read(fd, record, BUF_LEN) < 0) {
+   if (errno == EPIPE)
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
-   return -2;
-   }
+   else
+   igt_warn("an error occurred while reading kmsg: 
%m\n");
 
-   if (errno == EAGAIN)
-   /* No records available */
-   continue;
-
-   igt_warn("kmsg truncated: unknown error (%m)\n");
return -2;
}
}
@@ -209,17 +199,12 @@ static int find_next_tap_subtest(int fd, char *record, 
char *test_name, bool is_
if (cutoff)
cutoff[0] = '\0';
 
-   while (read(fd, record, BUF_LEN) < 0) {
-   if (errno == EPIPE) {
+   if (read(fd, record, BUF_LEN) < 0) {
+   if (errno == EPIPE)
igt_warn("kmsg truncated: too many messages. 
You may want to increase log_buf_len in kmcdline\n");
-   return -2;
-

[Intel-gfx] [PATCH i-g-t v3 11/17] lib/kunit: Fail / skip on kernel taint

2023-09-18 Thread Janusz Krzysztofik
Similar to how igt_kselftest() handles kernel taints, fail current dynamic
sub-subtest and skip remaining ones when a kernel taint is detected during
execution of kunit test cases.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Mauro Carvalho Chehab 
---
 lib/igt_kmod.c | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 96240543a7..77fc971f8f 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -761,6 +761,7 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
bool is_builtin;
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
+   unsigned long taints;
int flags, ret;
 
igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n");
@@ -785,12 +786,20 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != 
NULL)
{
+   if (igt_kernel_tainted(&taints)) {
+   ktap_parser_cancel();
+   break;
+   }
+
if (READ_ONCE(results->head) != NULL) {
pthread_mutex_lock(&results->mutex);
 
-   igt_dynamic(results->head->test_name)
+   igt_dynamic(results->head->test_name) {
igt_assert(READ_ONCE(results->head->passed));
 
+   igt_fail_on(igt_kernel_tainted(&taints));
+   }
+
temp = results->head;
results->head = results->head->next;
free(temp);
@@ -801,6 +810,7 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
ret = ktap_parser_stop();
 
+   igt_skip_on(igt_kernel_tainted(&taints));
igt_skip_on_f(ret, "KTAP parser failed\n");
 }
 
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v3 14/17] lib/kunit: Load test modules in background

2023-09-18 Thread Janusz Krzysztofik
For igt_runner to be able to correlate a stream of IGT results from
dynamic sub-subtests that correspond to individual kunit test cases, read
by the igt_runner from stdout / stderr of the test process, with a stream
of kernel messages read from /dev/kmsg, we need both result streams being
fed with data in parallel.  While our KTAP parser is currently started in
the background and reads KTAP results from /dev/kmsg in parallel with
execution of kunit tests performed by the kernel while we are loading a
kunit test module, results from the parser are then only stored as
intermediate data and not processed any further until the module loading
completes.  As a consequence, there is no synchronization between the two
streams.

Call the function that loads the kunit test module from a separate thread
and process the intermediate results immediately, as soon as available
from the background parser, without waiting for completion of module
loading.

Signed-off-by: Janusz Krzysztofik 
Acked-by: Mauro Carvalho Chehab 
---
 lib/igt_kmod.c | 35 +--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 2941524bb4..8fbd274ccf 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "igt_aux.h"
@@ -746,6 +747,21 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
kmod_module_info_free_list(pre);
 }
 
+struct modprobe_data {
+   struct kmod_module *kmod;
+   const char *opts;
+   int err;
+};
+
+static void *modprobe_task(void *arg)
+{
+   struct modprobe_data *data = arg;
+
+   data->err = modprobe(data->kmod, data->opts);
+
+   return NULL;
+}
+
 /**
  * igt_kunit:
  * @module_name: the name of the module
@@ -757,9 +773,11 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
  */
 static void __igt_kunit(struct igt_ktest *tst, const char *opts)
 {
+   struct modprobe_data modprobe = { tst->kmod, opts, 0, };
struct kmod_module *kunit_kmod;
bool is_builtin;
struct ktap_test_results *results;
+   pthread_t modprobe_thread;
unsigned long taints;
int flags, ret;
 
@@ -777,18 +795,25 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
results = ktap_parser_start(tst->kmsg, is_builtin);
 
-   if (igt_debug_on(igt_kmod_load(tst->module_name, opts) < 0)) {
+   if (igt_debug_on(pthread_create(&modprobe_thread, NULL,
+   modprobe_task, &modprobe))) {
ktap_parser_cancel();
igt_ignore_warn(ktap_parser_stop());
-   igt_skip("Unable to load %s module\n", tst->module_name);
+   igt_skip("Failed to create a modprobe thread\n");
}
 
while (READ_ONCE(results->still_running) || 
!igt_list_empty(&results->list))
{
struct ktap_test_results_element *result;
 
+   if (!pthread_tryjoin_np(modprobe_thread, NULL) && modprobe.err) 
{
+   ktap_parser_cancel();
+   break;
+   }
+
if (igt_kernel_tainted(&taints)) {
ktap_parser_cancel();
+   pthread_cancel(modprobe_thread);
break;
}
 
@@ -806,14 +831,20 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
igt_dynamic(result->test_name) {
igt_assert(READ_ONCE(result->passed));
 
+   if (!pthread_tryjoin_np(modprobe_thread, NULL))
+   igt_assert_eq(modprobe.err, 0);
+
igt_fail_on(igt_kernel_tainted(&taints));
}
 
free(result);
}
 
+   pthread_join(modprobe_thread, NULL);
+
ret = ktap_parser_stop();
 
+   igt_skip_on(modprobe.err);
igt_skip_on(igt_kernel_tainted(&taints));
igt_skip_on_f(ret, "KTAP parser failed\n");
 }
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t v3 13/17] lib/ktap: Reimplement KTAP parser

2023-09-18 Thread Janusz Krzysztofik
Current implementation of KTAP parser suffers from several issues:
- works only with built-in kunit, can't parse KTAP output if modular,
- in most cases, kernel messages that are not part of KTAP output but
  happen to appear in between break the parser,
- results from parametrized test cases, not preceded with a "1..N" test
  plan, break the parser,
- skips are not supported, reported as success,
- IGT results from all 3 kunit test nesting levels, i.e., from
  parametrized subtests (should those were fixed to work correctly), test
  cases and test suites, are reported individually as if all those items
  were executed sequentially, all at the same level of nesting, which can
  be confusing to igt_runner,
- subtest names mostly consist of kunit suite name and kunit test case
  name but not always, sometimes the first component is omited,
- the parser is not only parsing the data, but also handles data input
  from a /dev/kmsg like source, which is integrated into it, making it
  hard if not impossible to feed KTAP data from different sources,
  including mock sources,
- since the parser has been designed for running it in a separate thread,
  it's not possible to use igt_skip() nor igt_fail() and friends
  immediately when a result is available, only pass it to the main thread
  over a buffer.  As a consequence, it is virtually impossible to
  synchronize IGT output with KTAP output.

Fixing the existing parser occurred more complicated than re-implementing
it from scratch.  This patch provides a new implementation.

Only results from kunit test cases are reported as results of IGT dynamic
sub-subtests.  Results from individual parametrized subtests have been
considered problematic since many of them provide multi-word descriptions
in place of single-word subtest names.  If a parametrized test case fails
then full KTAP output from its subtests, potentially mixed with
accompanying kernel messages, is available in dmesg for analysis so users
can still find out which individual subtests succeeded and which failed.

Results from test suites level are also omitted in faith that IGT can
handle aggregation of results from individual kunit test cases reported as
IGT dynamic sub-subtests and report those aggregated results correctly as
results from an IGT dynamic subtest.  That 1:1 mapping of kunit test
suites to IGT dynamic subtests now works perfectly for modules that
provide only one test suite, which is the case for all kunit test modules
now existing under drivers/gpu/drm, and the most common case among all
kunit test modules in the whole kernel tree.

New igt_ktap functions can be called directly from igt_kunit subtest body,
but for this patch, the old igt_ktap_parser() function that runs in a
separate thread has been preserved, only modified to use the new
implementation and translate results from those new functions to legacy
format.  Unlike the former implementation, translation of kunit names to
IGT names is handled outside the parser itself, though for now it is still
performed inside the legacy igt_ktap_parser() function.

For better readability of the patch, no longer used functions have been
left untouched, only tagged with __maybe_unused to shut up compiler
warnings / errors.  Kunit library functions will be modified to use the
new igt_ktap interface, and those old ktap functions removed by follow-
up patches.

A test with example subtests that feed igt_ktap_parse() function with some
example data and verifies correctness of their parsing is also provided.

v2: Fix incorrect and missing includes in the test source file,
  - add license and copyright clauses to the test source file.

Signed-off-by: Janusz Krzysztofik 
Acked-by: Mauro Carvalho Chehab 
---
 lib/igt_ktap.c  | 422 
 lib/igt_ktap.h  |  15 ++
 lib/tests/igt_ktap_parser.c | 246 +
 lib/tests/meson.build   |   1 +
 4 files changed, 645 insertions(+), 39 deletions(-)
 create mode 100644 lib/tests/igt_ktap_parser.c

diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index c64323d9b4..5eac102417 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: MIT
 /*
  * Copyright © 2023 Isabella Basso do Amaral 
+ * Copyright © 2023 Intel Corporation
  */
 
 #include 
@@ -8,12 +9,310 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
 #include "igt_aux.h"
 #include "igt_core.h"
 #include "igt_ktap.h"
 #include "igt_list.h"
 
+enum ktap_phase {
+   KTAP_START,
+   SUITE_COUNT,
+   SUITE_START,
+   SUITE_NAME,
+   CASE_COUNT,
+   CASE_NAME,
+   SUB_RESULT,
+   CASE_RESULT,
+   SUITE_RESULT,
+};
+
+struct igt_ktap_results {
+   enum ktap_phase expect;
+   unsigned int suite_count;
+   unsigned int suite_last;
+   char *suite_name;
+   unsigned int case_count;
+   unsigned int case_

[Intel-gfx] [PATCH i-g-t v3 12/17] lib/ktap: Use IGT linked lists for storing KTAP results

2023-09-18 Thread Janusz Krzysztofik
For code simplicity and clarity, use existing IGT linked lists library
instead of open coding a custom implementation of a list of KTAP results.

While being at it, flatten the code by inverting a check for pending
results.

Signed-off-by: Janusz Krzysztofik 
Acked-by: Mauro Carvalho Chehab 
---
 lib/igt_kmod.c | 28 
 lib/igt_ktap.c | 25 +
 lib/igt_ktap.h |  6 --
 3 files changed, 25 insertions(+), 34 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 77fc971f8f..2941524bb4 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -760,7 +760,6 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
struct kmod_module *kunit_kmod;
bool is_builtin;
struct ktap_test_results *results;
-   struct ktap_test_results_element *temp;
unsigned long taints;
int flags, ret;
 
@@ -784,28 +783,33 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
igt_skip("Unable to load %s module\n", tst->module_name);
}
 
-   while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != 
NULL)
+   while (READ_ONCE(results->still_running) || 
!igt_list_empty(&results->list))
{
+   struct ktap_test_results_element *result;
+
if (igt_kernel_tainted(&taints)) {
ktap_parser_cancel();
break;
}
 
-   if (READ_ONCE(results->head) != NULL) {
-   pthread_mutex_lock(&results->mutex);
+   pthread_mutex_lock(&results->mutex);
+   if (igt_list_empty(&results->list)) {
+   pthread_mutex_unlock(&results->mutex);
+   continue;
+   }
 
-   igt_dynamic(results->head->test_name) {
-   igt_assert(READ_ONCE(results->head->passed));
+   result = igt_list_first_entry(&results->list, result, link);
 
-   igt_fail_on(igt_kernel_tainted(&taints));
-   }
+   igt_list_del(&result->link);
+   pthread_mutex_unlock(&results->mutex);
 
-   temp = results->head;
-   results->head = results->head->next;
-   free(temp);
+   igt_dynamic(result->test_name) {
+   igt_assert(READ_ONCE(result->passed));
 
-   pthread_mutex_unlock(&results->mutex);
+   igt_fail_on(igt_kernel_tainted(&taints));
}
+
+   free(result);
}
 
ret = ktap_parser_stop();
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 282e44176e..c64323d9b4 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -12,6 +12,7 @@
 #include "igt_aux.h"
 #include "igt_core.h"
 #include "igt_ktap.h"
+#include "igt_list.h"
 
 #define DELIMITER "-"
 
@@ -335,7 +336,7 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
   bool *found_tests, bool is_builtin)
 {
char record[BUF_LEN + 1];
-   struct ktap_test_results_element *r, *temp;
+   struct ktap_test_results_element *r;
int internal_test_count;
char test_name[BUF_LEN + 1];
char base_test_name_for_next_level[BUF_LEN + 1];
@@ -403,17 +404,9 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
r->test_name[BUF_LEN] = '\0';
 
r->passed = false;
-   r->next = NULL;
 
pthread_mutex_lock(&results.mutex);
-   if (results.head == NULL) {
-   results.head = r;
-   } else {
-   temp = results.head;
-   while (temp->next != NULL)
-   temp = temp->next;
-   temp->next = r;
-   }
+   igt_list_add_tail(&r->link, &results.list);
pthread_mutex_unlock(&results.mutex);
 
test_name[0] = '\0';
@@ -431,17 +424,9 @@ static int parse_tap_level(int fd, char *base_test_name, 
int test_count, bool *f
r->test_name[BUF_LEN] = '\0';
 
r->passed = true;
-   r->next = NULL;
 
pthread_mutex_lock(&results.mutex);
-   if (results.head == NULL) {
-   results.head = r;
-   } else {
-   tem

[Intel-gfx] [PATCH i-g-t v3 15/17] lib/kunit: Parse KTAP report from the main process thread

2023-09-18 Thread Janusz Krzysztofik
There was an attempt to parse KTAP reports in the background while a kunit
test module is loading.  However, since dynamic sub-subtests can be
executed only from the main thread, that attempt was not quite successful,
as IGT results from all executed kunit test cases were generated only
after loading of kunit test module completed.

Now that the parser maintains its state and we can call it separately for
each input line of a KTAP report, it is perfectly possible to call the
parser from the main thread while the module is loading in the background,
and convert results from kunit test cases immediately to results of IGT
dynamic sub-subtests by running an igt_dynamic() section for each result
as soon as returned by the parser.

Drop igt_ktap_parser() thread and execute igt_dynamic() for each kunit
result obtained from igt_ktap_parse() called from the main thread.

Also, drop no longer needed functions from igt_ktap soruces.

v2: Interrupt blocking read() on modprobe failure.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 208 ++
 lib/igt_ktap.c | 568 -
 lib/igt_ktap.h |  22 --
 3 files changed, 166 insertions(+), 632 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 8fbd274ccf..7fa5b4aa80 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2016 Intel Corporation
+ * Copyright © 2016-2023 Intel Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -26,7 +26,10 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
+#include 
 
 #include "igt_aux.h"
 #include "igt_core.h"
@@ -748,20 +751,109 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
 }
 
 struct modprobe_data {
+   pthread_t parent;
struct kmod_module *kmod;
const char *opts;
int err;
+   pthread_mutex_t lock;
+   pthread_t thread;
 };
 
 static void *modprobe_task(void *arg)
 {
struct modprobe_data *data = arg;
+   int err;
+
+   err = modprobe(data->kmod, data->opts);
 
-   data->err = modprobe(data->kmod, data->opts);
+   if (err) {
+   while (pthread_mutex_trylock(&data->lock) == EBUSY)
+   pthread_kill(data->parent, SIGCHLD);
+
+   data->err = err;
+   pthread_mutex_unlock(&data->lock);
+   }
 
return NULL;
 }
 
+static void kunit_sigchld_handler(int signal)
+{
+   return;
+}
+
+static int kunit_kmsg_result_get(struct igt_list_head *results,
+struct modprobe_data *modprobe,
+int fd, struct igt_ktap_results *ktap)
+{
+   struct sigaction sigchld = { .sa_handler = kunit_sigchld_handler, };
+   char record[BUF_LEN + 1], *buf;
+   unsigned long taints;
+   int ret;
+
+   do {
+   if (igt_kernel_tainted(&taints))
+   return -ENOTRECOVERABLE;
+
+   pthread_mutex_lock(&modprobe->lock);
+   if (!pthread_tryjoin_np(modprobe->thread, NULL) &&
+   modprobe->err) {
+   pthread_mutex_unlock(&modprobe->lock);
+   return modprobe->err;
+   }
+
+   sigaction(SIGCHLD, &sigchld, NULL);
+   ret = read(fd, record, BUF_LEN);
+   sigaction(SIGCHLD, NULL, NULL);
+   pthread_mutex_unlock(&modprobe->lock);
+
+   if (!ret)
+   return -ENODATA;
+   if (ret == -1)
+   return -errno;
+
+   igt_assert_lt(0, ret);
+
+   /* skip kmsg continuation lines */
+   if (igt_debug_on(*record == ' '))
+   continue;
+
+   /* NULL-terminate the record */
+   record[ret] = '\0';
+
+   /* detect start of log message, continue if not found */
+   buf = strchrnul(record, ';');
+   if (igt_debug_on(*buf == '\0'))
+   continue;
+   buf++;
+
+   ret = igt_ktap_parse(buf, ktap);
+   if (ret != -EINPROGRESS)
+   break;
+   } while (igt_list_empty(results));
+
+   return ret;
+}
+
+static void kunit_result_free(struct igt_ktap_result *r,
+ char **suite_name, char **case_name)
+{
+   igt_list_del(&r->link);
+
+   if (r->suite_name != *suite_name) {
+   free(*suite_name);
+   *suite_name = r->suite_name;
+   }
+
+   if (r->case_name != *case_name) {
+   free(*case_name);
+   *case_name = r->case_name;
+   }
+
+   free(r->msg);
+ 

[Intel-gfx] [PATCH i-g-t v3 16/17] lib/kunit: Strip "_test" or "_kunit" suffix from subtest names

2023-09-18 Thread Janusz Krzysztofik
If a user (an IGT test) doesn't provide a subtest name when calling
igt_kunit() then we now use the requested kernel module name as IGT
subtest name.  Since names of kunit test modules usually end with a
"_test" or "_kunit" suffix, those parts of the names don't carry any
useful information.  Strip those suffixes from IGT subtest names.

Signed-off-by: Janusz Krzysztofik 
Reviewed-by: Mauro Carvalho Chehab 
---
 lib/igt_kmod.c | 23 ---
 tests/drm_mm.c | 42 +-
 2 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 7fa5b4aa80..f6e0ab07ce 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -978,7 +978,27 @@ void igt_kunit(const char *module_name, const char *name, 
const char *opts)
struct igt_ktest tst = { .kmsg = -1, };
 
 
+   /*
+* If the caller (an IGT test) provides no subtest name then we
+* take the module name, drop the trailing "_test" or "_kunit"
+* suffix, if any, and use the result as our IGT subtest name.
+*/
+   if (!name) {
+   name = strdup(module_name);
+   if (name) {
+   char *suffix = strstr(name, "_test");
+
+   if (!suffix)
+   suffix = strstr(name, "_kunit");
+
+   if (suffix)
+   *suffix = '\0';
+   }
+   }
+
igt_fixture {
+   igt_require(name);
+
igt_skip_on(igt_ktest_init(&tst, module_name));
igt_skip_on(igt_ktest_begin(&tst));
}
@@ -990,9 +1010,6 @@ void igt_kunit(const char *module_name, const char *name, 
const char *opts)
 * proper namespace for dynamic subtests, with is required for CI
 * and for documentation.
 */
-   if (name == NULL)
-   name = module_name;
-
igt_subtest_with_dynamic(name)
__igt_kunit(&tst, opts);
 
diff --git a/tests/drm_mm.c b/tests/drm_mm.c
index 9a8b3f3fcb..e6ba224745 100644
--- a/tests/drm_mm.c
+++ b/tests/drm_mm.c
@@ -29,123 +29,123 @@
  * Feature: mapping
  * Run type: FULL
  *
- * SUBTEST: drm_mm_test
+ * SUBTEST: drm_mm
  *
- * SUBTEST: drm_mm_test@align
+ * SUBTEST: drm_mm@align
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@align32
+ * SUBTEST: drm_mm@align32
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@align64
+ * SUBTEST: drm_mm@align64
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@bottomup
+ * SUBTEST: drm_mm@bottomup
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@color
+ * SUBTEST: drm_mm@color
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@color_evict
+ * SUBTEST: drm_mm@color_evict
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@color_evict_range
+ * SUBTEST: drm_mm@color_evict_range
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@debug
+ * SUBTEST: drm_mm@debug
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@evict
+ * SUBTEST: drm_mm@evict
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@evict_range
+ * SUBTEST: drm_mm@evict_range
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@frag
+ * SUBTEST: drm_mm@frag
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@highest
+ * SUBTEST: drm_mm@highest
  * Category: Infrastructure
  * Description: drm_mm range manager SW validation
  * Functionality: DRM memory mangemnt
  * Test category: GEM_Legacy
  *
- * SUBTEST: drm_mm_test@init
+ * SUBTEST: drm_mm@init
  * Ca

[Intel-gfx] [PATCH i-g-t v3 17/17] lib/kunit: Omit suite name prefix if the same as subtest name

2023-09-18 Thread Janusz Krzysztofik
Kunit test modules usually contain one test suite, named after the module
name with the trailing "_test" or "_kunit" suffix omitted.  Since we
follow the same convention when we derive subtest names from module names,
there is a great chance that those two names match.  Take this into
account when composing names for IGT dynamic sub-subtest names and drop
the leading test suite name component when it is the same as subtest name.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index f6e0ab07ce..05c837031c 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -863,7 +863,8 @@ static void kunit_result_free(struct igt_ktap_result *r,
  *
  * Returns: IGT default codes
  */
-static void __igt_kunit(struct igt_ktest *tst, const char *opts)
+static void
+__igt_kunit(struct igt_ktest *tst, const char *name, const char *opts)
 {
struct modprobe_data modprobe = { pthread_self(), tst->kmod, opts, 0,
  PTHREAD_MUTEX_INITIALIZER, };
@@ -902,7 +903,11 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
r = igt_list_first_entry(&results, r, link);
 
-   igt_dynamic_f("%s-%s", r->suite_name, r->case_name) {
+   igt_dynamic_f("%s%s%s",
+ strcmp(r->suite_name, name) ?  r->suite_name : "",
+ strcmp(r->suite_name, name) ? "-" : "",
+ r->case_name) {
+
if (r->code == IGT_EXIT_INVALID) {
/* parametrized test case, get actual result */
kunit_result_free(r, &suite_name, &case_name);
@@ -1011,7 +1016,7 @@ void igt_kunit(const char *module_name, const char *name, 
const char *opts)
 * and for documentation.
 */
igt_subtest_with_dynamic(name)
-   __igt_kunit(&tst, opts);
+   __igt_kunit(&tst, name, opts);
 
igt_fixture
igt_ktest_end(&tst);
-- 
2.41.0



[Intel-gfx] [PATCH i-g-t 0/9] Kunit fixes and improvements

2023-10-03 Thread Janusz Krzysztofik
Janusz Krzysztofik (9):
  lib/kunit: Fix handling of potential errors from F_GETFL
  lib/kunit: Be more verbose on errors
  lib/kunit: Fix misplaced igt_kunit() doc
  lib/kunit: Parse KTAP report from the main process thread
  lib/kunit: Omit suite name prefix if the same as subtest name
  tests/kms_selftest: Let subtest names match suite names
  lib/ktap: Drop workaround for missing top level KTAP headers
  lib/kunit: Fetch a list of test cases in advance
  lib/kunit: Execute kunit test cases only when needed

 lib/igt_kmod.c  | 413 +
 lib/igt_ktap.c  | 580 
 lib/igt_ktap.h  |  22 --
 lib/tests/igt_ktap_parser.c |   3 +-
 tests/kms_selftest.c|  37 +--
 5 files changed, 369 insertions(+), 686 deletions(-)

-- 
2.42.0



[Intel-gfx] [PATCH i-g-t 1/9] lib/kunit: Fix handling of potential errors from F_GETFL

2023-10-03 Thread Janusz Krzysztofik
Function fcntl(..., F_GETFL, ...) that returns file status flags may also
return a negative error code.  Handle that error instead of blindly using
the returned value as flags.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index d98e6c5f9e..05ff178b27 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -783,8 +783,8 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
 
igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n");
 
-   flags = fcntl(tst->kmsg, F_GETFL, 0) & ~O_NONBLOCK;
-   igt_skip_on_f(fcntl(tst->kmsg, F_SETFL, flags) == -1,
+   igt_skip_on((flags = fcntl(tst->kmsg, F_GETFL, 0), flags < 0));
+   igt_skip_on_f(fcntl(tst->kmsg, F_SETFL, flags & ~O_NONBLOCK) == -1,
  "Could not set /dev/kmsg to blocking mode\n");
 
igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0);
-- 
2.42.0



[Intel-gfx] [PATCH i-g-t 2/9] lib/kunit: Be more verbose on errors

2023-10-03 Thread Janusz Krzysztofik
Use a more verbose variant of igt_fail() when failing a dynamic sub-
subtest on kernel taint.  Also, print a debug message on string
duplication failure.

Signed-off-by: Janusz Krzysztofik 
---
 lib/igt_kmod.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 05ff178b27..df0e650d49 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -834,7 +834,7 @@ static void __igt_kunit(struct igt_ktest *tst, const char 
*opts)
if (!pthread_tryjoin_np(modprobe_thread, NULL))
igt_assert_eq(modprobe.err, 0);
 
-   igt_fail_on(igt_kernel_tainted(&taints));
+   igt_assert_eq(igt_kernel_tainted(&taints), 0);
}
 
free(result);
@@ -861,7 +861,7 @@ void igt_kunit(const char *module_name, const char *name, 
const char *opts)
 */
if (!name) {
name = strdup(module_name);
-   if (name) {
+   if (!igt_debug_on(!name)) {
char *suffix = strstr(name, "_test");
 
if (!suffix)
-- 
2.42.0



  1   2   3   4   5   6   7   8   9   >