All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs
@ 2016-07-10 13:41 akash.goel
  2016-07-10 13:41 ` [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter akash.goel
                   ` (17 more replies)
  0 siblings, 18 replies; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Akash Goel <akash.goel@intel.com>

GuC firmware log its debug messages into a Host-GuC shared memory buffer
and when the buffer is half full it sends a Flush interrupt to Host.
GuC firmware follows the half-full draining protocol where it expects that
while it is writing to 2nd half of the buffer, first half would get consumed
by Host and then get a flush completed acknowledgement from Host, so that it
does not end up doing any overwrite causing loss of logs.
So far flush interrupt wasn't enabled on Host side & User could capture the
contents/snapshot of log buffer through 'i915_guc_log_dump' debugfs iface.
But this couldn't meet couple of key requirements, especially of Validation,
first is to ensure capturing of all boot time logs even with high verbosity
level and second is to enable capturing of logs in a sustained manner like
for the entire duration of a workload.
Now Driver will enable flush interrupt and on receving it, would copy the
contents of log buffer into its local buffer. The size of local buffer would
be big enough to contain multiple snapshots of the log buffer giving ample
time to User to pull boot time messages.
Have added a debugfs interface '/sys/kernel/debug/dri/guc_log' for User to
collect the logs. Availed relay framework to implement this interface, where
Driver will have to just use a relay API to store snapshots of GuC log buffer
in a buffer managed by relay. The relay buffer will be operated in a mode
where the old data, not yet collected by User, will be overwritten if buffer
becomes full. So the behavior exhibited will be equivalent to 'dmesg -c'.
Besides mmap method, through which User can directly access the relay
buffer contents, relay also supports the 'poll' method. Through the 'poll'
call on log file, User can come to know whenever a new snapshot of the log
buffer is taken by Driver, so can run in tandem with the Driver and thus
capture logs in a sustained/streaming manner, without any loss of data.

v2: Rebased to the latest drm-intel-nightly.

v3: Aligned with the modification of late debugfs registration, at the end of
    i915 Driver load. Did cleanup as per Tvrtko's review comments, added 3
    new patches to optimize the log-buffer flush interrupt handling, gather
    and report the logging related stats.

v4: Added 2 new patches to further optimize the log-buffer flush interrupt
    handling. Did cleanup as per Chris's review comments, fixed couple of
    issues related to clearing of Guc2Host message register. Switched to
    no-overwrite mode for the relay.

Akash Goel (10):
  drm/i915: New structure to contain GuC logging related fields
  drm/i915: Add low level set of routines for programming PM IER/IIR/IMR
    register set
  drm/i915: Add a relay backed debugfs interface for capturing GuC logs
  drm/i915: New module param to control the size of buffer used for
    storing GuC firmware logs
  drm/i915: Use uncached(WC) mapping for acessing the GuC log buffer
  drm/i915: New lock to serialize the Host2GuC actions
  drm/i915: Add stats for GuC log buffer flush interrupts
  drm/i915: Increase GuC log buffer size to reduce flush interrupts
  drm/i915: Optimization to reduce the sampling time of GuC log buffer
  drm/i915: Use rt priority kthread to do GuC log buffer sampling

Chris Wilson (1):
  drm/i915: Support to create write combined type vmaps

Sagar Arun Kamble (6):
  drm/i915: Decouple GuC log setup from verbosity parameter
  drm/i915: Add GuC ukernel logging related fields to fw interface file
  drm/i915: Support for GuC interrupts
  drm/i915: Handle log buffer flush interrupt event from GuC
  drm/i915: Forcefully flush GuC log buffer on reset
  drm/i915: Debugfs support for GuC logging control

 drivers/gpu/drm/i915/i915_debugfs.c        |  60 +++-
 drivers/gpu/drm/i915/i915_drv.c            |   2 +
 drivers/gpu/drm/i915/i915_drv.h            |   8 +-
 drivers/gpu/drm/i915/i915_gem.c            |  57 ++-
 drivers/gpu/drm/i915/i915_gem_dmabuf.c     |   2 +-
 drivers/gpu/drm/i915/i915_guc_submission.c | 554 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/i915_irq.c            | 159 +++++++--
 drivers/gpu/drm/i915/i915_params.c         |   5 +
 drivers/gpu/drm/i915/i915_params.h         |   1 +
 drivers/gpu/drm/i915/i915_reg.h            |  11 +
 drivers/gpu/drm/i915/intel_drv.h           |   6 +
 drivers/gpu/drm/i915/intel_guc.h           |  30 +-
 drivers/gpu/drm/i915/intel_guc_fwif.h      |  82 ++++-
 drivers/gpu/drm/i915/intel_guc_loader.c    |  12 +-
 drivers/gpu/drm/i915/intel_lrc.c           |   8 +-
 drivers/gpu/drm/i915/intel_ringbuffer.c    |   6 +-
 16 files changed, 934 insertions(+), 69 deletions(-)

-- 
1.9.2

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-11  9:37   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 02/17] drm/i915: Add GuC ukernel logging related fields to fw interface file akash.goel
                   ` (16 subsequent siblings)
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Sagar Arun Kamble <sagar.a.kamble@intel.com>

GuC Log buffer allocation was tied up with verbosity level module param
i915.guc_log_level. User would be given a provision to enable firmware
logging at runtime, through a host2guc action, and not necessarily during
Driver load time. But the address of log buffer can be passed only in
init params, at firmware load time, so GuC has to be reset and firmware
needs to be reloaded to pass the log buffer address at runtime.
To avoid reset of GuC & reload of firmware, allocation of log buffer will
be done always but logging would be enabled initially on GuC side based on
the value of module paramter guc_log_level.

v2: Update commit message to describe the constraint with allocation of
    log buffer at runtime. (Tvrtko)

Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 3 ---
 drivers/gpu/drm/i915/intel_guc_loader.c    | 8 +++++---
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 2112e02..8a9a0cb 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -832,9 +832,6 @@ static void guc_create_log(struct intel_guc *guc)
 	unsigned long offset;
 	uint32_t size, flags;
 
-	if (i915.guc_log_level < GUC_LOG_VERBOSITY_MIN)
-		return;
-
 	if (i915.guc_log_level > GUC_LOG_VERBOSITY_MAX)
 		i915.guc_log_level = GUC_LOG_VERBOSITY_MAX;
 
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 605c696..b211bd0 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -175,11 +175,13 @@ static void set_guc_init_params(struct drm_i915_private *dev_priv)
 	params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
 			GUC_CTL_VCS2_ENABLED;
 
-	if (i915.guc_log_level >= 0) {
-		params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
+	params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
+
+	if (i915.guc_log_level >= 0)
 		params[GUC_CTL_DEBUG] =
 			i915.guc_log_level << GUC_LOG_VERBOSITY_SHIFT;
-	}
+	else
+		params[GUC_CTL_DEBUG] = GUC_LOG_DISABLED;
 
 	if (guc->ads_obj) {
 		u32 ads = (u32)i915_gem_obj_ggtt_offset(guc->ads_obj)
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 02/17] drm/i915: Add GuC ukernel logging related fields to fw interface file
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
  2016-07-10 13:41 ` [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-10 13:41 ` [PATCH 03/17] drm/i915: New structure to contain GuC logging related fields akash.goel
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Sagar Arun Kamble <sagar.a.kamble@intel.com>

The first page of the GuC log buffer contains state info or meta data
which is required to parse the logs contained in the subsequent pages.
The structure representing the state info is added to interface file
as Driver would need to handle log buffer flush interrupts from GuC.
Added an enum for the different message/event types that can be send
by the GuC ukernel to Host.
Also added 2 new Host to GuC action types to inform GuC when Host has
flushed the log buffer and forcefuly cause the GuC to send a new
log buffer flush interrupt.

v2: Make documentation of log buffer state structure more elaborate. (Tvrtko)
    Rename LOGBUFFERFLUSH action to LOG_BUFFER_FLUSH for consistency. (Tvrtko)

v3: Add GuC log buffer layout diagram for more clarity.

Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Akash Goel <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/intel_guc_fwif.h | 78 +++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
index 944786d..1de6928 100644
--- a/drivers/gpu/drm/i915/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
@@ -418,15 +418,87 @@ struct guc_ads {
 	u32 reserved2[4];
 } __packed;
 
+/* GuC logging structures */
+
+enum guc_log_buffer_type {
+	GUC_ISR_LOG_BUFFER,
+	GUC_DPC_LOG_BUFFER,
+	GUC_CRASH_DUMP_LOG_BUFFER,
+	GUC_MAX_LOG_BUFFER
+};
+
+/**
+ * DOC: GuC Log buffer Layout
+ *
+ * Page0  +-------------------------------+
+ *        |   ISR state header (32 bytes) |
+ *        |      DPC state header         |
+ *        |   Crash dump state header     |
+ * Page1  +-------------------------------+
+ *        |           ISR logs            |
+ * Page5  +-------------------------------+
+ *        |           DPC logs            |
+ * Page9  +-------------------------------+
+ *        |         Crash Dump logs       |
+ *        +-------------------------------+
+ *
+ * Below state structure is used for coordination of retrieval of GuC firmware
+ * logs. Separate state is maintained for each log buffer type.
+ * read_ptr points to the location where i915 read last in log buffer and
+ * is read only for GuC firmware. write_ptr is incremented by GuC with number
+ * of bytes written for each log entry and is read only for i915.
+ * When any type of log buffer becomes half full, GuC sends a flush interrupt.
+ * GuC firmware expects that while it is writing to 2nd half of the buffer,
+ * first half would get consumed by Host and then get a flush completed
+ * acknowledgement from Host, so that it does not end up doing any overwrite
+ * causing loss of logs. So when buffer gets half filled & i915 has requested
+ * for interrupt, GuC will set flush_to_file field, set the sampled_write_ptr
+ * to the value of write_ptr and raise the interrupt.
+ * On receving the interrupt i915 should read the buffer, clear flush_to_file
+ * field and also update read_ptr with the value of sample_write_ptr, before
+ * sending an acknowledgement to GuC. marker & version fields are for internal
+ * usage of GuC and opaque to i915. buffer_full_cnt field is incremented every
+ * time GuC detects the log buffer overflow.
+ */
+struct guc_log_buffer_state {
+	u32 marker[2];
+	u32 read_ptr;
+	u32 write_ptr;
+	u32 size;
+	u32 sampled_write_ptr;
+	union {
+		struct {
+			u32 flush_to_file:1;
+			u32 buffer_full_cnt:4;
+			u32 reserved:27;
+		};
+		u32 flags;
+	};
+	u32 version;
+} __packed;
+
+union guc_log_control {
+	struct {
+		u32 logging_enabled:1;
+		u32 reserved1:3;
+		u32 verbosity:4;
+		u32 reserved2:24;
+	};
+	u32 value;
+} __packed;
+
 /* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */
 enum host2guc_action {
 	HOST2GUC_ACTION_DEFAULT = 0x0,
 	HOST2GUC_ACTION_SAMPLE_FORCEWAKE = 0x6,
 	HOST2GUC_ACTION_ALLOCATE_DOORBELL = 0x10,
 	HOST2GUC_ACTION_DEALLOCATE_DOORBELL = 0x20,
+	HOST2GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE = 0x30,
+	HOST2GUC_ACTION_FORCE_LOG_BUFFER_FLUSH = 0x302,
 	HOST2GUC_ACTION_ENTER_S_STATE = 0x501,
 	HOST2GUC_ACTION_EXIT_S_STATE = 0x502,
 	HOST2GUC_ACTION_SLPC_REQUEST = 0x3003,
+	HOST2GUC_ACTION_UK_LOG_ENABLE_LOGGING = 0x0E000,
 	HOST2GUC_ACTION_LIMIT
 };
 
@@ -448,4 +520,10 @@ enum guc2host_status {
 	GUC2HOST_STATUS_GENERIC_FAIL = GUC2HOST_STATUS(0x0000F000)
 };
 
+/* This action will be programmed in C1BC - SOFT_SCRATCH_15_REG */
+enum guc2host_message {
+	GUC2HOST_MSG_CRASH_DUMP_POSTED = (1 << 1),
+	GUC2HOST_MSG_FLUSH_LOG_BUFFER = (1 << 3)
+};
+
 #endif
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 03/17] drm/i915: New structure to contain GuC logging related fields
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
  2016-07-10 13:41 ` [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter akash.goel
  2016-07-10 13:41 ` [PATCH 02/17] drm/i915: Add GuC ukernel logging related fields to fw interface file akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-10 13:41 ` [PATCH 04/17] drm/i915: Add low level set of routines for programming PM IER/IIR/IMR register set akash.goel
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Akash Goel <akash.goel@intel.com>

So far there were 2 fields related to GuC logs in 'intel_guc' structure.
For the support of capturing GuC logs & storing them in a local buffer,
multiple new fields would have to be added. This warrants a separate
structure to contain the fields related to GuC logging state.
Added a new structure 'intel_guc_log' and instance of it inside
'intel_guc' structure.

Signed-off-by: Akash Goel <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c        |  2 +-
 drivers/gpu/drm/i915/i915_guc_submission.c | 10 +++++-----
 drivers/gpu/drm/i915/intel_guc.h           |  8 ++++++--
 drivers/gpu/drm/i915/intel_guc_loader.c    |  2 +-
 4 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 844fea7..5e35565 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2621,7 +2621,7 @@ static int i915_guc_log_dump(struct seq_file *m, void *data)
 	struct drm_info_node *node = m->private;
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
-	struct drm_i915_gem_object *log_obj = dev_priv->guc.log_obj;
+	struct drm_i915_gem_object *log_obj = dev_priv->guc.log.obj;
 	u32 *log;
 	int i = 0, pg;
 
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 8a9a0cb..0fb00ab 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -841,7 +841,7 @@ static void guc_create_log(struct intel_guc *guc)
 		GUC_LOG_ISR_PAGES + 1 +
 		GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT;
 
-	obj = guc->log_obj;
+	obj = guc->log.obj;
 	if (!obj) {
 		obj = gem_allocate_guc_obj(dev_priv, size);
 		if (!obj) {
@@ -850,7 +850,7 @@ static void guc_create_log(struct intel_guc *guc)
 			return;
 		}
 
-		guc->log_obj = obj;
+		guc->log.obj = obj;
 	}
 
 	/* each allocated unit is a page */
@@ -860,7 +860,7 @@ static void guc_create_log(struct intel_guc *guc)
 		(GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT);
 
 	offset = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; /* in pages */
-	guc->log_flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
+	guc->log.flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
 }
 
 static void init_guc_policies(struct guc_policies *policies)
@@ -1021,8 +1021,8 @@ void i915_guc_submission_fini(struct drm_i915_private *dev_priv)
 	gem_release_guc_obj(dev_priv->guc.ads_obj);
 	guc->ads_obj = NULL;
 
-	gem_release_guc_obj(dev_priv->guc.log_obj);
-	guc->log_obj = NULL;
+	gem_release_guc_obj(dev_priv->guc.log.obj);
+	guc->log.obj = NULL;
 
 	if (guc->ctx_pool_obj)
 		ida_destroy(&guc->ctx_ids);
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 3e3e743..d52eca3 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -122,10 +122,14 @@ struct intel_guc_fw {
 	uint32_t ucode_offset;
 };
 
+struct intel_guc_log {
+	uint32_t flags;
+	struct drm_i915_gem_object *obj;
+};
+
 struct intel_guc {
 	struct intel_guc_fw guc_fw;
-	uint32_t log_flags;
-	struct drm_i915_gem_object *log_obj;
+	struct intel_guc_log log;
 
 	struct drm_i915_gem_object *ads_obj;
 
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index b211bd0..4882f17 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -175,7 +175,7 @@ static void set_guc_init_params(struct drm_i915_private *dev_priv)
 	params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
 			GUC_CTL_VCS2_ENABLED;
 
-	params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
+	params[GUC_CTL_LOG_PARAMS] = guc->log.flags;
 
 	if (i915.guc_log_level >= 0)
 		params[GUC_CTL_DEBUG] =
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 04/17] drm/i915: Add low level set of routines for programming PM IER/IIR/IMR register set
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (2 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 03/17] drm/i915: New structure to contain GuC logging related fields akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-11 10:04   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 05/17] drm/i915: Support for GuC interrupts akash.goel
                   ` (13 subsequent siblings)
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Akash Goel <akash.goel@intel.com>

So far PM IER/IIR/IMR registers were being used only for Turbo related
interrupts. But interrupts coming from GuC also use the same set.
As a precursor to supporting GuC interrupts, added new low level routines
so as to allow sharing the programming of PM IER/IIR/IMR registers between
Turbo & GuC.
Also similar to PM IMR, maintaining a bitmask for PM IER register, to allow
easy sharing of it between Turbo & GuC without involving a rmw operation.

v2:
- For appropriateness & avoid any ambiguity, rename old functions
  enable/disable pm_irq to mask/unmask pm_irq and rename new functions
  enable/disable pm_interrupts to enable/disable pm_irq. (Tvrtko)
- Use u32 in place of uint32_t. (Tvrtko)

v3:
- Rename the fields pm_irq_mask & pm_ier_mask and do some cleanup. (Chris)
- Rebase.

Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h         |  3 +-
 drivers/gpu/drm/i915/i915_irq.c         | 71 ++++++++++++++++++++++-----------
 drivers/gpu/drm/i915/intel_drv.h        |  3 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c |  4 +-
 4 files changed, 54 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 4478cc8..c3a579f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1791,7 +1791,8 @@ struct drm_i915_private {
 		u32 de_irq_mask[I915_MAX_PIPES];
 	};
 	u32 gt_irq_mask;
-	u32 pm_irq_mask;
+	u32 pm_imr;
+	u32 pm_ier;
 	u32 pm_rps_events;
 	u32 pipestat_irq_mask[I915_MAX_PIPES];
 
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 1c2aec3..24bbaf7 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -303,18 +303,18 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
 
 	assert_spin_locked(&dev_priv->irq_lock);
 
-	new_val = dev_priv->pm_irq_mask;
+	new_val = dev_priv->pm_imr;
 	new_val &= ~interrupt_mask;
 	new_val |= (~enabled_irq_mask & interrupt_mask);
 
-	if (new_val != dev_priv->pm_irq_mask) {
-		dev_priv->pm_irq_mask = new_val;
-		I915_WRITE(gen6_pm_imr(dev_priv), dev_priv->pm_irq_mask);
+	if (new_val != dev_priv->pm_imr) {
+		dev_priv->pm_imr = new_val;
+		I915_WRITE(gen6_pm_imr(dev_priv), dev_priv->pm_imr);
 		POSTING_READ(gen6_pm_imr(dev_priv));
 	}
 }
 
-void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
+void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
 		return;
@@ -322,28 +322,54 @@ void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
 	snb_update_pm_irq(dev_priv, mask, mask);
 }
 
-static void __gen6_disable_pm_irq(struct drm_i915_private *dev_priv,
-				  uint32_t mask)
+static void __gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
 	snb_update_pm_irq(dev_priv, mask, 0);
 }
 
-void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
+void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
 		return;
 
-	__gen6_disable_pm_irq(dev_priv, mask);
+	__gen6_mask_pm_irq(dev_priv, mask);
 }
 
-void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv)
+void gen6_reset_pm_iir(struct drm_i915_private *dev_priv, u32 reset_mask)
 {
 	i915_reg_t reg = gen6_pm_iir(dev_priv);
 
-	spin_lock_irq(&dev_priv->irq_lock);
-	I915_WRITE(reg, dev_priv->pm_rps_events);
-	I915_WRITE(reg, dev_priv->pm_rps_events);
+	assert_spin_locked(&dev_priv->irq_lock);
+
+	I915_WRITE(reg, reset_mask);
+	I915_WRITE(reg, reset_mask);
 	POSTING_READ(reg);
+}
+
+void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, u32 enable_mask)
+{
+	assert_spin_locked(&dev_priv->irq_lock);
+
+	dev_priv->pm_ier |= enable_mask;
+	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier);
+	gen6_unmask_pm_irq(dev_priv, enable_mask);
+	/* unmask_pm_irq provides an implicit barrier (POSTING_READ) */
+}
+
+void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, u32 disable_mask)
+{
+	assert_spin_locked(&dev_priv->irq_lock);
+
+	dev_priv->pm_ier &= ~disable_mask;
+	__gen6_mask_pm_irq(dev_priv, disable_mask);
+	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier);
+	/* though a barrier is missing here, but don't really need a one */
+}
+
+void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv)
+{
+	spin_lock_irq(&dev_priv->irq_lock);
+	gen6_reset_pm_iir(dev_priv, dev_priv->pm_rps_events);
 	dev_priv->rps.pm_iir = 0;
 	spin_unlock_irq(&dev_priv->irq_lock);
 }
@@ -354,8 +380,6 @@ void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv)
 	WARN_ON_ONCE(dev_priv->rps.pm_iir);
 	WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events);
 	dev_priv->rps.interrupts_enabled = true;
-	I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) |
-				dev_priv->pm_rps_events);
 	gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
 
 	spin_unlock_irq(&dev_priv->irq_lock);
@@ -373,9 +397,7 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
 
 	I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0));
 
-	__gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
-	I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) &
-				~dev_priv->pm_rps_events);
+	gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
 
 	spin_unlock_irq(&dev_priv->irq_lock);
 	synchronize_irq(dev_priv->drm.irq);
@@ -1086,7 +1108,7 @@ static void gen6_pm_rps_work(struct work_struct *work)
 	pm_iir = dev_priv->rps.pm_iir;
 	dev_priv->rps.pm_iir = 0;
 	/* Make sure not to corrupt PMIMR state used by ringbuffer on GEN6 */
-	gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+	gen6_unmask_pm_irq(dev_priv, dev_priv->pm_rps_events);
 	client_boost = dev_priv->rps.client_boost;
 	dev_priv->rps.client_boost = false;
 	spin_unlock_irq(&dev_priv->irq_lock);
@@ -1586,7 +1608,7 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
 {
 	if (pm_iir & dev_priv->pm_rps_events) {
 		spin_lock(&dev_priv->irq_lock);
-		gen6_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
+		gen6_mask_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
 		if (dev_priv->rps.interrupts_enabled) {
 			dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
 			schedule_work(&dev_priv->rps.work);
@@ -3605,8 +3627,8 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
 		if (HAS_VEBOX(dev))
 			pm_irqs |= PM_VEBOX_USER_INTERRUPT;
 
-		dev_priv->pm_irq_mask = 0xffffffff;
-		GEN5_IRQ_INIT(GEN6_PM, dev_priv->pm_irq_mask, pm_irqs);
+		dev_priv->pm_imr = 0xffffffff;
+		GEN5_IRQ_INIT(GEN6_PM, dev_priv->pm_imr, pm_irqs);
 	}
 }
 
@@ -3726,14 +3748,15 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
 	if (HAS_L3_DPF(dev_priv))
 		gt_interrupts[0] |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 
-	dev_priv->pm_irq_mask = 0xffffffff;
+	dev_priv->pm_ier = 0x0;
+	dev_priv->pm_imr = ~dev_priv->pm_ier;
 	GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
 	GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
 	/*
 	 * RPS interrupts will get enabled/disabled on demand when RPS itself
 	 * is enabled/disabled.
 	 */
-	GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, 0);
+	GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier);
 	GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 55aeaf0..ae6c535 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1077,6 +1077,9 @@ void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv);
 /* i915_irq.c */
 void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
+void gen6_reset_pm_iir(struct drm_i915_private *dev_priv, u32 mask);
+void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask);
+void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask);
 void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 61e00bf..736ddba 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1741,7 +1741,7 @@ hsw_vebox_irq_enable(struct intel_engine_cs *engine)
 	struct drm_i915_private *dev_priv = engine->i915;
 
 	I915_WRITE_IMR(engine, ~engine->irq_enable_mask);
-	gen6_enable_pm_irq(dev_priv, engine->irq_enable_mask);
+	gen6_unmask_pm_irq(dev_priv, engine->irq_enable_mask);
 }
 
 static void
@@ -1750,7 +1750,7 @@ hsw_vebox_irq_disable(struct intel_engine_cs *engine)
 	struct drm_i915_private *dev_priv = engine->i915;
 
 	I915_WRITE_IMR(engine, ~0);
-	gen6_disable_pm_irq(dev_priv, engine->irq_enable_mask);
+	gen6_mask_pm_irq(dev_priv, engine->irq_enable_mask);
 }
 
 static void
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 05/17] drm/i915: Support for GuC interrupts
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (3 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 04/17] drm/i915: Add low level set of routines for programming PM IER/IIR/IMR register set akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-11 10:30   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 06/17] drm/i915: Handle log buffer flush interrupt event from GuC akash.goel
                   ` (12 subsequent siblings)
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Sagar Arun Kamble <sagar.a.kamble@intel.com>

There are certain types of interrupts which Host can recieve from GuC.
GuC ukernel sends an interrupt to Host for certain events, like for
example retrieve/consume the logs generated by ukernel.
This patch adds support to receive interrupts from GuC but currently
enables & partially handles only the interrupt sent by GuC ukernel.
Future patches will add support for handling other interrupt types.

v2:
- Use common low level routines for PM IER/IIR programming (Chris)
- Rename interrupt functions to gen9_xxx from gen8_xxx (Chris)
- Replace disabling of wake ref asserts with rpm get/put (Chris)

v3:
- Update comments for more clarity. (Tvrtko)
- Remove the masking of GuC interrupt, which was kept masked till the
  start of bottom half, its not really needed as there is only a
  single instance of work item & wq is ordered. (Tvrtko)

v4:
- Rebase.
- Rename guc_events to pm_guc_events so as to be indicative of the
  register/control block it is associated with. (Chris)
- Add handling for back to back log buffer flush interrupts.

Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h            |  1 +
 drivers/gpu/drm/i915/i915_guc_submission.c |  5 ++
 drivers/gpu/drm/i915/i915_irq.c            | 98 ++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/i915_reg.h            | 11 ++++
 drivers/gpu/drm/i915/intel_drv.h           |  3 +
 drivers/gpu/drm/i915/intel_guc.h           |  4 ++
 drivers/gpu/drm/i915/intel_guc_loader.c    |  4 ++
 7 files changed, 122 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c3a579f..6e2ddfa 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1794,6 +1794,7 @@ struct drm_i915_private {
 	u32 pm_imr;
 	u32 pm_ier;
 	u32 pm_rps_events;
+	u32 pm_guc_events;
 	u32 pipestat_irq_mask[I915_MAX_PIPES];
 
 	struct i915_hotplug hotplug;
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 0fb00ab..0bac172 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -1044,6 +1044,8 @@ int intel_guc_suspend(struct drm_device *dev)
 	if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS)
 		return 0;
 
+	gen9_disable_guc_interrupts(dev_priv);
+
 	ctx = dev_priv->kernel_context;
 
 	data[0] = HOST2GUC_ACTION_ENTER_S_STATE;
@@ -1070,6 +1072,9 @@ int intel_guc_resume(struct drm_device *dev)
 	if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS)
 		return 0;
 
+	if (i915.guc_log_level >= 0)
+		gen9_enable_guc_interrupts(dev_priv);
+
 	ctx = dev_priv->kernel_context;
 
 	data[0] = HOST2GUC_ACTION_EXIT_S_STATE;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 24bbaf7..fd73c94 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -170,6 +170,7 @@ static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv,
 } while (0)
 
 static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
+static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
 
 /* For display hotplug interrupt */
 static inline void
@@ -411,6 +412,39 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
 	gen6_reset_rps_interrupts(dev_priv);
 }
 
+void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv)
+{
+	spin_lock_irq(&dev_priv->irq_lock);
+	gen6_reset_pm_iir(dev_priv, dev_priv->pm_guc_events);
+	spin_unlock_irq(&dev_priv->irq_lock);
+}
+
+void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv)
+{
+	spin_lock_irq(&dev_priv->irq_lock);
+	if (!dev_priv->guc.interrupts_enabled) {
+		WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) &
+						dev_priv->pm_guc_events);
+		dev_priv->guc.interrupts_enabled = true;
+		gen6_enable_pm_irq(dev_priv, dev_priv->pm_guc_events);
+	}
+	spin_unlock_irq(&dev_priv->irq_lock);
+}
+
+void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv)
+{
+	spin_lock_irq(&dev_priv->irq_lock);
+	dev_priv->guc.interrupts_enabled = false;
+
+	gen6_disable_pm_irq(dev_priv, dev_priv->pm_guc_events);
+
+	spin_unlock_irq(&dev_priv->irq_lock);
+	synchronize_irq(dev_priv->drm.irq);
+
+	cancel_work_sync(&dev_priv->guc.events_work);
+	gen9_reset_guc_interrupts(dev_priv);
+}
+
 /**
  * bdw_update_port_irq - update DE port interrupt
  * @dev_priv: driver private
@@ -1174,6 +1208,21 @@ static void gen6_pm_rps_work(struct work_struct *work)
 	mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
+static void gen9_guc2host_events_work(struct work_struct *work)
+{
+	struct drm_i915_private *dev_priv =
+		container_of(work, struct drm_i915_private, guc.events_work);
+
+	spin_lock_irq(&dev_priv->irq_lock);
+	/* Speed up work cancellation during disabling guc interrupts. */
+	if (!dev_priv->guc.interrupts_enabled) {
+		spin_unlock_irq(&dev_priv->irq_lock);
+		return;
+	}
+	spin_unlock_irq(&dev_priv->irq_lock);
+
+	/* TODO: Handle the events for which GuC interrupted host */
+}
 
 /**
  * ivybridge_parity_work - Workqueue called when a parity error interrupt
@@ -1346,11 +1395,13 @@ static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
 			DRM_ERROR("The master control interrupt lied (GT3)!\n");
 	}
 
-	if (master_ctl & GEN8_GT_PM_IRQ) {
+	if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
 		gt_iir[2] = I915_READ_FW(GEN8_GT_IIR(2));
-		if (gt_iir[2] & dev_priv->pm_rps_events) {
+		if (gt_iir[2] & (dev_priv->pm_rps_events |
+				 dev_priv->pm_guc_events)) {
 			I915_WRITE_FW(GEN8_GT_IIR(2),
-				      gt_iir[2] & dev_priv->pm_rps_events);
+				      gt_iir[2] & (dev_priv->pm_rps_events |
+						   dev_priv->pm_guc_events));
 			ret = IRQ_HANDLED;
 		} else
 			DRM_ERROR("The master control interrupt lied (PM)!\n");
@@ -1382,6 +1433,9 @@ static void gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
 
 	if (gt_iir[2] & dev_priv->pm_rps_events)
 		gen6_rps_irq_handler(dev_priv, gt_iir[2]);
+
+	if (gt_iir[2] & dev_priv->pm_guc_events)
+		gen9_guc_irq_handler(dev_priv, gt_iir[2]);
 }
 
 static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
@@ -1628,6 +1682,38 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
 	}
 }
 
+static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
+{
+	if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) {
+		spin_lock(&dev_priv->irq_lock);
+		if (dev_priv->guc.interrupts_enabled) {
+			/* Sample the log buffer flush related bits & clear them
+			 * out now itself from the message identity register to
+			 * minimize the probability of losing a flush interrupt,
+			 * when there are back to back flush interrupts.
+			 * There can be a new flush interrupt, for different log
+			 * buffer type (like for ISR), whilst Host is handling
+			 * one (for DPC). Since same bit is used in message
+			 * register for ISR & DPC, it could happen that GuC
+			 * sets the bit for 2nd interrupt but Host clears out
+			 * the bit on handling the 1st interrupt.
+			 */
+			u32 msg = I915_READ(SOFT_SCRATCH(15)) &
+					(GUC2HOST_MSG_CRASH_DUMP_POSTED |
+					 GUC2HOST_MSG_FLUSH_LOG_BUFFER);
+			if (msg) {
+				/* Clear the message bits that are handled */
+				I915_WRITE(SOFT_SCRATCH(15),
+					I915_READ(SOFT_SCRATCH(15)) & ~msg);
+
+				/* Handle flush interrupt event in bottom half */
+				queue_work(dev_priv->wq, &dev_priv->guc.events_work);
+			}
+		}
+		spin_unlock(&dev_priv->irq_lock);
+	}
+}
+
 static bool intel_pipe_handle_vblank(struct drm_i915_private *dev_priv,
 				     enum pipe pipe)
 {
@@ -3754,7 +3840,7 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
 	GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
 	/*
 	 * RPS interrupts will get enabled/disabled on demand when RPS itself
-	 * is enabled/disabled.
+	 * is enabled/disabled. Same wil be the case for GuC interrupts.
 	 */
 	GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier);
 	GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
@@ -4539,6 +4625,10 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
 
 	INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
 	INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
+	INIT_WORK(&dev_priv->guc.events_work, gen9_guc2host_events_work);
+
+	if (HAS_GUC_UCODE(dev))
+		dev_priv->pm_guc_events = GEN9_GUC_TO_HOST_INT_EVENT;
 
 	/* Let's track the enabled rps events */
 	if (IS_VALLEYVIEW(dev_priv))
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 8bfde75..d0d13a2 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -5963,6 +5963,7 @@ enum {
 #define  GEN8_DE_PIPE_A_IRQ		(1<<16)
 #define  GEN8_DE_PIPE_IRQ(pipe)		(1<<(16+(pipe)))
 #define  GEN8_GT_VECS_IRQ		(1<<6)
+#define  GEN8_GT_GUC_IRQ		(1<<5)
 #define  GEN8_GT_PM_IRQ			(1<<4)
 #define  GEN8_GT_VCS2_IRQ		(1<<3)
 #define  GEN8_GT_VCS1_IRQ		(1<<2)
@@ -5974,6 +5975,16 @@ enum {
 #define GEN8_GT_IIR(which) _MMIO(0x44308 + (0x10 * (which)))
 #define GEN8_GT_IER(which) _MMIO(0x4430c + (0x10 * (which)))
 
+#define GEN9_GUC_TO_HOST_INT_EVENT	(1<<31)
+#define GEN9_GUC_EXEC_ERROR_EVENT	(1<<30)
+#define GEN9_GUC_DISPLAY_EVENT		(1<<29)
+#define GEN9_GUC_SEMA_SIGNAL_EVENT	(1<<28)
+#define GEN9_GUC_IOMMU_MSG_EVENT	(1<<27)
+#define GEN9_GUC_DB_RING_EVENT		(1<<26)
+#define GEN9_GUC_DMA_DONE_EVENT		(1<<25)
+#define GEN9_GUC_FATAL_ERROR_EVENT	(1<<24)
+#define GEN9_GUC_NOTIFICATION_EVENT	(1<<23)
+
 #define GEN8_RCS_IRQ_SHIFT 0
 #define GEN8_BCS_IRQ_SHIFT 16
 #define GEN8_VCS1_IRQ_SHIFT 0
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ae6c535..6868f31 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1102,6 +1102,9 @@ void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
 				     unsigned int pipe_mask);
 void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
 				     unsigned int pipe_mask);
+void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv);
+void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv);
+void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv);
 
 /* intel_crt.c */
 void intel_crt_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index d52eca3..2663b41 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -131,6 +131,10 @@ struct intel_guc {
 	struct intel_guc_fw guc_fw;
 	struct intel_guc_log log;
 
+	/* GuC2Host interrupt related state */
+	struct work_struct events_work;
+	bool interrupts_enabled;
+
 	struct drm_i915_gem_object *ads_obj;
 
 	struct drm_i915_gem_object *ctx_pool_obj;
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 4882f17..d74d7a5 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -450,6 +450,7 @@ int intel_guc_setup(struct drm_device *dev)
 	}
 
 	direct_interrupts_to_host(dev_priv);
+	gen9_reset_guc_interrupts(dev_priv);
 
 	guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING;
 
@@ -496,6 +497,9 @@ int intel_guc_setup(struct drm_device *dev)
 		intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
 
 	if (i915.enable_guc_submission) {
+		if (i915.guc_log_level >= 0)
+			gen9_enable_guc_interrupts(dev_priv);
+
 		err = i915_guc_submission_enable(dev_priv);
 		if (err)
 			goto fail;
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 06/17] drm/i915: Handle log buffer flush interrupt event from GuC
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (4 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 05/17] drm/i915: Support for GuC interrupts akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-19 10:58   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 07/17] drm/i915: Add a relay backed debugfs interface for capturing GuC logs akash.goel
                   ` (11 subsequent siblings)
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Sagar Arun Kamble <sagar.a.kamble@intel.com>

GuC ukernel sends an interrupt to Host to flush the log buffer
and expects Host to correspondingly update the read pointer
information in the state structure, once it has consumed the
log buffer contents by copying them to a file or buffer.
Even if Host couldn't copy the contents, it can still update the
read pointer so that logging state is not disturbed on GuC side.

v2:
- Use a dedicated workqueue for handling flush interrupt. (Tvrtko)
- Reduce the overall log buffer copying time by skipping the copy of
  crash buffer area for regular cases and copying only the state
  structure data in first page.

v3:
 - Create a vmalloc mapping of log buffer. (Chris)
 - Cover the flush acknowledgment under rpm get & put.(Chris)
 - Revert the change of skipping the copy of crash dump area, as
   not really needed, will be covered by subsequent patch.

Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.c            |  13 +++
 drivers/gpu/drm/i915/i915_guc_submission.c | 148 +++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_irq.c            |   5 +-
 drivers/gpu/drm/i915/intel_guc.h           |   3 +
 4 files changed, 167 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index b9a8117..25c6b9b 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -791,8 +791,20 @@ static int i915_workqueues_init(struct drm_i915_private *dev_priv)
 	if (dev_priv->hotplug.dp_wq == NULL)
 		goto out_free_wq;
 
+	if (HAS_GUC_SCHED(dev_priv)) {
+		/* Need a dedicated wq to process log buffer flush interrupts
+		 * from GuC without much delay so as to avoid any loss of logs.
+		 */
+		dev_priv->guc.log.wq =
+			alloc_ordered_workqueue("i915-guc_log", 0);
+		if (dev_priv->guc.log.wq == NULL)
+			goto out_free_hotplug_dp_wq;
+	}
+
 	return 0;
 
+out_free_hotplug_dp_wq:
+	destroy_workqueue(dev_priv->hotplug.dp_wq);
 out_free_wq:
 	destroy_workqueue(dev_priv->wq);
 out_err:
@@ -803,6 +815,7 @@ out_err:
 
 static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv)
 {
+	destroy_workqueue(dev_priv->guc.log.wq);
 	destroy_workqueue(dev_priv->hotplug.dp_wq);
 	destroy_workqueue(dev_priv->wq);
 }
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 0bac172..d3dbb8e 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -172,6 +172,15 @@ static int host2guc_sample_forcewake(struct intel_guc *guc,
 	return host2guc_action(guc, data, ARRAY_SIZE(data));
 }
 
+static int host2guc_logbuffer_flush_complete(struct intel_guc *guc)
+{
+	u32 data[1];
+
+	data[0] = HOST2GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE;
+
+	return host2guc_action(guc, data, 1);
+}
+
 /*
  * Initialise, update, or clear doorbell data shared with the GuC
  *
@@ -825,6 +834,123 @@ err:
 	return NULL;
 }
 
+static void guc_move_to_next_buf(struct intel_guc *guc)
+{
+	return;
+}
+
+static void* guc_get_write_buffer(struct intel_guc *guc)
+{
+	return NULL;
+}
+
+static void guc_read_update_log_buffer(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+	struct guc_log_buffer_state *log_buffer_state, *log_buffer_copy_state;
+	struct guc_log_buffer_state log_buffer_state_local;
+	void *src_data_ptr, *dst_data_ptr;
+	u32 i, buffer_size;
+
+	if (!guc->log.obj || !guc->log.buf_addr)
+		return;
+
+	log_buffer_state = src_data_ptr = guc->log.buf_addr;
+
+	/* Get the pointer to local buffer to store the logs */
+	dst_data_ptr = log_buffer_copy_state = guc_get_write_buffer(guc);
+
+	/* Actual logs are present from the 2nd page */
+	src_data_ptr += PAGE_SIZE;
+	dst_data_ptr += PAGE_SIZE;
+
+	for (i = 0; i < GUC_MAX_LOG_BUFFER; i++) {
+		log_buffer_state_local = *log_buffer_state;
+		buffer_size = log_buffer_state_local.size;
+
+		if (log_buffer_copy_state) {
+			/* First copy the state structure */
+			memcpy(log_buffer_copy_state, &log_buffer_state_local,
+					sizeof(struct guc_log_buffer_state));
+
+			/* The write pointer could have been updated by the GuC
+			 * firmware, after sending the flush interrupt to Host,
+			 * for consistency set the write pointer value to same
+			 * value of sampled_write_ptr in the snapshot buffer.
+			 */
+			log_buffer_copy_state->write_ptr =
+				log_buffer_copy_state->sampled_write_ptr;
+
+			log_buffer_copy_state++;
+
+			/* Now copy the actual logs */
+			memcpy(dst_data_ptr, src_data_ptr, buffer_size);
+
+			src_data_ptr += buffer_size;
+			dst_data_ptr += buffer_size;
+		}
+
+		/* FIXME: invalidate/flush for log buffer needed */
+
+		/* Update the read pointer in the shared log buffer */
+		log_buffer_state->read_ptr =
+			log_buffer_state_local.sampled_write_ptr;
+
+		/* Clear the 'flush to file' flag */
+		log_buffer_state->flush_to_file = 0;
+		log_buffer_state++;
+	}
+
+	if (log_buffer_copy_state)
+		guc_move_to_next_buf(guc);
+}
+
+static void guc_log_cleanup(struct drm_i915_private *dev_priv)
+{
+	struct intel_guc *guc = &dev_priv->guc;
+
+	lockdep_assert_held(&dev_priv->drm.struct_mutex);
+
+	if (i915.guc_log_level < 0)
+		return;
+
+	/* First disable the flush interrupt */
+	gen9_disable_guc_interrupts(dev_priv);
+
+	if (guc->log.buf_addr)
+		i915_gem_object_unpin_map(guc->log.obj);
+
+	guc->log.buf_addr = NULL;
+}
+
+static int guc_create_log_extras(struct intel_guc *guc)
+{
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	void *vaddr;
+	int ret;
+
+	lockdep_assert_held(&dev_priv->drm.struct_mutex);
+
+	/* Nothing to do */
+	if (i915.guc_log_level < 0)
+		return 0;
+
+	if (!guc->log.buf_addr) {
+		/* Create a vmalloc mapping of log buffer pages */
+		vaddr = i915_gem_object_pin_map(guc->log.obj);
+		if (IS_ERR(vaddr)) {
+			ret = PTR_ERR(vaddr);
+			DRM_ERROR("Couldn't map log buffer pages %d\n", ret);
+			return ret;
+		}
+
+		guc->log.buf_addr = vaddr;
+	}
+
+	return 0;
+}
+
 static void guc_create_log(struct intel_guc *guc)
 {
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
@@ -851,6 +977,13 @@ static void guc_create_log(struct intel_guc *guc)
 		}
 
 		guc->log.obj = obj;
+
+		if (guc_create_log_extras(guc)) {
+			gem_release_guc_obj(guc->log.obj);
+			guc->log.obj = NULL;
+			i915.guc_log_level = -1;
+			return;
+		}
 	}
 
 	/* each allocated unit is a page */
@@ -1021,6 +1154,7 @@ void i915_guc_submission_fini(struct drm_i915_private *dev_priv)
 	gem_release_guc_obj(dev_priv->guc.ads_obj);
 	guc->ads_obj = NULL;
 
+	guc_log_cleanup(dev_priv);
 	gem_release_guc_obj(dev_priv->guc.log.obj);
 	guc->log.obj = NULL;
 
@@ -1084,3 +1218,17 @@ int intel_guc_resume(struct drm_device *dev)
 
 	return host2guc_action(guc, data, ARRAY_SIZE(data));
 }
+
+void i915_guc_capture_logs(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	guc_read_update_log_buffer(dev);
+
+	/* Generally device is expected to be active only at this
+	 * time, so get/put should be really quick.
+	 */
+	intel_runtime_pm_get(dev_priv);
+	host2guc_logbuffer_flush_complete(&dev_priv->guc);
+	intel_runtime_pm_put(dev_priv);
+}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index fd73c94..f90d3c6 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1221,7 +1221,7 @@ static void gen9_guc2host_events_work(struct work_struct *work)
 	}
 	spin_unlock_irq(&dev_priv->irq_lock);
 
-	/* TODO: Handle the events for which GuC interrupted host */
+	i915_guc_capture_logs(&dev_priv->drm);
 }
 
 /**
@@ -1707,7 +1707,8 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
 					I915_READ(SOFT_SCRATCH(15)) & ~msg);
 
 				/* Handle flush interrupt event in bottom half */
-				queue_work(dev_priv->wq, &dev_priv->guc.events_work);
+				queue_work(dev_priv->guc.log.wq,
+						&dev_priv->guc.events_work);
 			}
 		}
 		spin_unlock(&dev_priv->irq_lock);
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 2663b41..d4f0fae 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -125,6 +125,8 @@ struct intel_guc_fw {
 struct intel_guc_log {
 	uint32_t flags;
 	struct drm_i915_gem_object *obj;
+	struct workqueue_struct *wq;
+	void *buf_addr;
 };
 
 struct intel_guc {
@@ -171,5 +173,6 @@ int i915_guc_wq_check_space(struct drm_i915_gem_request *rq);
 int i915_guc_submit(struct drm_i915_gem_request *rq);
 void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
 void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
+void i915_guc_capture_logs(struct drm_device *dev);
 
 #endif
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 07/17] drm/i915: Add a relay backed debugfs interface for capturing GuC logs
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (5 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 06/17] drm/i915: Handle log buffer flush interrupt event from GuC akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-10 17:07   ` kbuild test robot
  2016-07-19 11:31   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 08/17] drm/i915: Forcefully flush GuC log buffer on reset akash.goel
                   ` (10 subsequent siblings)
  17 siblings, 2 replies; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel, Sourab Gupta

From: Akash Goel <akash.goel@intel.com>

Added a new debugfs interface '/sys/kernel/debug/dri/guc_log' for the
User to capture GuC firmware logs. Availed relay framework to implement
the interface, where Driver will have to just use a relay API to store
snapshots of the GuC log buffer in the buffer managed by relay.
The snapshot will be taken when GuC firmware sends a log buffer flush
interrupt and up to four snaphots could be stored in the relay buffer.
The relay buffer will be operated in a mode where it will overwrite the
data not yet collected by User.
Besides mmap method, through which User can directly access the relay
buffer contents, relay also supports the 'poll' method. Through the 'poll'
call on log file, User can come to know whenever a new snapshot of the
log buffer is taken by Driver, so can run in tandem with the Driver and
capture the logs in a sustained/streaming manner, without any loss of data.

v2: Defer the creation of relay channel & associated debugfs file, as
    debugfs setup is now done at the end of i915 Driver load. (Chris)

v3:
- Switch to no-overwrite mode for relay.
- Fix the relay sub buffer switching sequence.

Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.c            |   2 +
 drivers/gpu/drm/i915/i915_guc_submission.c | 197 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_guc.h           |   3 +
 3 files changed, 199 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 25c6b9b..43c9900 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -1177,6 +1177,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
 	/* Reveal our presence to userspace */
 	if (drm_dev_register(dev, 0) == 0) {
 		i915_debugfs_register(dev_priv);
+		i915_guc_register(dev);
 		i915_setup_sysfs(dev);
 	} else
 		DRM_ERROR("Failed to register driver for userspace access!\n");
@@ -1215,6 +1216,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
 	intel_opregion_unregister(dev_priv);
 
 	i915_teardown_sysfs(&dev_priv->drm);
+	i915_guc_unregister(&dev_priv->drm);
 	i915_debugfs_unregister(dev_priv);
 	drm_dev_unregister(&dev_priv->drm);
 
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index d3dbb8e..9b436fa 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -23,6 +23,8 @@
  */
 #include <linux/firmware.h>
 #include <linux/circ_buf.h>
+#include <linux/debugfs.h>
+#include <linux/relay.h>
 #include "i915_drv.h"
 #include "intel_guc.h"
 
@@ -836,12 +838,33 @@ err:
 
 static void guc_move_to_next_buf(struct intel_guc *guc)
 {
-	return;
+	/* Make sure our updates are in the sub buffer are visible when
+	 * Consumer sees a newly produced sub buffer.
+	 */
+	smp_wmb();
+
+	/* All data has been written, so now move the offset of sub buffer. */
+	relay_reserve(guc->log.relay_chan, guc->log.obj->base.size);
+
+	/* Switch to the next sub buffer */
+	relay_flush(guc->log.relay_chan);
 }
 
 static void* guc_get_write_buffer(struct intel_guc *guc)
 {
-	return NULL;
+	/* FIXME: Cover the check under a lock ? */
+	if (!guc->log.relay_chan)
+		return NULL;
+
+	/* Just get the base address of a new sub buffer and copy data into it
+	 * ourselves. NULL will be returned in no-overwrite mode, if all sub
+	 * buffers are full. Could have used the relay_write() to indirectly
+	 * copy the data, but that would have been bit convoluted, as we need to
+	 * write to only certain locations inside a sub buffer which cannot be
+	 * done without using relay_reserve() along with relay_write(). So its
+	 * better to use relay_reserve() alone.
+	 */
+	return relay_reserve(guc->log.relay_chan, 0);
 }
 
 static void guc_read_update_log_buffer(struct drm_device *dev)
@@ -906,6 +929,119 @@ static void guc_read_update_log_buffer(struct drm_device *dev)
 		guc_move_to_next_buf(guc);
 }
 
+/*
+ * Sub buffer switch callback. Called whenever relay has to switch to a new
+ * sub buffer, relay stays on the same sub buffer if 0 is returned.
+ */
+static int subbuf_start_callback(struct rchan_buf *buf,
+				 void *subbuf,
+				 void *prev_subbuf,
+				 size_t prev_padding)
+{
+	/* Use no-overwrite mode by default, where relay will stop accepting
+	 * new data if there are no empty sub buffers left.
+	 * There is no strict synchronization enforced by relay between Consumer
+	 * and Producer. In overwrite mode, there is a possibility of getting
+	 * inconsistent/garbled data, the producer could be writing on to the
+	 * same sub buffer from which Consumer is reading. This can't be avoided
+	 * unless Consumer is fast enough and can always run in tandem with
+	 * Producer.
+	 */
+	if (relay_buf_full(buf))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * file_create() callback. Creates relay file in debugfs.
+ */
+static struct dentry *create_buf_file_callback(const char *filename,
+					       struct dentry *parent,
+					       umode_t mode,
+					       struct rchan_buf *buf,
+					       int *is_global)
+{
+	/*
+	 * Not using the channel filename passed as an argument, since for each
+	 * channel relay appends the corresponding CPU number to the filename
+	 * passed in relay_open(). This should be fine as relay just needs a
+	 * dentry of the file associated with the channel buffer and that file's
+	 * name need not be same as the filename passed as an argument.
+	 */
+	struct dentry *buf_file = debugfs_create_file("guc_log", mode,
+			parent, buf, &relay_file_operations);
+
+	/* This to enable the use of a single buffer for the relay channel and
+	 * correspondingly have a single file exposed to User, through which
+	 * it can collect the logs inorder without any post-processing.
+	 */
+	*is_global = 1;
+
+	return buf_file;
+}
+
+/*
+ * file_remove() default callback. Removes relay file in debugfs.
+ */
+static int remove_buf_file_callback(struct dentry *dentry)
+{
+	debugfs_remove(dentry);
+	return 0;
+}
+
+/* relay channel callbacks */
+static struct rchan_callbacks relay_callbacks = {
+	.subbuf_start = subbuf_start_callback,
+	.create_buf_file = create_buf_file_callback,
+	.remove_buf_file = remove_buf_file_callback,
+};
+
+static void guc_remove_log_relay_file(struct intel_guc *guc)
+{
+	if (guc->log.relay_chan)
+		relay_close(guc->log.relay_chan);
+}
+
+static int guc_create_log_relay_file(struct intel_guc *guc)
+{
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	struct drm_device *dev = &dev_priv->drm;
+	struct dentry *log_dir;
+	struct rchan *guc_log_relay_chan;
+	size_t n_subbufs, subbuf_size;
+
+	if (guc->log.relay_chan)
+		return 0;
+
+	/* If /sys/kernel/debug/dri/0 location do not exist, then debugfs is
+	 * not mounted and so can't create the relay file.
+	 * The relay API seems to fit well with debugfs only.
+	 */
+	if (!dev->primary->debugfs_root)
+		return -ENODEV;
+
+	/* For now create the log file in /sys/kernel/debug/dri/0 dir */
+	log_dir = dev->primary->debugfs_root;
+
+	/* Keep the size of sub buffers same as shared log buffer */
+	subbuf_size = guc->log.obj->base.size;
+	/* TODO: Decide based on the User's input */
+	n_subbufs = 4;
+
+	guc_log_relay_chan = relay_open("guc_log", log_dir,
+			subbuf_size, n_subbufs, &relay_callbacks, dev);
+
+	if (!guc_log_relay_chan) {
+		DRM_DEBUG_DRIVER("Couldn't create relay chan for guc logs\n");
+		return -ENOMEM;
+	}
+
+	/* FIXME: Cover the update under a lock ? */
+	guc->log.relay_chan = guc_log_relay_chan;
+	return 0;
+}
+
 static void guc_log_cleanup(struct drm_i915_private *dev_priv)
 {
 	struct intel_guc *guc = &dev_priv->guc;
@@ -918,6 +1054,9 @@ static void guc_log_cleanup(struct drm_i915_private *dev_priv)
 	/* First disable the flush interrupt */
 	gen9_disable_guc_interrupts(dev_priv);
 
+	guc_remove_log_relay_file(guc);
+	guc->log.relay_chan = NULL;
+
 	if (guc->log.buf_addr)
 		i915_gem_object_unpin_map(guc->log.obj);
 
@@ -996,6 +1135,39 @@ static void guc_create_log(struct intel_guc *guc)
 	guc->log.flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
 }
 
+static int guc_log_late_setup(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+	int ret;
+
+	lockdep_assert_held(&dev->struct_mutex);
+
+	if (i915.guc_log_level < 0)
+		return -EINVAL;
+
+	if (WARN_ON(guc->log.relay_chan))
+		return -EINVAL;
+
+	/* If log_level was set as -1 at boot time, then vmalloc mapping would
+	 * not have been created for the log buffer, so create one now.
+	 */
+	ret = guc_create_log_extras(guc);
+	if (ret)
+		goto err;
+
+	ret = guc_create_log_relay_file(guc);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	guc_log_cleanup(dev_priv);
+	/* logging will remain off */
+	i915.guc_log_level = -1;
+	return ret;
+}
+
 static void init_guc_policies(struct guc_policies *policies)
 {
 	struct guc_policy *policy;
@@ -1154,7 +1326,6 @@ void i915_guc_submission_fini(struct drm_i915_private *dev_priv)
 	gem_release_guc_obj(dev_priv->guc.ads_obj);
 	guc->ads_obj = NULL;
 
-	guc_log_cleanup(dev_priv);
 	gem_release_guc_obj(dev_priv->guc.log.obj);
 	guc->log.obj = NULL;
 
@@ -1232,3 +1403,23 @@ void i915_guc_capture_logs(struct drm_device *dev)
 	host2guc_logbuffer_flush_complete(&dev_priv->guc);
 	intel_runtime_pm_put(dev_priv);
 }
+
+void i915_guc_unregister(struct drm_device *dev)
+{
+	if (!i915.enable_guc_submission)
+		return;
+
+	mutex_lock(&dev->struct_mutex);
+	guc_log_cleanup(dev->dev_private);
+	mutex_unlock(&dev->struct_mutex);
+}
+
+void i915_guc_register(struct drm_device *dev)
+{
+	if (!i915.enable_guc_submission)
+		return;
+
+	mutex_lock(&dev->struct_mutex);
+	guc_log_late_setup(dev);
+	mutex_unlock(&dev->struct_mutex);
+}
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index d4f0fae..a784cf8 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -127,6 +127,7 @@ struct intel_guc_log {
 	struct drm_i915_gem_object *obj;
 	struct workqueue_struct *wq;
 	void *buf_addr;
+	struct rchan *relay_chan;
 };
 
 struct intel_guc {
@@ -174,5 +175,7 @@ int i915_guc_submit(struct drm_i915_gem_request *rq);
 void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
 void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
 void i915_guc_capture_logs(struct drm_device *dev);
+void i915_guc_register(struct drm_device *dev);
+void i915_guc_unregister(struct drm_device *dev);
 
 #endif
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 08/17] drm/i915: Forcefully flush GuC log buffer on reset
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (6 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 07/17] drm/i915: Add a relay backed debugfs interface for capturing GuC logs akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-19 11:12   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 09/17] drm/i915: Debugfs support for GuC logging control akash.goel
                   ` (9 subsequent siblings)
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Sagar Arun Kamble <sagar.a.kamble@intel.com>

If GuC logs are being captured, there should be a force log buffer flush
action sent to GuC before proceeding with GPU reset and re-initializing
GUC. Those logs would be useful to understand why the GPU reset was
initiated.

v2: Rebase.

Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 32 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_irq.c            |  2 ++
 drivers/gpu/drm/i915/intel_guc.h           |  1 +
 3 files changed, 35 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 9b436fa..8cc31c6 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -183,6 +183,16 @@ static int host2guc_logbuffer_flush_complete(struct intel_guc *guc)
 	return host2guc_action(guc, data, 1);
 }
 
+static int host2guc_force_logbuffer_flush(struct intel_guc *guc)
+{
+	u32 data[2];
+
+	data[0] = HOST2GUC_ACTION_FORCE_LOG_BUFFER_FLUSH;
+	data[1] = 0;
+
+	return host2guc_action(guc, data, 2);
+}
+
 /*
  * Initialise, update, or clear doorbell data shared with the GuC
  *
@@ -1404,6 +1414,28 @@ void i915_guc_capture_logs(struct drm_device *dev)
 	intel_runtime_pm_put(dev_priv);
 }
 
+void i915_guc_capture_logs_on_reset(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	mutex_lock(&dev->struct_mutex);
+
+	if (!i915.enable_guc_submission || (i915.guc_log_level < 0))
+		goto end;
+
+	/* First disable the interrupts, will be renabled after reset */
+	gen9_disable_guc_interrupts(dev_priv);
+
+	/* Ask GuC to update the log buffer state */
+	host2guc_force_logbuffer_flush(&dev_priv->guc);
+
+	/* GuC would have updated the log buffer by now, so capture it */
+	i915_guc_capture_logs(dev);
+
+end:
+	mutex_unlock(&dev->struct_mutex);
+}
+
 void i915_guc_unregister(struct drm_device *dev)
 {
 	if (!i915.enable_guc_submission)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index f90d3c6..bdd7a67 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2640,6 +2640,8 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv)
 		 */
 		intel_runtime_pm_get(dev_priv);
 
+		i915_guc_capture_logs_on_reset(&dev_priv->drm);
+
 		intel_prepare_reset(dev_priv);
 
 		/*
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index a784cf8..ed773b5 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -175,6 +175,7 @@ int i915_guc_submit(struct drm_i915_gem_request *rq);
 void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
 void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
 void i915_guc_capture_logs(struct drm_device *dev);
+void i915_guc_capture_logs_on_reset(struct drm_device *dev);
 void i915_guc_register(struct drm_device *dev);
 void i915_guc_unregister(struct drm_device *dev);
 
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (7 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 08/17] drm/i915: Forcefully flush GuC log buffer on reset akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-10 17:59   ` kbuild test robot
  2016-07-19 11:24   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs akash.goel
                   ` (8 subsequent siblings)
  17 siblings, 2 replies; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Sagar Arun Kamble <sagar.a.kamble@intel.com>

This patch provides debugfs interface i915_guc_output_control for
on the fly enabling/disabling of logging in GuC firmware and controlling
the verbosity level of logs.
The value written to the file, should have bit 0 set to enable logging and
bits 4-7 should contain the verbosity info.

v2: Add a forceful flush, to collect left over logs, on disabling logging.
    Useful for Validation.

Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c        | 32 ++++++++++++++++-
 drivers/gpu/drm/i915/i915_guc_submission.c | 57 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc.h           |  1 +
 3 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 5e35565..3c9c7f7 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2644,6 +2644,35 @@ static int i915_guc_log_dump(struct seq_file *m, void *data)
 	return 0;
 }
 
+static int
+i915_guc_log_control_set(void *data, u64 val)
+{
+	struct drm_device *dev = data;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	if (!i915.enable_guc_submission || !dev_priv->guc.log.obj) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	intel_runtime_pm_get(dev_priv);
+	ret = i915_guc_log_control(dev, val);
+	intel_runtime_pm_put(dev_priv);
+
+end:
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
+			NULL, i915_guc_log_control_set,
+			"0x%08llx\n");
+
 static int i915_edp_psr_status(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = m->private;
@@ -5464,7 +5493,8 @@ static const struct i915_debugfs_files {
 	{"i915_fbc_false_color", &i915_fbc_fc_fops},
 	{"i915_dp_test_data", &i915_displayport_test_data_fops},
 	{"i915_dp_test_type", &i915_displayport_test_type_fops},
-	{"i915_dp_test_active", &i915_displayport_test_active_fops}
+	{"i915_dp_test_active", &i915_displayport_test_active_fops},
+	{"i915_guc_log_control", &i915_guc_log_control_fops}
 };
 
 void intel_display_crc_init(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 8cc31c6..2e3b723 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -193,6 +193,16 @@ static int host2guc_force_logbuffer_flush(struct intel_guc *guc)
 	return host2guc_action(guc, data, 2);
 }
 
+static int host2guc_logging_control(struct intel_guc *guc, u32 control_val)
+{
+	u32 data[2];
+
+	data[0] = HOST2GUC_ACTION_UK_LOG_ENABLE_LOGGING;
+	data[1] = control_val;
+
+	return host2guc_action(guc, data, 2);
+}
+
 /*
  * Initialise, update, or clear doorbell data shared with the GuC
  *
@@ -1455,3 +1465,50 @@ void i915_guc_register(struct drm_device *dev)
 	guc_log_late_setup(dev);
 	mutex_unlock(&dev->struct_mutex);
 }
+
+int i915_guc_log_control(struct drm_device *dev, uint64_t control_val)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	union guc_log_control log_param;
+	int ret;
+
+	log_param.logging_enabled = control_val & 0x1;
+	log_param.verbosity = (control_val >> 4) & 0xF;
+
+	if (log_param.verbosity < GUC_LOG_VERBOSITY_MIN ||
+	    log_param.verbosity > GUC_LOG_VERBOSITY_MAX)
+		return -EINVAL;
+
+	/* This combination doesn't make sense & won't have any effect */
+	if (!log_param.logging_enabled && (i915.guc_log_level < 0))
+		return -EINVAL;
+
+	ret = host2guc_logging_control(&dev_priv->guc, log_param.value);
+	if (ret < 0) {
+		DRM_DEBUG_DRIVER("host2guc action failed\n");
+		return ret;
+	}
+
+	i915.guc_log_level = log_param.verbosity;
+
+	/* If log_level was set as -1 at boot time, then the relay channel file
+	 * wouldn't have been created by now and interrupts also would not have
+	 * been enabled.
+	 */
+	if (!dev_priv->guc.log.relay_chan) {
+		ret = guc_log_late_setup(dev);
+		if (!ret)
+			gen9_enable_guc_interrupts(dev_priv);
+	} else if (!log_param.logging_enabled) {
+		/* Once logging is disabled, GuC won't generate logs & send an
+		 * interrupt. But there could be some data in the log buffer
+		 * which is yet to be captured. So request GuC to update the log
+		 * buffer state and send the flush interrupt so that Host can
+		 * collect the left over logs also.
+		 */
+		flush_work(&dev_priv->guc.events_work);
+		host2guc_force_logbuffer_flush(&dev_priv->guc);
+	}
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index ed773b5..d56bde6 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -178,5 +178,6 @@ void i915_guc_capture_logs(struct drm_device *dev);
 void i915_guc_capture_logs_on_reset(struct drm_device *dev);
 void i915_guc_register(struct drm_device *dev);
 void i915_guc_unregister(struct drm_device *dev);
+int i915_guc_log_control(struct drm_device *dev, uint64_t control_val);
 
 #endif
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (8 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 09/17] drm/i915: Debugfs support for GuC logging control akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-15 11:15   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 11/17] drm/i915: Support to create write combined type vmaps akash.goel
                   ` (7 subsequent siblings)
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Akash Goel <akash.goel@intel.com>

On recieving the log buffer flush interrupt from GuC firmware, Driver
stores the snapshot of the log buffer in a local buffer, from which
Userspace can pull the logs. By default Driver store, up to, 4 snapshots
of the log buffer in a local buffer (managed by relay).
Added a new module (read only) param, 'guc_log_size', through which User
can specify the number of snapshots of log buffer to be stored in local
buffer. This can be used to ensure capturing of all boot time logs even
with high verbosity level.

v2: Rename module param to more apt name 'guc_log_buffer_nr'. (Nikula)

Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 3 +--
 drivers/gpu/drm/i915/i915_params.c         | 5 +++++
 drivers/gpu/drm/i915/i915_params.h         | 1 +
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 2e3b723..009d7c0 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -1046,8 +1046,7 @@ static int guc_create_log_relay_file(struct intel_guc *guc)
 
 	/* Keep the size of sub buffers same as shared log buffer */
 	subbuf_size = guc->log.obj->base.size;
-	/* TODO: Decide based on the User's input */
-	n_subbufs = 4;
+	n_subbufs = i915.guc_log_buffer_nr;
 
 	guc_log_relay_chan = relay_open("guc_log", log_dir,
 			subbuf_size, n_subbufs, &relay_callbacks, dev);
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 8b13bfa..d30c972 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -57,6 +57,7 @@ struct i915_params i915 __read_mostly = {
 	.enable_guc_loading = -1,
 	.enable_guc_submission = -1,
 	.guc_log_level = -1,
+	.guc_log_buffer_nr = 4,
 	.enable_dp_mst = true,
 	.inject_load_failure = 0,
 	.enable_dpcd_backlight = false,
@@ -214,6 +215,10 @@ module_param_named(guc_log_level, i915.guc_log_level, int, 0400);
 MODULE_PARM_DESC(guc_log_level,
 	"GuC firmware logging level (-1:disabled (default), 0-3:enabled)");
 
+module_param_named(guc_log_buffer_nr, i915.guc_log_buffer_nr, int, 0400);
+MODULE_PARM_DESC(guc_log_buffer_nr,
+	"Number of sub buffers to store GuC firmware logs (default: 4)");
+
 module_param_named_unsafe(enable_dp_mst, i915.enable_dp_mst, bool, 0600);
 MODULE_PARM_DESC(enable_dp_mst,
 	"Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)");
diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
index 0ad020b..14ca855 100644
--- a/drivers/gpu/drm/i915/i915_params.h
+++ b/drivers/gpu/drm/i915/i915_params.h
@@ -48,6 +48,7 @@ struct i915_params {
 	int enable_guc_loading;
 	int enable_guc_submission;
 	int guc_log_level;
+	int guc_log_buffer_nr;
 	int use_mmio_flip;
 	int mmio_debug;
 	int edp_vswing;
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 11/17] drm/i915: Support to create write combined type vmaps
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (9 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-15 11:31   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 12/17] drm/i915: Use uncached(WC) mapping for acessing the GuC log buffer akash.goel
                   ` (6 subsequent siblings)
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Chris Wilson <chris@chris-wilson.co.uk>

vmaps has a provision for controlling the page protection bits, with which
we can use to control the mapping type, e.g. WB, WC, UC or even WT.
To allow the caller to choose their mapping type, we add a parameter to
i915_gem_object_pin_map - but we still only allow one vmap to be cached
per object. If the object is currently not pinned, then we recreate the
previous vmap with the new access type, but if it was pinned we report an
error. This effectively limits the access via i915_gem_object_pin_map to a
single mapping type for the lifetime of the object. Not usually a problem,
but something to be aware of when setting up the object's vmap.

We will want to vary the access type to enable WC mappings of ringbuffer
and context objects on !llc platforms, as well as other objects where we
need coherent access to the GPU's pages without going through the GTT

v2: Remove the redundant braces around pin count check and fix the marker
    in documentation (Chris)

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h            |  4 ++-
 drivers/gpu/drm/i915/i915_gem.c            | 57 +++++++++++++++++++++++-------
 drivers/gpu/drm/i915/i915_gem_dmabuf.c     |  2 +-
 drivers/gpu/drm/i915/i915_guc_submission.c |  2 +-
 drivers/gpu/drm/i915/intel_lrc.c           |  8 ++---
 drivers/gpu/drm/i915/intel_ringbuffer.c    |  2 +-
 6 files changed, 54 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 6e2ddfa..84afa17 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3248,6 +3248,7 @@ static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
 /**
  * i915_gem_object_pin_map - return a contiguous mapping of the entire object
  * @obj - the object to map into kernel address space
+ * @use_wc - whether the mapping should be using WC or WB pgprot_t
  *
  * Calls i915_gem_object_pin_pages() to prevent reaping of the object's
  * pages and then returns a contiguous mapping of the backing storage into
@@ -3259,7 +3260,8 @@ static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
  * Returns the pointer through which to access the mapped object, or an
  * ERR_PTR() on error.
  */
-void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object *obj);
+void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object *obj,
+					 bool use_wc);
 
 /**
  * i915_gem_object_unpin_map - releases an earlier mapping
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 8f50919..c431b40 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2471,10 +2471,11 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
 	list_del(&obj->global_list);
 
 	if (obj->mapping) {
-		if (is_vmalloc_addr(obj->mapping))
-			vunmap(obj->mapping);
+		void *ptr = (void *)((uintptr_t)obj->mapping & ~1);
+		if (is_vmalloc_addr(ptr))
+			vunmap(ptr);
 		else
-			kunmap(kmap_to_page(obj->mapping));
+			kunmap(kmap_to_page(ptr));
 		obj->mapping = NULL;
 	}
 
@@ -2647,7 +2648,8 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
 }
 
 /* The 'mapping' part of i915_gem_object_pin_map() below */
-static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
+static void *i915_gem_object_map(const struct drm_i915_gem_object *obj,
+				bool use_wc)
 {
 	unsigned long n_pages = obj->base.size >> PAGE_SHIFT;
 	struct sg_table *sgt = obj->pages;
@@ -2659,7 +2661,7 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
 	void *addr;
 
 	/* A single page can always be kmapped */
-	if (n_pages == 1)
+	if (n_pages == 1 && !use_wc)
 		return kmap(sg_page(sgt->sgl));
 
 	if (n_pages > ARRAY_SIZE(stack_pages)) {
@@ -2675,7 +2677,8 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
 	/* Check that we have the expected number of pages */
 	GEM_BUG_ON(i != n_pages);
 
-	addr = vmap(pages, n_pages, 0, PAGE_KERNEL);
+	addr = vmap(pages, n_pages, VM_NO_GUARD,
+		    use_wc ? pgprot_writecombine(PAGE_KERNEL_IO) : PAGE_KERNEL);
 
 	if (pages != stack_pages)
 		drm_free_large(pages);
@@ -2684,27 +2687,55 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
 }
 
 /* get, pin, and map the pages of the object into kernel space */
-void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj)
+void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, bool use_wc)
 {
+	void *ptr;
+	bool has_wc;
+	bool pinned;
 	int ret;
 
 	lockdep_assert_held(&obj->base.dev->struct_mutex);
+	GEM_BUG_ON((obj->ops->flags & I915_GEM_OBJECT_HAS_STRUCT_PAGE) == 0);
 
 	ret = i915_gem_object_get_pages(obj);
 	if (ret)
 		return ERR_PTR(ret);
 
+	GEM_BUG_ON(obj->pages == NULL);
 	i915_gem_object_pin_pages(obj);
 
-	if (!obj->mapping) {
-		obj->mapping = i915_gem_object_map(obj);
-		if (!obj->mapping) {
-			i915_gem_object_unpin_pages(obj);
-			return ERR_PTR(-ENOMEM);
+	pinned = obj->pages_pin_count > 1;
+	ptr = (void *)((uintptr_t)obj->mapping & ~1);
+	has_wc = (uintptr_t)obj->mapping & 1;
+
+	if (ptr && has_wc != use_wc) {
+		if (pinned) {
+			ret = -EBUSY;
+			goto err;
+		}
+
+		if (is_vmalloc_addr(ptr))
+			vunmap(ptr);
+		else
+			kunmap(kmap_to_page(ptr));
+		ptr = obj->mapping = NULL;
+	}
+
+	if (!ptr) {
+		ptr = i915_gem_object_map(obj, use_wc);
+		if (!ptr) {
+			ret = -ENOMEM;
+			goto err;
 		}
+
+		obj->mapping = (void *)((uintptr_t)ptr | use_wc);
 	}
 
-	return obj->mapping;
+	return ptr;
+
+err:
+	i915_gem_object_unpin_pages(obj);
+	return ERR_PTR(ret);
 }
 
 void i915_vma_move_to_active(struct i915_vma *vma,
diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
index 80bbe43..edcadce 100644
--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
@@ -115,7 +115,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
 	if (ret)
 		return ERR_PTR(ret);
 
-	addr = i915_gem_object_pin_map(obj);
+	addr = i915_gem_object_pin_map(obj, false);
 	mutex_unlock(&dev->struct_mutex);
 
 	return addr;
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 009d7c0..c468619 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -1096,7 +1096,7 @@ static int guc_create_log_extras(struct intel_guc *guc)
 
 	if (!guc->log.buf_addr) {
 		/* Create a vmalloc mapping of log buffer pages */
-		vaddr = i915_gem_object_pin_map(guc->log.obj);
+		vaddr = i915_gem_object_pin_map(guc->log.obj, false);
 		if (IS_ERR(vaddr)) {
 			ret = PTR_ERR(vaddr);
 			DRM_ERROR("Couldn't map log buffer pages %d\n", ret);
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 70c6990..0d41047 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -971,7 +971,7 @@ static int intel_lr_context_pin(struct i915_gem_context *ctx,
 	if (ret)
 		goto err;
 
-	vaddr = i915_gem_object_pin_map(ce->state);
+	vaddr = i915_gem_object_pin_map(ce->state, false);
 	if (IS_ERR(vaddr)) {
 		ret = PTR_ERR(vaddr);
 		goto unpin_ctx_obj;
@@ -1993,7 +1993,7 @@ lrc_setup_hws(struct intel_engine_cs *engine,
 	/* The HWSP is part of the default context object in LRC mode. */
 	engine->status_page.gfx_addr = i915_gem_obj_ggtt_offset(dctx_obj) +
 				       LRC_PPHWSP_PN * PAGE_SIZE;
-	hws = i915_gem_object_pin_map(dctx_obj);
+	hws = i915_gem_object_pin_map(dctx_obj, false);
 	if (IS_ERR(hws))
 		return PTR_ERR(hws);
 	engine->status_page.page_addr = hws + LRC_PPHWSP_PN * PAGE_SIZE;
@@ -2324,7 +2324,7 @@ populate_lr_context(struct i915_gem_context *ctx,
 		return ret;
 	}
 
-	vaddr = i915_gem_object_pin_map(ctx_obj);
+	vaddr = i915_gem_object_pin_map(ctx_obj, false);
 	if (IS_ERR(vaddr)) {
 		ret = PTR_ERR(vaddr);
 		DRM_DEBUG_DRIVER("Could not map object pages! (%d)\n", ret);
@@ -2558,7 +2558,7 @@ void intel_lr_context_reset(struct drm_i915_private *dev_priv,
 		if (!ctx_obj)
 			continue;
 
-		vaddr = i915_gem_object_pin_map(ctx_obj);
+		vaddr = i915_gem_object_pin_map(ctx_obj, false);
 		if (WARN_ON(IS_ERR(vaddr)))
 			continue;
 
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 736ddba..a195f65 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -2007,7 +2007,7 @@ int intel_pin_and_map_ringbuffer_obj(struct drm_i915_private *dev_priv,
 		if (ret)
 			goto err_unpin;
 
-		addr = i915_gem_object_pin_map(obj);
+		addr = i915_gem_object_pin_map(obj, false);
 		if (IS_ERR(addr)) {
 			ret = PTR_ERR(addr);
 			goto err_unpin;
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 12/17] drm/i915: Use uncached(WC) mapping for acessing the GuC log buffer
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (10 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 11/17] drm/i915: Support to create write combined type vmaps akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-10 13:41 ` [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions akash.goel
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Akash Goel <akash.goel@intel.com>

Host needs to sample the GuC log buffer on every flush interrupt from GuC.
To ensure that we always get the up-to-date data from log buffer, its
better to access the buffer through an uncached CPU mapping. Also the way
buffer is accessed from GuC & Host side, manually doing cache flush may
not be effective always if cached CPU mapping is used.
Though there could be some performance implication with Uncached read, but
reliability of data will be ensured.

v2: Rebase.

Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index c468619..6043166 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -934,8 +934,6 @@ static void guc_read_update_log_buffer(struct drm_device *dev)
 			dst_data_ptr += buffer_size;
 		}
 
-		/* FIXME: invalidate/flush for log buffer needed */
-
 		/* Update the read pointer in the shared log buffer */
 		log_buffer_state->read_ptr =
 			log_buffer_state_local.sampled_write_ptr;
@@ -1095,8 +1093,11 @@ static int guc_create_log_extras(struct intel_guc *guc)
 		return 0;
 
 	if (!guc->log.buf_addr) {
-		/* Create a vmalloc mapping of log buffer pages */
-		vaddr = i915_gem_object_pin_map(guc->log.obj, false);
+		/* Create a WC (Uncached for read) vmalloc mapping of log
+		 * buffer pages, so that we can directly get the data
+		 * (up-to-date) from memory.
+		 */
+		vaddr = i915_gem_object_pin_map(guc->log.obj, true);
 		if (IS_ERR(vaddr)) {
 			ret = PTR_ERR(vaddr);
 			DRM_ERROR("Couldn't map log buffer pages %d\n", ret);
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (11 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 12/17] drm/i915: Use uncached(WC) mapping for acessing the GuC log buffer akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-15 11:40   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts akash.goel
                   ` (4 subsequent siblings)
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Akash Goel <akash.goel@intel.com>

With the addition of new Host2GuC actions related to GuC logging, there
is a need of a lock to serialize them, as they can execute concurrently
with each other and also with other existing actions.

Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 3 +++
 drivers/gpu/drm/i915/intel_guc.h           | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 6043166..c1e637f 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -88,6 +88,7 @@ static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
 		return -EINVAL;
 
 	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+	spin_lock(&guc->action_lock);
 
 	dev_priv->guc.action_count += 1;
 	dev_priv->guc.action_cmd = data[0];
@@ -126,6 +127,7 @@ static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
 	}
 	dev_priv->guc.action_status = status;
 
+	spin_unlock(&guc->action_lock);
 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 
 	return ret;
@@ -1304,6 +1306,7 @@ int i915_guc_submission_init(struct drm_i915_private *dev_priv)
 		return -ENOMEM;
 
 	ida_init(&guc->ctx_ids);
+	spin_lock_init(&guc->action_lock);
 	guc_create_log(guc);
 	guc_create_ads(guc);
 
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index d56bde6..611f4a7 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -157,6 +157,9 @@ struct intel_guc {
 
 	uint64_t submissions[I915_NUM_ENGINES];
 	uint32_t last_seqno[I915_NUM_ENGINES];
+
+	/* To serialize the Host2GuC actions */
+	spinlock_t action_lock;
 };
 
 /* intel_guc_loader.c */
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (12 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-15 11:51   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce " akash.goel
                   ` (3 subsequent siblings)
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Akash Goel <akash.goel@intel.com>

GuC firmware sends an interrupt to flush the log buffer when it
becomes half full. GuC firmware also tracks how many times the
buffer overflowed.
It would be useful to maintain a statistics of how many flush
interrupts were received and for which type of log buffer,
along with the overflow count of each buffer type.
Augmented i915_log_info debugfs to report back these statistics.

Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c        | 26 ++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_guc_submission.c |  8 ++++++++
 drivers/gpu/drm/i915/i915_irq.c            |  1 +
 drivers/gpu/drm/i915/intel_guc.h           |  6 ++++++
 4 files changed, 41 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 3c9c7f7..888a18a 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2538,6 +2538,30 @@ static int i915_guc_load_status_info(struct seq_file *m, void *data)
 	return 0;
 }
 
+static void i915_guc_log_info(struct seq_file *m,
+				 struct drm_i915_private *dev_priv)
+{
+	struct intel_guc *guc = &dev_priv->guc;
+
+	seq_printf(m, "\nGuC logging stats:\n");
+
+	seq_printf(m, "\tISR:   flush count %10u, overflow count %8u\n",
+		guc->log.flush_count[GUC_ISR_LOG_BUFFER],
+		guc->log.total_overflow_count[GUC_ISR_LOG_BUFFER]);
+
+	seq_printf(m, "\tDPC:   flush count %10u, overflow count %8u\n",
+		guc->log.flush_count[GUC_DPC_LOG_BUFFER],
+		guc->log.total_overflow_count[GUC_DPC_LOG_BUFFER]);
+
+	seq_printf(m, "\tCRASH: flush count %10u, overflow count %8u\n",
+		guc->log.flush_count[GUC_CRASH_DUMP_LOG_BUFFER],
+		guc->log.total_overflow_count[GUC_CRASH_DUMP_LOG_BUFFER]);
+
+	seq_printf(m, "\tTotal flush interrupt count: %u\n",
+			guc->log.flush_interrupt_count);
+
+}
+
 static void i915_guc_client_info(struct seq_file *m,
 				 struct drm_i915_private *dev_priv,
 				 struct i915_guc_client *client)
@@ -2611,6 +2635,8 @@ static int i915_guc_info(struct seq_file *m, void *data)
 	seq_printf(m, "\nGuC execbuf client @ %p:\n", guc.execbuf_client);
 	i915_guc_client_info(m, dev_priv, &client);
 
+	i915_guc_log_info(m, dev_priv);
+
 	/* Add more as required ... */
 
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index c1e637f..9c94a43 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -914,6 +914,14 @@ static void guc_read_update_log_buffer(struct drm_device *dev)
 		log_buffer_state_local = *log_buffer_state;
 		buffer_size = log_buffer_state_local.size;
 
+		guc->log.flush_count[i] += log_buffer_state_local.flush_to_file;
+		if (log_buffer_state_local.buffer_full_cnt !=
+					guc->log.prev_overflow_count[i]) {
+			guc->log.prev_overflow_count[i] =
+					log_buffer_state_local.buffer_full_cnt;
+			guc->log.total_overflow_count[i]++;
+		}
+
 		if (log_buffer_copy_state) {
 			/* First copy the state structure */
 			memcpy(log_buffer_copy_state, &log_buffer_state_local,
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index bdd7a67..c3fb67e 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1711,6 +1711,7 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
 						&dev_priv->guc.events_work);
 			}
 		}
+		dev_priv->guc.log.flush_interrupt_count++;
 		spin_unlock(&dev_priv->irq_lock);
 	}
 }
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 611f4a7..e911a32 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -128,6 +128,12 @@ struct intel_guc_log {
 	struct workqueue_struct *wq;
 	void *buf_addr;
 	struct rchan *relay_chan;
+
+	/* logging related stats */
+	u32 flush_interrupt_count;
+	u32 prev_overflow_count[GUC_MAX_LOG_BUFFER];
+	u32 total_overflow_count[GUC_MAX_LOG_BUFFER];
+	u32 flush_count[GUC_MAX_LOG_BUFFER];
 };
 
 struct intel_guc {
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce flush interrupts
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (13 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-15 11:57   ` Tvrtko Ursulin
  2016-07-10 13:41 ` [PATCH 16/17] drm/i915: Optimization to reduce the sampling time of GuC log buffer akash.goel
                   ` (2 subsequent siblings)
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Akash Goel <akash.goel@intel.com>

In cases where GuC generate logs at a very high rate, correspondingly
the rate of flush interrupts is also very high.
So far total 8 pages were allocated for storing both ISR & DPC logs.
As per the half-full draining protocol followed by GuC, by doubling
the number of pages, the frequency of flush interrupts can be cut down
to almost half, which then helps in reducing the logging overhead.
So now allocating 8 pages apiece for ISR & DPC logs.

Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/intel_guc_fwif.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
index 1de6928..7521ed5 100644
--- a/drivers/gpu/drm/i915/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
@@ -104,9 +104,9 @@
 #define   GUC_LOG_ALLOC_IN_MEGABYTE	(1 << 3)
 #define   GUC_LOG_CRASH_PAGES		1
 #define   GUC_LOG_CRASH_SHIFT		4
-#define   GUC_LOG_DPC_PAGES		3
+#define   GUC_LOG_DPC_PAGES		7
 #define   GUC_LOG_DPC_SHIFT		6
-#define   GUC_LOG_ISR_PAGES		3
+#define   GUC_LOG_ISR_PAGES		7
 #define   GUC_LOG_ISR_SHIFT		9
 #define   GUC_LOG_BUF_ADDR_SHIFT	12
 
@@ -436,9 +436,9 @@ enum guc_log_buffer_type {
  *        |   Crash dump state header     |
  * Page1  +-------------------------------+
  *        |           ISR logs            |
- * Page5  +-------------------------------+
- *        |           DPC logs            |
  * Page9  +-------------------------------+
+ *        |           DPC logs            |
+ * Page17 +-------------------------------+
  *        |         Crash Dump logs       |
  *        +-------------------------------+
  *
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 16/17] drm/i915: Optimization to reduce the sampling time of GuC log buffer
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (14 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce " akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-10 13:41 ` [PATCH 17/17] drm/i915: Use rt priority kthread to do GuC log buffer sampling akash.goel
  2016-07-10 14:12 ` ✗ Ro.CI.BAT: failure for Support for sustained capturing of GuC firmware logs (rev5) Patchwork
  17 siblings, 0 replies; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Akash Goel <akash.goel@intel.com>

GuC firmware sends an interrupt to flush the log buffer when it becomes
half full, so Driver doesn't really need to sample the complete buffer
and can just copy only the newly written data by GuC into the local
buffer, i.e. as per the read & write pointer values.
Moreover the flush interrupt would generally come for one type of log
buffer, when it becomes half full, so at that time the other 2 types of
log buffer would comparatively have much lesser unread data in them.
In case of overflow reported by GuC, Driver do need to copy the entire
buffer as the whole buffer would contain the unread data.

Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 41 +++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 9c94a43..067eb52 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -896,7 +896,8 @@ static void guc_read_update_log_buffer(struct drm_device *dev)
 	struct guc_log_buffer_state *log_buffer_state, *log_buffer_copy_state;
 	struct guc_log_buffer_state log_buffer_state_local;
 	void *src_data_ptr, *dst_data_ptr;
-	u32 i, buffer_size;
+	bool new_overflow;
+	u32 i, buffer_size, read_offset, write_offset, bytes_to_copy;
 
 	if (!guc->log.obj || !guc->log.buf_addr)
 		return;
@@ -913,14 +914,18 @@ static void guc_read_update_log_buffer(struct drm_device *dev)
 	for (i = 0; i < GUC_MAX_LOG_BUFFER; i++) {
 		log_buffer_state_local = *log_buffer_state;
 		buffer_size = log_buffer_state_local.size;
+		read_offset = log_buffer_state_local.read_ptr;
+		write_offset = log_buffer_state_local.sampled_write_ptr;
 
 		guc->log.flush_count[i] += log_buffer_state_local.flush_to_file;
 		if (log_buffer_state_local.buffer_full_cnt !=
 					guc->log.prev_overflow_count[i]) {
+			new_overflow = 1;
 			guc->log.prev_overflow_count[i] =
 					log_buffer_state_local.buffer_full_cnt;
 			guc->log.total_overflow_count[i]++;
-		}
+		} else
+			new_overflow = 0;
 
 		if (log_buffer_copy_state) {
 			/* First copy the state structure */
@@ -932,21 +937,43 @@ static void guc_read_update_log_buffer(struct drm_device *dev)
 			 * for consistency set the write pointer value to same
 			 * value of sampled_write_ptr in the snapshot buffer.
 			 */
-			log_buffer_copy_state->write_ptr =
-				log_buffer_copy_state->sampled_write_ptr;
+			log_buffer_copy_state->write_ptr = write_offset;
 
 			log_buffer_copy_state++;
 
 			/* Now copy the actual logs */
-			memcpy(dst_data_ptr, src_data_ptr, buffer_size);
+			if (unlikely(new_overflow)) {
+				/* copy the whole buffer in case of overflow */
+				read_offset = 0;
+				write_offset = buffer_size;
+			} else if (unlikely((read_offset > buffer_size) ||
+					    (write_offset > buffer_size))) {
+				DRM_ERROR("invalid log buffer state\n");
+				/* copy whole buffer as offsets are unreliable */
+				read_offset = 0;
+				write_offset = buffer_size;
+			}
+
+			/* Just copy the new data */
+			if (read_offset <= write_offset) {
+				bytes_to_copy = write_offset - read_offset;
+				memcpy(dst_data_ptr + read_offset,
+				     src_data_ptr + read_offset, bytes_to_copy);
+			} else {
+				bytes_to_copy = buffer_size - read_offset;
+				memcpy(dst_data_ptr + read_offset,
+				     src_data_ptr + read_offset, bytes_to_copy);
+
+				bytes_to_copy = write_offset;
+				memcpy(dst_data_ptr, src_data_ptr, bytes_to_copy);
+			}
 
 			src_data_ptr += buffer_size;
 			dst_data_ptr += buffer_size;
 		}
 
 		/* Update the read pointer in the shared log buffer */
-		log_buffer_state->read_ptr =
-			log_buffer_state_local.sampled_write_ptr;
+		log_buffer_state->read_ptr = write_offset;
 
 		/* Clear the 'flush to file' flag */
 		log_buffer_state->flush_to_file = 0;
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 17/17] drm/i915: Use rt priority kthread to do GuC log buffer sampling
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (15 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 16/17] drm/i915: Optimization to reduce the sampling time of GuC log buffer akash.goel
@ 2016-07-10 13:41 ` akash.goel
  2016-07-20 19:34   ` Chris Wilson
  2016-07-10 14:12 ` ✗ Ro.CI.BAT: failure for Support for sustained capturing of GuC firmware logs (rev5) Patchwork
  17 siblings, 1 reply; 87+ messages in thread
From: akash.goel @ 2016-07-10 13:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Akash Goel

From: Akash Goel <akash.goel@intel.com>

In cases where GuC firmware generates logs at a very high rate, Driver too
needs to be fast enough to sample the log buffer in time for the half-full
draining protocol to be effective and prevent any overflows of log buffer.
So the scheduling latency of bottom half, where sampling is done, should be
kept to lowest and for that having a dedicated high priority rt kthread is a
better option compared to a dedicated high priority workqueue.
The behavior would be more deterministic with a dedicated high priority rt
kthread, compared to worker threads which could have to cater to work items
from other workqueues.
Also optimization on Driver side alone will not ensure lossless capture of
logs, under high speed logging, Userpsace should also be equally fast in
collecting the logs from relay buffer.

Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Akash Goel <akash.goel@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.c            | 13 -----
 drivers/gpu/drm/i915/i915_guc_submission.c | 76 ++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/i915_irq.c            | 24 ++--------
 drivers/gpu/drm/i915/intel_guc.h           |  5 +-
 4 files changed, 80 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 43c9900..ed00192 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -791,20 +791,8 @@ static int i915_workqueues_init(struct drm_i915_private *dev_priv)
 	if (dev_priv->hotplug.dp_wq == NULL)
 		goto out_free_wq;
 
-	if (HAS_GUC_SCHED(dev_priv)) {
-		/* Need a dedicated wq to process log buffer flush interrupts
-		 * from GuC without much delay so as to avoid any loss of logs.
-		 */
-		dev_priv->guc.log.wq =
-			alloc_ordered_workqueue("i915-guc_log", 0);
-		if (dev_priv->guc.log.wq == NULL)
-			goto out_free_hotplug_dp_wq;
-	}
-
 	return 0;
 
-out_free_hotplug_dp_wq:
-	destroy_workqueue(dev_priv->hotplug.dp_wq);
 out_free_wq:
 	destroy_workqueue(dev_priv->wq);
 out_err:
@@ -815,7 +803,6 @@ out_err:
 
 static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv)
 {
-	destroy_workqueue(dev_priv->guc.log.wq);
 	destroy_workqueue(dev_priv->hotplug.dp_wq);
 	destroy_workqueue(dev_priv->wq);
 }
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index 067eb52..0093240 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -21,6 +21,7 @@
  * IN THE SOFTWARE.
  *
  */
+#include <linux/kthread.h>
 #include <linux/firmware.h>
 #include <linux/circ_buf.h>
 #include <linux/debugfs.h>
@@ -1096,6 +1097,48 @@ static int guc_create_log_relay_file(struct intel_guc *guc)
 	return 0;
 }
 
+void guc_cancel_log_flush_work_sync(struct drm_i915_private *dev_priv)
+{
+	spin_lock_irq(&dev_priv->irq_lock);
+	dev_priv->guc.log.flush_signal = false;
+	spin_unlock_irq(&dev_priv->irq_lock);
+
+	if (dev_priv->guc.log.flush_task)
+		wait_for_completion(&dev_priv->guc.log.flush_completion);
+}
+
+static int guc_log_flush_worker(void *arg)
+{
+	struct drm_i915_private *dev_priv = arg;
+	struct intel_guc *guc = &dev_priv->guc;
+
+	/* Install ourselves with high priority to reduce signalling latency */
+	struct sched_param param = { .sched_priority = 1 };
+	sched_setscheduler_nocheck(current, SCHED_FIFO, &param);
+
+	do {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irq(&dev_priv->irq_lock);
+		if (guc->log.flush_signal) {
+			guc->log.flush_signal = false;
+			reinit_completion(&guc->log.flush_completion);
+			spin_unlock_irq(&dev_priv->irq_lock);
+			i915_guc_capture_logs(&dev_priv->drm);
+			complete_all(&guc->log.flush_completion);
+		} else {
+			spin_unlock_irq(&dev_priv->irq_lock);
+			if (kthread_should_stop())
+				break;
+
+			schedule();
+		}
+	} while (1);
+	__set_current_state(TASK_RUNNING);
+
+	return 0;
+}
+
 static void guc_log_cleanup(struct drm_i915_private *dev_priv)
 {
 	struct intel_guc *guc = &dev_priv->guc;
@@ -1108,6 +1151,11 @@ static void guc_log_cleanup(struct drm_i915_private *dev_priv)
 	/* First disable the flush interrupt */
 	gen9_disable_guc_interrupts(dev_priv);
 
+	if (guc->log.flush_task)
+		kthread_stop(guc->log.flush_task);
+
+	guc->log.flush_task = NULL;
+
 	guc_remove_log_relay_file(guc);
 	guc->log.relay_chan = NULL;
 
@@ -1120,6 +1168,7 @@ static void guc_log_cleanup(struct drm_i915_private *dev_priv)
 static int guc_create_log_extras(struct intel_guc *guc)
 {
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	struct task_struct *tsk;
 	void *vaddr;
 	int ret;
 
@@ -1144,6 +1193,23 @@ static int guc_create_log_extras(struct intel_guc *guc)
 		guc->log.buf_addr = vaddr;
 	}
 
+	if (!guc->log.flush_task) {
+		init_completion(&guc->log.flush_completion);
+		/* Spawn a thread to provide a fast bottom-half for handling log
+		 * buffer flush interrupts.
+		 */
+		tsk = kthread_run(guc_log_flush_worker, dev_priv,
+					"i915/guc_log_flushd");
+		if (IS_ERR(tsk)) {
+			ret = PTR_ERR(tsk);
+			DRM_ERROR("creation of log flush task failed %d\n", ret);
+			guc_log_cleanup(dev_priv);
+			return ret;
+		}
+
+		guc->log.flush_task = tsk;
+	}
+
 	return 0;
 }
 
@@ -1206,8 +1272,9 @@ static int guc_log_late_setup(struct drm_device *dev)
 	if (WARN_ON(guc->log.relay_chan))
 		return -EINVAL;
 
-	/* If log_level was set as -1 at boot time, then vmalloc mapping would
-	 * not have been created for the log buffer, so create one now.
+	/* If log_level was set as -1 at boot time, then vmalloc mapping and
+	 * flush daemon would not have been created for the log buffer, so
+	 * create one now.
 	 */
 	ret = guc_create_log_extras(guc);
 	if (ret)
@@ -1474,6 +1541,9 @@ void i915_guc_capture_logs_on_reset(struct drm_device *dev)
 	/* First disable the interrupts, will be renabled after reset */
 	gen9_disable_guc_interrupts(dev_priv);
 
+	/* Wait for the ongoing flush, if any, to complete */
+	guc_cancel_log_flush_work_sync(dev_priv);
+
 	/* Ask GuC to update the log buffer state */
 	host2guc_force_logbuffer_flush(&dev_priv->guc);
 
@@ -1544,7 +1614,7 @@ int i915_guc_log_control(struct drm_device *dev, uint64_t control_val)
 		 * buffer state and send the flush interrupt so that Host can
 		 * collect the left over logs also.
 		 */
-		flush_work(&dev_priv->guc.events_work);
+		guc_cancel_log_flush_work_sync(dev_priv);
 		host2guc_force_logbuffer_flush(&dev_priv->guc);
 	}
 
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index c3fb67e..0b6991e 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -435,13 +435,14 @@ void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv)
 {
 	spin_lock_irq(&dev_priv->irq_lock);
 	dev_priv->guc.interrupts_enabled = false;
+	/* Speed up cancellation after disabling interrupts */
+	dev_priv->guc.log.flush_signal = false;
 
 	gen6_disable_pm_irq(dev_priv, dev_priv->pm_guc_events);
 
 	spin_unlock_irq(&dev_priv->irq_lock);
 	synchronize_irq(dev_priv->drm.irq);
 
-	cancel_work_sync(&dev_priv->guc.events_work);
 	gen9_reset_guc_interrupts(dev_priv);
 }
 
@@ -1208,22 +1209,6 @@ static void gen6_pm_rps_work(struct work_struct *work)
 	mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
-static void gen9_guc2host_events_work(struct work_struct *work)
-{
-	struct drm_i915_private *dev_priv =
-		container_of(work, struct drm_i915_private, guc.events_work);
-
-	spin_lock_irq(&dev_priv->irq_lock);
-	/* Speed up work cancellation during disabling guc interrupts. */
-	if (!dev_priv->guc.interrupts_enabled) {
-		spin_unlock_irq(&dev_priv->irq_lock);
-		return;
-	}
-	spin_unlock_irq(&dev_priv->irq_lock);
-
-	i915_guc_capture_logs(&dev_priv->drm);
-}
-
 /**
  * ivybridge_parity_work - Workqueue called when a parity error interrupt
  * occurred.
@@ -1707,8 +1692,8 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
 					I915_READ(SOFT_SCRATCH(15)) & ~msg);
 
 				/* Handle flush interrupt event in bottom half */
-				queue_work(dev_priv->guc.log.wq,
-						&dev_priv->guc.events_work);
+				smp_store_mb(dev_priv->guc.log.flush_signal, 1);
+				wake_up_process(dev_priv->guc.log.flush_task);
 			}
 		}
 		dev_priv->guc.log.flush_interrupt_count++;
@@ -4629,7 +4614,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
 
 	INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
 	INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
-	INIT_WORK(&dev_priv->guc.events_work, gen9_guc2host_events_work);
 
 	if (HAS_GUC_UCODE(dev))
 		dev_priv->pm_guc_events = GEN9_GUC_TO_HOST_INT_EVENT;
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index e911a32..70c2241 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -125,9 +125,11 @@ struct intel_guc_fw {
 struct intel_guc_log {
 	uint32_t flags;
 	struct drm_i915_gem_object *obj;
-	struct workqueue_struct *wq;
 	void *buf_addr;
 	struct rchan *relay_chan;
+	struct task_struct *flush_task;
+	struct completion flush_completion;
+	bool flush_signal;
 
 	/* logging related stats */
 	u32 flush_interrupt_count;
@@ -141,7 +143,6 @@ struct intel_guc {
 	struct intel_guc_log log;
 
 	/* GuC2Host interrupt related state */
-	struct work_struct events_work;
 	bool interrupts_enabled;
 
 	struct drm_i915_gem_object *ads_obj;
-- 
1.9.2

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

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* ✗ Ro.CI.BAT: failure for Support for sustained capturing of GuC firmware logs (rev5)
  2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
                   ` (16 preceding siblings ...)
  2016-07-10 13:41 ` [PATCH 17/17] drm/i915: Use rt priority kthread to do GuC log buffer sampling akash.goel
@ 2016-07-10 14:12 ` Patchwork
  17 siblings, 0 replies; 87+ messages in thread
From: Patchwork @ 2016-07-10 14:12 UTC (permalink / raw)
  To: Akash Goel; +Cc: intel-gfx

== Series Details ==

Series: Support for sustained capturing of GuC firmware logs (rev5)
URL   : https://patchwork.freedesktop.org/series/7910/
State : failure

== Summary ==

Series 7910v5 Support for sustained capturing of GuC firmware logs
http://patchwork.freedesktop.org/api/1.0/series/7910/revisions/5/mbox

Test gem_sync:
        Subgroup basic-all:
                pass       -> FAIL       (ro-hsw-i7-4770r)
        Subgroup basic-store-all:
                pass       -> FAIL       (ro-hsw-i7-4770r)
                pass       -> FAIL       (ro-hsw-i3-4010u)
        Subgroup basic-store-each:
                fail       -> DMESG-FAIL (ro-bdw-i7-5600u)
Test kms_flip:
        Subgroup basic-flip-vs-wf_vblank:
                fail       -> PASS       (ro-hsw-i7-4770r)
Test kms_pipe_crc_basic:
        Subgroup suspend-read-crc-pipe-b:
                skip       -> DMESG-WARN (ro-bdw-i7-5557U)

fi-kbl-qkkr      total:237  pass:168  dwarn:28  dfail:2   fail:5   skip:34 
fi-skl-i5-6260u  total:237  pass:212  dwarn:0   dfail:1   fail:4   skip:20 
fi-skl-i7-6700k  total:237  pass:198  dwarn:0   dfail:1   fail:4   skip:34 
fi-snb-i7-2600   total:237  pass:184  dwarn:0   dfail:1   fail:4   skip:48 
ro-bdw-i5-5250u  total:237  pass:207  dwarn:1   dfail:1   fail:4   skip:24 
ro-bdw-i7-5557U  total:237  pass:207  dwarn:2   dfail:1   fail:4   skip:23 
ro-bdw-i7-5600u  total:237  pass:192  dwarn:0   dfail:2   fail:4   skip:39 
ro-bsw-n3050     total:237  pass:170  dwarn:0   dfail:0   fail:4   skip:42 
ro-byt-n2820     total:237  pass:183  dwarn:0   dfail:1   fail:7   skip:46 
ro-hsw-i3-4010u  total:237  pass:199  dwarn:0   dfail:1   fail:5   skip:32 
ro-hsw-i7-4770r  total:237  pass:198  dwarn:0   dfail:1   fail:6   skip:32 
ro-ilk-i7-620lm  total:237  pass:160  dwarn:0   dfail:1   fail:5   skip:71 
ro-ilk1-i5-650   total:232  pass:160  dwarn:0   dfail:1   fail:5   skip:66 
ro-ivb-i7-3770   total:237  pass:191  dwarn:0   dfail:1   fail:4   skip:41 
ro-skl3-i5-6260u total:237  pass:211  dwarn:1   dfail:1   fail:4   skip:20 
ro-snb-i7-2620M  total:237  pass:182  dwarn:0   dfail:1   fail:5   skip:49 

Results at /archive/results/CI_IGT_test/RO_Patchwork_1462/

0230e3c drm-intel-nightly: 2016y-07m-10d-12h-23m-38s UTC integration manifest
5b05f2d drm/i915: Use rt priority kthread to do GuC log buffer sampling
15a26b2 drm/i915: Optimization to reduce the sampling time of GuC log buffer
e1d8923 drm/i915: Increase GuC log buffer size to reduce flush interrupts
ade9783 drm/i915: Add stats for GuC log buffer flush interrupts
9474de3 drm/i915: New lock to serialize the Host2GuC actions
658b0e7 drm/i915: Use uncached(WC) mapping for acessing the GuC log buffer
7ed44fa drm/i915: Support to create write combined type vmaps
48733bb drm/i915: New module param to control the size of buffer used for storing GuC firmware logs
ac286a7 drm/i915: Debugfs support for GuC logging control
0cd099b drm/i915: Forcefully flush GuC log buffer on reset
92c182a drm/i915: Add a relay backed debugfs interface for capturing GuC logs
c851a6a drm/i915: Handle log buffer flush interrupt event from GuC
bd0ebfc drm/i915: Support for GuC interrupts
3964e5a drm/i915: Add low level set of routines for programming PM IER/IIR/IMR register set
949fa5b drm/i915: New structure to contain GuC logging related fields
d2bb131 drm/i915: Add GuC ukernel logging related fields to fw interface file
50235be drm/i915: Decouple GuC log setup from verbosity parameter

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 07/17] drm/i915: Add a relay backed debugfs interface for capturing GuC logs
  2016-07-10 13:41 ` [PATCH 07/17] drm/i915: Add a relay backed debugfs interface for capturing GuC logs akash.goel
@ 2016-07-10 17:07   ` kbuild test robot
  2016-07-19 11:31   ` Tvrtko Ursulin
  1 sibling, 0 replies; 87+ messages in thread
From: kbuild test robot @ 2016-07-10 17:07 UTC (permalink / raw)
  Cc: Akash Goel, intel-gfx, Sourab Gupta, kbuild-all

[-- Attachment #1: Type: text/plain, Size: 1630 bytes --]

Hi,

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

url:    https://github.com/0day-ci/linux/commits/akash-goel-intel-com/Support-for-sustained-capturing-of-GuC-firmware-logs/20160710-213134
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: x86_64-randconfig-s5-07102345 (attached as .config)
compiler: gcc-6 (Debian 6.1.1-1) 6.1.1 20160430
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   drivers/built-in.o: In function `relay_reserve':
>> i915_guc_submission.c:(.text+0x1db57e): undefined reference to `relay_switch_subbuf'
   drivers/built-in.o: In function `create_buf_file_callback':
   i915_guc_submission.c:(.text+0x1db5dc): undefined reference to `relay_file_operations'
   drivers/built-in.o: In function `subbuf_start_callback':
>> i915_guc_submission.c:(.text+0x1db5f8): undefined reference to `relay_buf_full'
   drivers/built-in.o: In function `guc_log_cleanup':
>> i915_guc_submission.c:(.text+0x1db6ec): undefined reference to `relay_close'
   drivers/built-in.o: In function `i915_guc_capture_logs':
>> (.text+0x1dcce4): undefined reference to `relay_flush'
   drivers/built-in.o: In function `i915_guc_register':
   (.text+0x1dcebd): undefined reference to `relay_open'

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

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 28971 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-10 13:41 ` [PATCH 09/17] drm/i915: Debugfs support for GuC logging control akash.goel
@ 2016-07-10 17:59   ` kbuild test robot
  2016-07-19 11:24   ` Tvrtko Ursulin
  1 sibling, 0 replies; 87+ messages in thread
From: kbuild test robot @ 2016-07-10 17:59 UTC (permalink / raw)
  Cc: Akash Goel, intel-gfx, kbuild-all

[-- Attachment #1: Type: text/plain, Size: 1653 bytes --]

Hi,

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

url:    https://github.com/0day-ci/linux/commits/akash-goel-intel-com/Support-for-sustained-capturing-of-GuC-firmware-logs/20160710-213134
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: x86_64-randconfig-s5-07102345 (attached as .config)
compiler: gcc-6 (Debian 6.1.1-1) 6.1.1 20160430
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   drivers/built-in.o: In function `relay_reserve':
   i915_guc_submission.c:(.text+0x1db624): undefined reference to `relay_switch_subbuf'
   drivers/built-in.o: In function `create_buf_file_callback':
   i915_guc_submission.c:(.text+0x1db682): undefined reference to `relay_file_operations'
   drivers/built-in.o: In function `subbuf_start_callback':
   i915_guc_submission.c:(.text+0x1db69e): undefined reference to `relay_buf_full'
   drivers/built-in.o: In function `guc_log_cleanup':
   i915_guc_submission.c:(.text+0x1db792): undefined reference to `relay_close'
   drivers/built-in.o: In function `guc_log_late_setup':
>> i915_guc_submission.c:(.text+0x1db9a4): undefined reference to `relay_open'
   drivers/built-in.o: In function `i915_guc_capture_logs':
   (.text+0x1dcf44): undefined reference to `relay_flush'

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

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 28971 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter
  2016-07-10 13:41 ` [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter akash.goel
@ 2016-07-11  9:37   ` Tvrtko Ursulin
  2016-07-11 11:41     ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-11  9:37 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>
> GuC Log buffer allocation was tied up with verbosity level module param
> i915.guc_log_level. User would be given a provision to enable firmware
> logging at runtime, through a host2guc action, and not necessarily during
> Driver load time. But the address of log buffer can be passed only in
> init params, at firmware load time, so GuC has to be reset and firmware
> needs to be reloaded to pass the log buffer address at runtime.
> To avoid reset of GuC & reload of firmware, allocation of log buffer will
> be done always but logging would be enabled initially on GuC side based on
> the value of module paramter guc_log_level.
>
> v2: Update commit message to describe the constraint with allocation of
>      log buffer at runtime. (Tvrtko)
>
> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 ---
>   drivers/gpu/drm/i915/intel_guc_loader.c    | 8 +++++---
>   2 files changed, 5 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index 2112e02..8a9a0cb 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -832,9 +832,6 @@ static void guc_create_log(struct intel_guc *guc)
>   	unsigned long offset;
>   	uint32_t size, flags;
>
> -	if (i915.guc_log_level < GUC_LOG_VERBOSITY_MIN)
> -		return;
> -
>   	if (i915.guc_log_level > GUC_LOG_VERBOSITY_MAX)
>   		i915.guc_log_level = GUC_LOG_VERBOSITY_MAX;
>
> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
> index 605c696..b211bd0 100644
> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> @@ -175,11 +175,13 @@ static void set_guc_init_params(struct drm_i915_private *dev_priv)
>   	params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
>   			GUC_CTL_VCS2_ENABLED;
>
> -	if (i915.guc_log_level >= 0) {
> -		params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
> +	params[GUC_CTL_LOG_PARAMS] = guc->log_flags;

guc->log_flags will be zero when logging is not configured because guc 
is a part of dev_priv. So it looks safe - although I reckon it would be 
clearer to set this (GUC_CTL_LOG_PARAMS) explicitly inside the if-else 
below?

> +
> +	if (i915.guc_log_level >= 0)
>   		params[GUC_CTL_DEBUG] =
>   			i915.guc_log_level << GUC_LOG_VERBOSITY_SHIFT;
> -	}
> +	else
> +		params[GUC_CTL_DEBUG] = GUC_LOG_DISABLED;

I also wonder how come GUC_LOG_DISABLED isn't set today when 
i915.guc_log_level == -1, given that:

#define   GUC_LOG_DISABLED             (1 << 6)

Is that bit set by default somehow if i915 does not program it?

>
>   	if (guc->ads_obj) {
>   		u32 ads = (u32)i915_gem_obj_ggtt_offset(guc->ads_obj)
>

Regards,

Tvrtko

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 04/17] drm/i915: Add low level set of routines for programming PM IER/IIR/IMR register set
  2016-07-10 13:41 ` [PATCH 04/17] drm/i915: Add low level set of routines for programming PM IER/IIR/IMR register set akash.goel
@ 2016-07-11 10:04   ` Tvrtko Ursulin
  0 siblings, 0 replies; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-11 10:04 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Akash Goel <akash.goel@intel.com>
>
> So far PM IER/IIR/IMR registers were being used only for Turbo related
> interrupts. But interrupts coming from GuC also use the same set.
> As a precursor to supporting GuC interrupts, added new low level routines
> so as to allow sharing the programming of PM IER/IIR/IMR registers between
> Turbo & GuC.
> Also similar to PM IMR, maintaining a bitmask for PM IER register, to allow
> easy sharing of it between Turbo & GuC without involving a rmw operation.
>
> v2:
> - For appropriateness & avoid any ambiguity, rename old functions
>    enable/disable pm_irq to mask/unmask pm_irq and rename new functions
>    enable/disable pm_interrupts to enable/disable pm_irq. (Tvrtko)
> - Use u32 in place of uint32_t. (Tvrtko)
>
> v3:
> - Rename the fields pm_irq_mask & pm_ier_mask and do some cleanup. (Chris)
> - Rebase.
>
> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_drv.h         |  3 +-
>   drivers/gpu/drm/i915/i915_irq.c         | 71 ++++++++++++++++++++++-----------
>   drivers/gpu/drm/i915/intel_drv.h        |  3 ++
>   drivers/gpu/drm/i915/intel_ringbuffer.c |  4 +-
>   4 files changed, 54 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 4478cc8..c3a579f 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1791,7 +1791,8 @@ struct drm_i915_private {
>   		u32 de_irq_mask[I915_MAX_PIPES];
>   	};
>   	u32 gt_irq_mask;
> -	u32 pm_irq_mask;
> +	u32 pm_imr;
> +	u32 pm_ier;
>   	u32 pm_rps_events;
>   	u32 pipestat_irq_mask[I915_MAX_PIPES];
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 1c2aec3..24bbaf7 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -303,18 +303,18 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
>
>   	assert_spin_locked(&dev_priv->irq_lock);
>
> -	new_val = dev_priv->pm_irq_mask;
> +	new_val = dev_priv->pm_imr;
>   	new_val &= ~interrupt_mask;
>   	new_val |= (~enabled_irq_mask & interrupt_mask);
>
> -	if (new_val != dev_priv->pm_irq_mask) {
> -		dev_priv->pm_irq_mask = new_val;
> -		I915_WRITE(gen6_pm_imr(dev_priv), dev_priv->pm_irq_mask);
> +	if (new_val != dev_priv->pm_imr) {
> +		dev_priv->pm_imr = new_val;
> +		I915_WRITE(gen6_pm_imr(dev_priv), dev_priv->pm_imr);
>   		POSTING_READ(gen6_pm_imr(dev_priv));
>   	}
>   }
>
> -void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
> +void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
>   {
>   	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
>   		return;
> @@ -322,28 +322,54 @@ void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
>   	snb_update_pm_irq(dev_priv, mask, mask);
>   }
>
> -static void __gen6_disable_pm_irq(struct drm_i915_private *dev_priv,
> -				  uint32_t mask)
> +static void __gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
>   {
>   	snb_update_pm_irq(dev_priv, mask, 0);
>   }
>
> -void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
> +void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
>   {
>   	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
>   		return;
>
> -	__gen6_disable_pm_irq(dev_priv, mask);
> +	__gen6_mask_pm_irq(dev_priv, mask);
>   }
>
> -void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv)
> +void gen6_reset_pm_iir(struct drm_i915_private *dev_priv, u32 reset_mask)
>   {
>   	i915_reg_t reg = gen6_pm_iir(dev_priv);
>
> -	spin_lock_irq(&dev_priv->irq_lock);
> -	I915_WRITE(reg, dev_priv->pm_rps_events);
> -	I915_WRITE(reg, dev_priv->pm_rps_events);
> +	assert_spin_locked(&dev_priv->irq_lock);
> +
> +	I915_WRITE(reg, reset_mask);
> +	I915_WRITE(reg, reset_mask);
>   	POSTING_READ(reg);
> +}
> +
> +void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, u32 enable_mask)
> +{
> +	assert_spin_locked(&dev_priv->irq_lock);
> +
> +	dev_priv->pm_ier |= enable_mask;
> +	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier);
> +	gen6_unmask_pm_irq(dev_priv, enable_mask);
> +	/* unmask_pm_irq provides an implicit barrier (POSTING_READ) */
> +}
> +
> +void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, u32 disable_mask)
> +{
> +	assert_spin_locked(&dev_priv->irq_lock);
> +
> +	dev_priv->pm_ier &= ~disable_mask;
> +	__gen6_mask_pm_irq(dev_priv, disable_mask);
> +	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier);
> +	/* though a barrier is missing here, but don't really need a one */
> +}
> +
> +void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv)
> +{
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	gen6_reset_pm_iir(dev_priv, dev_priv->pm_rps_events);
>   	dev_priv->rps.pm_iir = 0;
>   	spin_unlock_irq(&dev_priv->irq_lock);
>   }
> @@ -354,8 +380,6 @@ void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv)
>   	WARN_ON_ONCE(dev_priv->rps.pm_iir);
>   	WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events);
>   	dev_priv->rps.interrupts_enabled = true;
> -	I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) |
> -				dev_priv->pm_rps_events);
>   	gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
>
>   	spin_unlock_irq(&dev_priv->irq_lock);
> @@ -373,9 +397,7 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
>
>   	I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0));
>
> -	__gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> -	I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) &
> -				~dev_priv->pm_rps_events);
> +	gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
>
>   	spin_unlock_irq(&dev_priv->irq_lock);
>   	synchronize_irq(dev_priv->drm.irq);
> @@ -1086,7 +1108,7 @@ static void gen6_pm_rps_work(struct work_struct *work)
>   	pm_iir = dev_priv->rps.pm_iir;
>   	dev_priv->rps.pm_iir = 0;
>   	/* Make sure not to corrupt PMIMR state used by ringbuffer on GEN6 */
> -	gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> +	gen6_unmask_pm_irq(dev_priv, dev_priv->pm_rps_events);
>   	client_boost = dev_priv->rps.client_boost;
>   	dev_priv->rps.client_boost = false;
>   	spin_unlock_irq(&dev_priv->irq_lock);
> @@ -1586,7 +1608,7 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
>   {
>   	if (pm_iir & dev_priv->pm_rps_events) {
>   		spin_lock(&dev_priv->irq_lock);
> -		gen6_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
> +		gen6_mask_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
>   		if (dev_priv->rps.interrupts_enabled) {
>   			dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
>   			schedule_work(&dev_priv->rps.work);
> @@ -3605,8 +3627,8 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
>   		if (HAS_VEBOX(dev))
>   			pm_irqs |= PM_VEBOX_USER_INTERRUPT;
>
> -		dev_priv->pm_irq_mask = 0xffffffff;
> -		GEN5_IRQ_INIT(GEN6_PM, dev_priv->pm_irq_mask, pm_irqs);
> +		dev_priv->pm_imr = 0xffffffff;
> +		GEN5_IRQ_INIT(GEN6_PM, dev_priv->pm_imr, pm_irqs);
>   	}
>   }
>
> @@ -3726,14 +3748,15 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
>   	if (HAS_L3_DPF(dev_priv))
>   		gt_interrupts[0] |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
>
> -	dev_priv->pm_irq_mask = 0xffffffff;
> +	dev_priv->pm_ier = 0x0;
> +	dev_priv->pm_imr = ~dev_priv->pm_ier;
>   	GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
>   	GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
>   	/*
>   	 * RPS interrupts will get enabled/disabled on demand when RPS itself
>   	 * is enabled/disabled.
>   	 */
> -	GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, 0);
> +	GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier);
>   	GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
>   }
>
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 55aeaf0..ae6c535 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1077,6 +1077,9 @@ void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv);
>   /* i915_irq.c */
>   void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>   void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> +void gen6_reset_pm_iir(struct drm_i915_private *dev_priv, u32 mask);
> +void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask);
> +void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask);
>   void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>   void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>   void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv);
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 61e00bf..736ddba 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1741,7 +1741,7 @@ hsw_vebox_irq_enable(struct intel_engine_cs *engine)
>   	struct drm_i915_private *dev_priv = engine->i915;
>
>   	I915_WRITE_IMR(engine, ~engine->irq_enable_mask);
> -	gen6_enable_pm_irq(dev_priv, engine->irq_enable_mask);
> +	gen6_unmask_pm_irq(dev_priv, engine->irq_enable_mask);
>   }
>
>   static void
> @@ -1750,7 +1750,7 @@ hsw_vebox_irq_disable(struct intel_engine_cs *engine)
>   	struct drm_i915_private *dev_priv = engine->i915;
>
>   	I915_WRITE_IMR(engine, ~0);
> -	gen6_disable_pm_irq(dev_priv, engine->irq_enable_mask);
> +	gen6_mask_pm_irq(dev_priv, engine->irq_enable_mask);
>   }
>
>   static void
>

Looks OK.

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 05/17] drm/i915: Support for GuC interrupts
  2016-07-10 13:41 ` [PATCH 05/17] drm/i915: Support for GuC interrupts akash.goel
@ 2016-07-11 10:30   ` Tvrtko Ursulin
  2016-07-11 13:15     ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-11 10:30 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>
> There are certain types of interrupts which Host can recieve from GuC.
> GuC ukernel sends an interrupt to Host for certain events, like for
> example retrieve/consume the logs generated by ukernel.
> This patch adds support to receive interrupts from GuC but currently
> enables & partially handles only the interrupt sent by GuC ukernel.
> Future patches will add support for handling other interrupt types.
>
> v2:
> - Use common low level routines for PM IER/IIR programming (Chris)
> - Rename interrupt functions to gen9_xxx from gen8_xxx (Chris)
> - Replace disabling of wake ref asserts with rpm get/put (Chris)
>
> v3:
> - Update comments for more clarity. (Tvrtko)
> - Remove the masking of GuC interrupt, which was kept masked till the
>    start of bottom half, its not really needed as there is only a
>    single instance of work item & wq is ordered. (Tvrtko)
>
> v4:
> - Rebase.
> - Rename guc_events to pm_guc_events so as to be indicative of the
>    register/control block it is associated with. (Chris)
> - Add handling for back to back log buffer flush interrupts.
>
> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_drv.h            |  1 +
>   drivers/gpu/drm/i915/i915_guc_submission.c |  5 ++
>   drivers/gpu/drm/i915/i915_irq.c            | 98 ++++++++++++++++++++++++++++--
>   drivers/gpu/drm/i915/i915_reg.h            | 11 ++++
>   drivers/gpu/drm/i915/intel_drv.h           |  3 +
>   drivers/gpu/drm/i915/intel_guc.h           |  4 ++
>   drivers/gpu/drm/i915/intel_guc_loader.c    |  4 ++
>   7 files changed, 122 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index c3a579f..6e2ddfa 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1794,6 +1794,7 @@ struct drm_i915_private {
>   	u32 pm_imr;
>   	u32 pm_ier;
>   	u32 pm_rps_events;
> +	u32 pm_guc_events;
>   	u32 pipestat_irq_mask[I915_MAX_PIPES];
>
>   	struct i915_hotplug hotplug;
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index 0fb00ab..0bac172 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -1044,6 +1044,8 @@ int intel_guc_suspend(struct drm_device *dev)
>   	if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS)
>   		return 0;
>
> +	gen9_disable_guc_interrupts(dev_priv);
> +
>   	ctx = dev_priv->kernel_context;
>
>   	data[0] = HOST2GUC_ACTION_ENTER_S_STATE;
> @@ -1070,6 +1072,9 @@ int intel_guc_resume(struct drm_device *dev)
>   	if (guc->guc_fw.guc_fw_load_status != GUC_FIRMWARE_SUCCESS)
>   		return 0;
>
> +	if (i915.guc_log_level >= 0)
> +		gen9_enable_guc_interrupts(dev_priv);
> +
>   	ctx = dev_priv->kernel_context;
>
>   	data[0] = HOST2GUC_ACTION_EXIT_S_STATE;
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 24bbaf7..fd73c94 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -170,6 +170,7 @@ static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv,
>   } while (0)
>
>   static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
> +static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
>
>   /* For display hotplug interrupt */
>   static inline void
> @@ -411,6 +412,39 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
>   	gen6_reset_rps_interrupts(dev_priv);
>   }
>
> +void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv)
> +{
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	gen6_reset_pm_iir(dev_priv, dev_priv->pm_guc_events);
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +}
> +
> +void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv)
> +{
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	if (!dev_priv->guc.interrupts_enabled) {
> +		WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) &
> +						dev_priv->pm_guc_events);
> +		dev_priv->guc.interrupts_enabled = true;
> +		gen6_enable_pm_irq(dev_priv, dev_priv->pm_guc_events);
> +	}
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +}
> +
> +void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv)
> +{
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	dev_priv->guc.interrupts_enabled = false;
> +
> +	gen6_disable_pm_irq(dev_priv, dev_priv->pm_guc_events);
> +
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +	synchronize_irq(dev_priv->drm.irq);
> +
> +	cancel_work_sync(&dev_priv->guc.events_work);
> +	gen9_reset_guc_interrupts(dev_priv);
> +}
> +
>   /**
>    * bdw_update_port_irq - update DE port interrupt
>    * @dev_priv: driver private
> @@ -1174,6 +1208,21 @@ static void gen6_pm_rps_work(struct work_struct *work)
>   	mutex_unlock(&dev_priv->rps.hw_lock);
>   }
>
> +static void gen9_guc2host_events_work(struct work_struct *work)
> +{
> +	struct drm_i915_private *dev_priv =
> +		container_of(work, struct drm_i915_private, guc.events_work);
> +
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	/* Speed up work cancellation during disabling guc interrupts. */
> +	if (!dev_priv->guc.interrupts_enabled) {
> +		spin_unlock_irq(&dev_priv->irq_lock);
> +		return;
> +	}
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +
> +	/* TODO: Handle the events for which GuC interrupted host */
> +}
>
>   /**
>    * ivybridge_parity_work - Workqueue called when a parity error interrupt
> @@ -1346,11 +1395,13 @@ static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
>   			DRM_ERROR("The master control interrupt lied (GT3)!\n");
>   	}
>
> -	if (master_ctl & GEN8_GT_PM_IRQ) {
> +	if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
>   		gt_iir[2] = I915_READ_FW(GEN8_GT_IIR(2));
> -		if (gt_iir[2] & dev_priv->pm_rps_events) {
> +		if (gt_iir[2] & (dev_priv->pm_rps_events |
> +				 dev_priv->pm_guc_events)) {
>   			I915_WRITE_FW(GEN8_GT_IIR(2),
> -				      gt_iir[2] & dev_priv->pm_rps_events);
> +				      gt_iir[2] & (dev_priv->pm_rps_events |
> +						   dev_priv->pm_guc_events));
>   			ret = IRQ_HANDLED;
>   		} else
>   			DRM_ERROR("The master control interrupt lied (PM)!\n");
> @@ -1382,6 +1433,9 @@ static void gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
>
>   	if (gt_iir[2] & dev_priv->pm_rps_events)
>   		gen6_rps_irq_handler(dev_priv, gt_iir[2]);
> +
> +	if (gt_iir[2] & dev_priv->pm_guc_events)
> +		gen9_guc_irq_handler(dev_priv, gt_iir[2]);
>   }
>
>   static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
> @@ -1628,6 +1682,38 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
>   	}
>   }
>
> +static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
> +{
> +	if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) {
> +		spin_lock(&dev_priv->irq_lock);
> +		if (dev_priv->guc.interrupts_enabled) {
> +			/* Sample the log buffer flush related bits & clear them
> +			 * out now itself from the message identity register to
> +			 * minimize the probability of losing a flush interrupt,
> +			 * when there are back to back flush interrupts.
> +			 * There can be a new flush interrupt, for different log
> +			 * buffer type (like for ISR), whilst Host is handling
> +			 * one (for DPC). Since same bit is used in message
> +			 * register for ISR & DPC, it could happen that GuC
> +			 * sets the bit for 2nd interrupt but Host clears out
> +			 * the bit on handling the 1st interrupt.
> +			 */
> +			u32 msg = I915_READ(SOFT_SCRATCH(15)) &
> +					(GUC2HOST_MSG_CRASH_DUMP_POSTED |
> +					 GUC2HOST_MSG_FLUSH_LOG_BUFFER);
> +			if (msg) {
> +				/* Clear the message bits that are handled */
> +				I915_WRITE(SOFT_SCRATCH(15),
> +					I915_READ(SOFT_SCRATCH(15)) & ~msg);
> +
> +				/* Handle flush interrupt event in bottom half */
> +				queue_work(dev_priv->wq, &dev_priv->guc.events_work);

Since the later patch is changing this to use a thread, since you have 
established worker is too slow - especially the shared one - I would 
really recommend you start with the kthread straight away. Not have the 
worker for a while in the same series and then later change it to a thread.

> +			}
> +		}
> +		spin_unlock(&dev_priv->irq_lock);

Why does the above needs to be done under the irq_lock ?

> +	}
> +}
> +
>   static bool intel_pipe_handle_vblank(struct drm_i915_private *dev_priv,
>   				     enum pipe pipe)
>   {
> @@ -3754,7 +3840,7 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
>   	GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
>   	/*
>   	 * RPS interrupts will get enabled/disabled on demand when RPS itself
> -	 * is enabled/disabled.
> +	 * is enabled/disabled. Same wil be the case for GuC interrupts.
>   	 */
>   	GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier);
>   	GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
> @@ -4539,6 +4625,10 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
>
>   	INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
>   	INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
> +	INIT_WORK(&dev_priv->guc.events_work, gen9_guc2host_events_work);
> +
> +	if (HAS_GUC_UCODE(dev))
> +		dev_priv->pm_guc_events = GEN9_GUC_TO_HOST_INT_EVENT;
>
>   	/* Let's track the enabled rps events */
>   	if (IS_VALLEYVIEW(dev_priv))
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 8bfde75..d0d13a2 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -5963,6 +5963,7 @@ enum {
>   #define  GEN8_DE_PIPE_A_IRQ		(1<<16)
>   #define  GEN8_DE_PIPE_IRQ(pipe)		(1<<(16+(pipe)))
>   #define  GEN8_GT_VECS_IRQ		(1<<6)
> +#define  GEN8_GT_GUC_IRQ		(1<<5)
>   #define  GEN8_GT_PM_IRQ			(1<<4)
>   #define  GEN8_GT_VCS2_IRQ		(1<<3)
>   #define  GEN8_GT_VCS1_IRQ		(1<<2)
> @@ -5974,6 +5975,16 @@ enum {
>   #define GEN8_GT_IIR(which) _MMIO(0x44308 + (0x10 * (which)))
>   #define GEN8_GT_IER(which) _MMIO(0x4430c + (0x10 * (which)))
>
> +#define GEN9_GUC_TO_HOST_INT_EVENT	(1<<31)
> +#define GEN9_GUC_EXEC_ERROR_EVENT	(1<<30)
> +#define GEN9_GUC_DISPLAY_EVENT		(1<<29)
> +#define GEN9_GUC_SEMA_SIGNAL_EVENT	(1<<28)
> +#define GEN9_GUC_IOMMU_MSG_EVENT	(1<<27)
> +#define GEN9_GUC_DB_RING_EVENT		(1<<26)
> +#define GEN9_GUC_DMA_DONE_EVENT		(1<<25)
> +#define GEN9_GUC_FATAL_ERROR_EVENT	(1<<24)
> +#define GEN9_GUC_NOTIFICATION_EVENT	(1<<23)
> +
>   #define GEN8_RCS_IRQ_SHIFT 0
>   #define GEN8_BCS_IRQ_SHIFT 16
>   #define GEN8_VCS1_IRQ_SHIFT 0
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index ae6c535..6868f31 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1102,6 +1102,9 @@ void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
>   				     unsigned int pipe_mask);
>   void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
>   				     unsigned int pipe_mask);
> +void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv);
> +void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv);
> +void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv);
>
>   /* intel_crt.c */
>   void intel_crt_init(struct drm_device *dev);
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index d52eca3..2663b41 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -131,6 +131,10 @@ struct intel_guc {
>   	struct intel_guc_fw guc_fw;
>   	struct intel_guc_log log;
>
> +	/* GuC2Host interrupt related state */
> +	struct work_struct events_work;
> +	bool interrupts_enabled;
> +
>   	struct drm_i915_gem_object *ads_obj;
>
>   	struct drm_i915_gem_object *ctx_pool_obj;
> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
> index 4882f17..d74d7a5 100644
> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> @@ -450,6 +450,7 @@ int intel_guc_setup(struct drm_device *dev)
>   	}
>
>   	direct_interrupts_to_host(dev_priv);
> +	gen9_reset_guc_interrupts(dev_priv);
>
>   	guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING;
>
> @@ -496,6 +497,9 @@ int intel_guc_setup(struct drm_device *dev)
>   		intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
>
>   	if (i915.enable_guc_submission) {
> +		if (i915.guc_log_level >= 0)
> +			gen9_enable_guc_interrupts(dev_priv);
> +
>   		err = i915_guc_submission_enable(dev_priv);
>   		if (err)
>   			goto fail;
>

Regards,

Tvrtko

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter
  2016-07-11  9:37   ` Tvrtko Ursulin
@ 2016-07-11 11:41     ` Goel, Akash
  2016-07-11 11:50       ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-11 11:41 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/11/2016 3:07 PM, Tvrtko Ursulin wrote:
>
> On 10/07/16 14:41, akash.goel@intel.com wrote:
>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>
>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>> index 2112e02..8a9a0cb 100644
>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>> @@ -832,9 +832,6 @@ static void guc_create_log(struct intel_guc *guc)
>>       unsigned long offset;
>>       uint32_t size, flags;
>>
>> -    if (i915.guc_log_level < GUC_LOG_VERBOSITY_MIN)
>> -        return;
>> -
>>       if (i915.guc_log_level > GUC_LOG_VERBOSITY_MAX)
>>           i915.guc_log_level = GUC_LOG_VERBOSITY_MAX;
>>
>> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c
>> b/drivers/gpu/drm/i915/intel_guc_loader.c
>> index 605c696..b211bd0 100644
>> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
>> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
>> @@ -175,11 +175,13 @@ static void set_guc_init_params(struct
>> drm_i915_private *dev_priv)
>>       params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
>>               GUC_CTL_VCS2_ENABLED;
>>
>> -    if (i915.guc_log_level >= 0) {
>> -        params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
>> +    params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
>
> guc->log_flags will be zero when logging is not configured because guc
> is a part of dev_priv. So it looks safe - although I reckon it would be
> clearer to set this (GUC_CTL_LOG_PARAMS) explicitly inside the if-else
> below?

If logging is not enabled at (due to guc_log_level < 0), then also 
log_flags needs to be setup & passed to GuC firmware.
log_flags shall not be zero even when logging is not be enabled (at boot 
time).
Actually log_flags will also contain the address of the log buffer.

>
>> +
>> +    if (i915.guc_log_level >= 0)
>>           params[GUC_CTL_DEBUG] =
>>               i915.guc_log_level << GUC_LOG_VERBOSITY_SHIFT;
>> -    }
>> +    else
>> +        params[GUC_CTL_DEBUG] = GUC_LOG_DISABLED;
>
> I also wonder how come GUC_LOG_DISABLED isn't set today when
> i915.guc_log_level == -1, given that:
>
> #define   GUC_LOG_DISABLED             (1 << 6)
>
> Is that bit set by default somehow if i915 does not program it?
>

Yes currently GUC_LOG_DISABLED won't get set for guc_log_level = -1.
But then log buffer address will go as NULL and GUC_LOG_VALID flag will
go as 0, for guc_log_level = -1. So this way logging on GuC side will 
not get enabled.
I hope I understood your concern correctly.

Best regards
Akash

>>
>>       if (guc->ads_obj) {
>>           u32 ads = (u32)i915_gem_obj_ggtt_offset(guc->ads_obj)
>>
>
> Regards,
>
> Tvrtko
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter
  2016-07-11 11:41     ` Goel, Akash
@ 2016-07-11 11:50       ` Tvrtko Ursulin
  2016-07-11 12:11         ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-11 11:50 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 11/07/16 12:41, Goel, Akash wrote:
> On 7/11/2016 3:07 PM, Tvrtko Ursulin wrote:
>>
>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>
>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> index 2112e02..8a9a0cb 100644
>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> @@ -832,9 +832,6 @@ static void guc_create_log(struct intel_guc *guc)
>>>       unsigned long offset;
>>>       uint32_t size, flags;
>>>
>>> -    if (i915.guc_log_level < GUC_LOG_VERBOSITY_MIN)
>>> -        return;
>>> -
>>>       if (i915.guc_log_level > GUC_LOG_VERBOSITY_MAX)
>>>           i915.guc_log_level = GUC_LOG_VERBOSITY_MAX;
>>>
>>> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c
>>> b/drivers/gpu/drm/i915/intel_guc_loader.c
>>> index 605c696..b211bd0 100644
>>> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
>>> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
>>> @@ -175,11 +175,13 @@ static void set_guc_init_params(struct
>>> drm_i915_private *dev_priv)
>>>       params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
>>>               GUC_CTL_VCS2_ENABLED;
>>>
>>> -    if (i915.guc_log_level >= 0) {
>>> -        params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
>>> +    params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
>>
>> guc->log_flags will be zero when logging is not configured because guc
>> is a part of dev_priv. So it looks safe - although I reckon it would be
>> clearer to set this (GUC_CTL_LOG_PARAMS) explicitly inside the if-else
>> below?
>
> If logging is not enabled at (due to guc_log_level < 0), then also
> log_flags needs to be setup & passed to GuC firmware.
> log_flags shall not be zero even when logging is not be enabled (at boot
> time).
> Actually log_flags will also contain the address of the log buffer.

Ah yes, I got confused by jumping between one file with your patch 
applied and one without it.

>>> +
>>> +    if (i915.guc_log_level >= 0)
>>>           params[GUC_CTL_DEBUG] =
>>>               i915.guc_log_level << GUC_LOG_VERBOSITY_SHIFT;
>>> -    }
>>> +    else
>>> +        params[GUC_CTL_DEBUG] = GUC_LOG_DISABLED;
>>
>> I also wonder how come GUC_LOG_DISABLED isn't set today when
>> i915.guc_log_level == -1, given that:
>>
>> #define   GUC_LOG_DISABLED             (1 << 6)
>>
>> Is that bit set by default somehow if i915 does not program it?
>>
>
> Yes currently GUC_LOG_DISABLED won't get set for guc_log_level = -1.
> But then log buffer address will go as NULL and GUC_LOG_VALID flag will
> go as 0, for guc_log_level = -1. So this way logging on GuC side will
> not get enabled.
> I hope I understood your concern correctly.

Yes, this clarifies it. Although I do have one more question then - what 
happens if at boot i915.guc_log_level == -1 and then with later patches 
logging gets enabled via debugfs - who and how sets 
params[GUC_CTL_DEBUG]? Host2GuC overrides this parameter?

Regards,

Tvrtko


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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter
  2016-07-11 11:50       ` Tvrtko Ursulin
@ 2016-07-11 12:11         ` Goel, Akash
  2016-07-11 13:07           ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-11 12:11 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/11/2016 5:20 PM, Tvrtko Ursulin wrote:
>
> On 11/07/16 12:41, Goel, Akash wrote:
>> On 7/11/2016 3:07 PM, Tvrtko Ursulin wrote:
>>>
>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>>
>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> index 2112e02..8a9a0cb 100644
>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>
>>>> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c
>>>> b/drivers/gpu/drm/i915/intel_guc_loader.c
>>>> index 605c696..b211bd0 100644
>>>> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
>>>> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
>>>> @@ -175,11 +175,13 @@ static void set_guc_init_params(struct
>>>> drm_i915_private *dev_priv)
>>>>       params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
>>>>               GUC_CTL_VCS2_ENABLED;
>>>>
>>>> -    if (i915.guc_log_level >= 0) {
>>>> -        params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
>>>> +    params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
>>>
>>> guc->log_flags will be zero when logging is not configured because guc
>>> is a part of dev_priv. So it looks safe - although I reckon it would be
>>> clearer to set this (GUC_CTL_LOG_PARAMS) explicitly inside the if-else
>>> below?
>>
>> If logging is not enabled at (due to guc_log_level < 0), then also
>> log_flags needs to be setup & passed to GuC firmware.
>> log_flags shall not be zero even when logging is not be enabled (at boot
>> time).
>> Actually log_flags will also contain the address of the log buffer.
>
> Ah yes, I got confused by jumping between one file with your patch
> applied and one without it.
>
>>>> +
>>>> +    if (i915.guc_log_level >= 0)
>>>>           params[GUC_CTL_DEBUG] =
>>>>               i915.guc_log_level << GUC_LOG_VERBOSITY_SHIFT;
>>>> -    }
>>>> +    else
>>>> +        params[GUC_CTL_DEBUG] = GUC_LOG_DISABLED;
>>>
>>> I also wonder how come GUC_LOG_DISABLED isn't set today when
>>> i915.guc_log_level == -1, given that:
>>>
>>> #define   GUC_LOG_DISABLED             (1 << 6)
>>>
>>> Is that bit set by default somehow if i915 does not program it?
>>>
>>
>> Yes currently GUC_LOG_DISABLED won't get set for guc_log_level = -1.
>> But then log buffer address will go as NULL and GUC_LOG_VALID flag will
>> go as 0, for guc_log_level = -1. So this way logging on GuC side will
>> not get enabled.
>> I hope I understood your concern correctly.
>
> Yes, this clarifies it. Although I do have one more question then - what
> happens if at boot i915.guc_log_level == -1 and then with later patches
> logging gets enabled via debugfs - who and how sets
> params[GUC_CTL_DEBUG]? Host2GuC overrides this parameter?
>

Yes through Host2GuC action type, UK_LOG_ENABLE_LOGGING, Host will 
request GuC firmware to enable/disable logging and alter the verbosity
level.

The params[GUC_CTL_DEBUG] is just part of the firmware initialization
parameters and is not used after that.

Best regards
Akash

> Regards,
>
> Tvrtko
>
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter
  2016-07-11 12:11         ` Goel, Akash
@ 2016-07-11 13:07           ` Tvrtko Ursulin
  0 siblings, 0 replies; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-11 13:07 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 11/07/16 13:11, Goel, Akash wrote:
>
>
> On 7/11/2016 5:20 PM, Tvrtko Ursulin wrote:
>>
>> On 11/07/16 12:41, Goel, Akash wrote:
>>> On 7/11/2016 3:07 PM, Tvrtko Ursulin wrote:
>>>>
>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>>>
>>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> index 2112e02..8a9a0cb 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>
>>>>> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c
>>>>> b/drivers/gpu/drm/i915/intel_guc_loader.c
>>>>> index 605c696..b211bd0 100644
>>>>> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
>>>>> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
>>>>> @@ -175,11 +175,13 @@ static void set_guc_init_params(struct
>>>>> drm_i915_private *dev_priv)
>>>>>       params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
>>>>>               GUC_CTL_VCS2_ENABLED;
>>>>>
>>>>> -    if (i915.guc_log_level >= 0) {
>>>>> -        params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
>>>>> +    params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
>>>>
>>>> guc->log_flags will be zero when logging is not configured because guc
>>>> is a part of dev_priv. So it looks safe - although I reckon it would be
>>>> clearer to set this (GUC_CTL_LOG_PARAMS) explicitly inside the if-else
>>>> below?
>>>
>>> If logging is not enabled at (due to guc_log_level < 0), then also
>>> log_flags needs to be setup & passed to GuC firmware.
>>> log_flags shall not be zero even when logging is not be enabled (at boot
>>> time).
>>> Actually log_flags will also contain the address of the log buffer.
>>
>> Ah yes, I got confused by jumping between one file with your patch
>> applied and one without it.
>>
>>>>> +
>>>>> +    if (i915.guc_log_level >= 0)
>>>>>           params[GUC_CTL_DEBUG] =
>>>>>               i915.guc_log_level << GUC_LOG_VERBOSITY_SHIFT;
>>>>> -    }
>>>>> +    else
>>>>> +        params[GUC_CTL_DEBUG] = GUC_LOG_DISABLED;
>>>>
>>>> I also wonder how come GUC_LOG_DISABLED isn't set today when
>>>> i915.guc_log_level == -1, given that:
>>>>
>>>> #define   GUC_LOG_DISABLED             (1 << 6)
>>>>
>>>> Is that bit set by default somehow if i915 does not program it?
>>>>
>>>
>>> Yes currently GUC_LOG_DISABLED won't get set for guc_log_level = -1.
>>> But then log buffer address will go as NULL and GUC_LOG_VALID flag will
>>> go as 0, for guc_log_level = -1. So this way logging on GuC side will
>>> not get enabled.
>>> I hope I understood your concern correctly.
>>
>> Yes, this clarifies it. Although I do have one more question then - what
>> happens if at boot i915.guc_log_level == -1 and then with later patches
>> logging gets enabled via debugfs - who and how sets
>> params[GUC_CTL_DEBUG]? Host2GuC overrides this parameter?
>>
>
> Yes through Host2GuC action type, UK_LOG_ENABLE_LOGGING, Host will
> request GuC firmware to enable/disable logging and alter the verbosity
> level.
>
> The params[GUC_CTL_DEBUG] is just part of the firmware initialization
> parameters and is not used after that.

Got it now, in that case:

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Regards,

Tvrtko


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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 05/17] drm/i915: Support for GuC interrupts
  2016-07-11 10:30   ` Tvrtko Ursulin
@ 2016-07-11 13:15     ` Goel, Akash
  2016-07-11 13:23       ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-11 13:15 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/11/2016 4:00 PM, Tvrtko Ursulin wrote:
>
> On 10/07/16 14:41, akash.goel@intel.com wrote:
>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>
>> There are certain types of interrupts which Host can recieve from GuC.
>> GuC ukernel sends an interrupt to Host for certain events, like for
>> example retrieve/consume the logs generated by ukernel.
>> This patch adds support to receive interrupts from GuC but currently
>> enables & partially handles only the interrupt sent by GuC ukernel.
>> Future patches will add support for handling other interrupt types.
>>
>> v2:
>> - Use common low level routines for PM IER/IIR programming (Chris)
>> - Rename interrupt functions to gen9_xxx from gen8_xxx (Chris)
>> - Replace disabling of wake ref asserts with rpm get/put (Chris)
>>
>> v3:
>> - Update comments for more clarity. (Tvrtko)
>> - Remove the masking of GuC interrupt, which was kept masked till the
>>    start of bottom half, its not really needed as there is only a
>>    single instance of work item & wq is ordered. (Tvrtko)
>>
>> v4:
>> - Rebase.
>> - Rename guc_events to pm_guc_events so as to be indicative of the
>>    register/control block it is associated with. (Chris)
>> - Add handling for back to back log buffer flush interrupts.
>>
>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>> ---
>>   drivers/gpu/drm/i915/i915_drv.h            |  1 +
>>   drivers/gpu/drm/i915/i915_guc_submission.c |  5 ++
>>   drivers/gpu/drm/i915/i915_irq.c            | 98
>> ++++++++++++++++++++++++++++--
>>   drivers/gpu/drm/i915/i915_reg.h            | 11 ++++
>>   drivers/gpu/drm/i915/intel_drv.h           |  3 +
>>   drivers/gpu/drm/i915/intel_guc.h           |  4 ++
>>   drivers/gpu/drm/i915/intel_guc_loader.c    |  4 ++
>>   7 files changed, 122 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_drv.h
>> b/drivers/gpu/drm/i915/i915_drv.h
>> index c3a579f..6e2ddfa 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.h
>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> @@ -1794,6 +1794,7 @@ struct drm_i915_private {
>>       u32 pm_imr;
>>       u32 pm_ier;
>>       u32 pm_rps_events;
>> +    u32 pm_guc_events;
>>       u32 pipestat_irq_mask[I915_MAX_PIPES];
>>
>>       struct i915_hotplug hotplug;
>>
>> +
>>   /**
>>    * bdw_update_port_irq - update DE port interrupt
>>    * @dev_priv: driver private
>> @@ -1174,6 +1208,21 @@ static void gen6_pm_rps_work(struct work_struct
>> *work)
>>       mutex_unlock(&dev_priv->rps.hw_lock);
>>   }
>>
>> +static void gen9_guc2host_events_work(struct work_struct *work)
>> +{
>> +    struct drm_i915_private *dev_priv =
>> +        container_of(work, struct drm_i915_private, guc.events_work);
>> +
>> +    spin_lock_irq(&dev_priv->irq_lock);
>> +    /* Speed up work cancellation during disabling guc interrupts. */
>> +    if (!dev_priv->guc.interrupts_enabled) {
>> +        spin_unlock_irq(&dev_priv->irq_lock);
>> +        return;
>> +    }
>> +    spin_unlock_irq(&dev_priv->irq_lock);
>> +
>> +    /* TODO: Handle the events for which GuC interrupted host */
>> +}
>>
>>   /**
>>    * ivybridge_parity_work - Workqueue called when a parity error
>> interrupt
>> @@ -1346,11 +1395,13 @@ static irqreturn_t gen8_gt_irq_ack(struct
>> drm_i915_private *dev_priv,
>>               DRM_ERROR("The master control interrupt lied (GT3)!\n");
>>       }
>>
>> -    if (master_ctl & GEN8_GT_PM_IRQ) {
>> +    if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
>>           gt_iir[2] = I915_READ_FW(GEN8_GT_IIR(2));
>> -        if (gt_iir[2] & dev_priv->pm_rps_events) {
>> +        if (gt_iir[2] & (dev_priv->pm_rps_events |
>> +                 dev_priv->pm_guc_events)) {
>>               I915_WRITE_FW(GEN8_GT_IIR(2),
>> -                      gt_iir[2] & dev_priv->pm_rps_events);
>> +                      gt_iir[2] & (dev_priv->pm_rps_events |
>> +                           dev_priv->pm_guc_events));
>>               ret = IRQ_HANDLED;
>>           } else
>>               DRM_ERROR("The master control interrupt lied (PM)!\n");
>> @@ -1382,6 +1433,9 @@ static void gen8_gt_irq_handler(struct
>> drm_i915_private *dev_priv,
>>
>>       if (gt_iir[2] & dev_priv->pm_rps_events)
>>           gen6_rps_irq_handler(dev_priv, gt_iir[2]);
>> +
>> +    if (gt_iir[2] & dev_priv->pm_guc_events)
>> +        gen9_guc_irq_handler(dev_priv, gt_iir[2]);
>>   }
>>
>>   static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
>> @@ -1628,6 +1682,38 @@ static void gen6_rps_irq_handler(struct
>> drm_i915_private *dev_priv, u32 pm_iir)
>>       }
>>   }
>>
>> +static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv,
>> u32 gt_iir)
>> +{
>> +    if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) {
>> +        spin_lock(&dev_priv->irq_lock);
>> +        if (dev_priv->guc.interrupts_enabled) {
>> +            /* Sample the log buffer flush related bits & clear them
>> +             * out now itself from the message identity register to
>> +             * minimize the probability of losing a flush interrupt,
>> +             * when there are back to back flush interrupts.
>> +             * There can be a new flush interrupt, for different log
>> +             * buffer type (like for ISR), whilst Host is handling
>> +             * one (for DPC). Since same bit is used in message
>> +             * register for ISR & DPC, it could happen that GuC
>> +             * sets the bit for 2nd interrupt but Host clears out
>> +             * the bit on handling the 1st interrupt.
>> +             */
>> +            u32 msg = I915_READ(SOFT_SCRATCH(15)) &
>> +                    (GUC2HOST_MSG_CRASH_DUMP_POSTED |
>> +                     GUC2HOST_MSG_FLUSH_LOG_BUFFER);
>> +            if (msg) {
>> +                /* Clear the message bits that are handled */
>> +                I915_WRITE(SOFT_SCRATCH(15),
>> +                    I915_READ(SOFT_SCRATCH(15)) & ~msg);
>> +
>> +                /* Handle flush interrupt event in bottom half */
>> +                queue_work(dev_priv->wq, &dev_priv->guc.events_work);
>
> Since the later patch is changing this to use a thread, since you have
> established worker is too slow - especially the shared one - I would
> really recommend you start with the kthread straight away. Not have the
> worker for a while in the same series and then later change it to a thread.
>
Actually it won't be appropriate to say that shared worker thread is too 
slow, but having a dedicated kthread definitely helps.

I kept the kthread patch at the last so that as per the response,
review comments can drop it also.

>> +            }
>> +        }
>> +        spin_unlock(&dev_priv->irq_lock);
>
> Why does the above needs to be done under the irq_lock ?
>
Using the irq_lock for 'guc.interrupts_enabled', especially useful
while disabling the interrupt.

Best regards
Akash

>> +    }
>> +}
>> +
>>   static bool intel_pipe_handle_vblank(struct drm_i915_private *dev_priv,
>>                        enum pipe pipe)
>>   {
>> @@ -3754,7 +3840,7 @@ static void gen8_gt_irq_postinstall(struct
>> drm_i915_private *dev_priv)
>>       GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
>>       /*
>>        * RPS interrupts will get enabled/disabled on demand when RPS
>> itself
>> -     * is enabled/disabled.
>> +     * is enabled/disabled. Same wil be the case for GuC interrupts.
>>        */
>>       GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier);
>>       GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
>> @@ -4539,6 +4625,10 @@ void intel_irq_init(struct drm_i915_private
>> *dev_priv)
>>
>>       INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
>>       INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
>> +    INIT_WORK(&dev_priv->guc.events_work, gen9_guc2host_events_work);
>> +
>> +    if (HAS_GUC_UCODE(dev))
>> +        dev_priv->pm_guc_events = GEN9_GUC_TO_HOST_INT_EVENT;
>>
>>       /* Let's track the enabled rps events */
>>       if (IS_VALLEYVIEW(dev_priv))
>> diff --git a/drivers/gpu/drm/i915/i915_reg.h
>> b/drivers/gpu/drm/i915/i915_reg.h
>> index 8bfde75..d0d13a2 100644
>> --- a/drivers/gpu/drm/i915/i915_reg.h
>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>> @@ -5963,6 +5963,7 @@ enum {
>>   #define  GEN8_DE_PIPE_A_IRQ        (1<<16)
>>   #define  GEN8_DE_PIPE_IRQ(pipe)        (1<<(16+(pipe)))
>>   #define  GEN8_GT_VECS_IRQ        (1<<6)
>> +#define  GEN8_GT_GUC_IRQ        (1<<5)
>>   #define  GEN8_GT_PM_IRQ            (1<<4)
>>   #define  GEN8_GT_VCS2_IRQ        (1<<3)
>>   #define  GEN8_GT_VCS1_IRQ        (1<<2)
>> @@ -5974,6 +5975,16 @@ enum {
>>   #define GEN8_GT_IIR(which) _MMIO(0x44308 + (0x10 * (which)))
>>   #define GEN8_GT_IER(which) _MMIO(0x4430c + (0x10 * (which)))
>>
>> +#define GEN9_GUC_TO_HOST_INT_EVENT    (1<<31)
>> +#define GEN9_GUC_EXEC_ERROR_EVENT    (1<<30)
>> +#define GEN9_GUC_DISPLAY_EVENT        (1<<29)
>> +#define GEN9_GUC_SEMA_SIGNAL_EVENT    (1<<28)
>> +#define GEN9_GUC_IOMMU_MSG_EVENT    (1<<27)
>> +#define GEN9_GUC_DB_RING_EVENT        (1<<26)
>> +#define GEN9_GUC_DMA_DONE_EVENT        (1<<25)
>> +#define GEN9_GUC_FATAL_ERROR_EVENT    (1<<24)
>> +#define GEN9_GUC_NOTIFICATION_EVENT    (1<<23)
>> +
>>   #define GEN8_RCS_IRQ_SHIFT 0
>>   #define GEN8_BCS_IRQ_SHIFT 16
>>   #define GEN8_VCS1_IRQ_SHIFT 0
>> diff --git a/drivers/gpu/drm/i915/intel_drv.h
>> b/drivers/gpu/drm/i915/intel_drv.h
>> index ae6c535..6868f31 100644
>> --- a/drivers/gpu/drm/i915/intel_drv.h
>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> @@ -1102,6 +1102,9 @@ void gen8_irq_power_well_post_enable(struct
>> drm_i915_private *dev_priv,
>>                        unsigned int pipe_mask);
>>   void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
>>                        unsigned int pipe_mask);
>> +void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv);
>> +void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv);
>> +void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv);
>>
>>   /* intel_crt.c */
>>   void intel_crt_init(struct drm_device *dev);
>> diff --git a/drivers/gpu/drm/i915/intel_guc.h
>> b/drivers/gpu/drm/i915/intel_guc.h
>> index d52eca3..2663b41 100644
>> --- a/drivers/gpu/drm/i915/intel_guc.h
>> +++ b/drivers/gpu/drm/i915/intel_guc.h
>> @@ -131,6 +131,10 @@ struct intel_guc {
>>       struct intel_guc_fw guc_fw;
>>       struct intel_guc_log log;
>>
>> +    /* GuC2Host interrupt related state */
>> +    struct work_struct events_work;
>> +    bool interrupts_enabled;
>> +
>>       struct drm_i915_gem_object *ads_obj;
>>
>>       struct drm_i915_gem_object *ctx_pool_obj;
>> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c
>> b/drivers/gpu/drm/i915/intel_guc_loader.c
>> index 4882f17..d74d7a5 100644
>> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
>> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
>> @@ -450,6 +450,7 @@ int intel_guc_setup(struct drm_device *dev)
>>       }
>>
>>       direct_interrupts_to_host(dev_priv);
>> +    gen9_reset_guc_interrupts(dev_priv);
>>
>>       guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING;
>>
>> @@ -496,6 +497,9 @@ int intel_guc_setup(struct drm_device *dev)
>>           intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
>>
>>       if (i915.enable_guc_submission) {
>> +        if (i915.guc_log_level >= 0)
>> +            gen9_enable_guc_interrupts(dev_priv);
>> +
>>           err = i915_guc_submission_enable(dev_priv);
>>           if (err)
>>               goto fail;
>>
>
> Regards,
>
> Tvrtko
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 05/17] drm/i915: Support for GuC interrupts
  2016-07-11 13:15     ` Goel, Akash
@ 2016-07-11 13:23       ` Tvrtko Ursulin
  2016-07-11 13:38         ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-11 13:23 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 11/07/16 14:15, Goel, Akash wrote:
> On 7/11/2016 4:00 PM, Tvrtko Ursulin wrote:
>>
>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>
>>> There are certain types of interrupts which Host can recieve from GuC.
>>> GuC ukernel sends an interrupt to Host for certain events, like for
>>> example retrieve/consume the logs generated by ukernel.
>>> This patch adds support to receive interrupts from GuC but currently
>>> enables & partially handles only the interrupt sent by GuC ukernel.
>>> Future patches will add support for handling other interrupt types.
>>>
>>> v2:
>>> - Use common low level routines for PM IER/IIR programming (Chris)
>>> - Rename interrupt functions to gen9_xxx from gen8_xxx (Chris)
>>> - Replace disabling of wake ref asserts with rpm get/put (Chris)
>>>
>>> v3:
>>> - Update comments for more clarity. (Tvrtko)
>>> - Remove the masking of GuC interrupt, which was kept masked till the
>>>    start of bottom half, its not really needed as there is only a
>>>    single instance of work item & wq is ordered. (Tvrtko)
>>>
>>> v4:
>>> - Rebase.
>>> - Rename guc_events to pm_guc_events so as to be indicative of the
>>>    register/control block it is associated with. (Chris)
>>> - Add handling for back to back log buffer flush interrupts.
>>>
>>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>> ---
>>>   drivers/gpu/drm/i915/i915_drv.h            |  1 +
>>>   drivers/gpu/drm/i915/i915_guc_submission.c |  5 ++
>>>   drivers/gpu/drm/i915/i915_irq.c            | 98
>>> ++++++++++++++++++++++++++++--
>>>   drivers/gpu/drm/i915/i915_reg.h            | 11 ++++
>>>   drivers/gpu/drm/i915/intel_drv.h           |  3 +
>>>   drivers/gpu/drm/i915/intel_guc.h           |  4 ++
>>>   drivers/gpu/drm/i915/intel_guc_loader.c    |  4 ++
>>>   7 files changed, 122 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_drv.h
>>> b/drivers/gpu/drm/i915/i915_drv.h
>>> index c3a579f..6e2ddfa 100644
>>> --- a/drivers/gpu/drm/i915/i915_drv.h
>>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>>> @@ -1794,6 +1794,7 @@ struct drm_i915_private {
>>>       u32 pm_imr;
>>>       u32 pm_ier;
>>>       u32 pm_rps_events;
>>> +    u32 pm_guc_events;
>>>       u32 pipestat_irq_mask[I915_MAX_PIPES];
>>>
>>>       struct i915_hotplug hotplug;
>>>
>>> +
>>>   /**
>>>    * bdw_update_port_irq - update DE port interrupt
>>>    * @dev_priv: driver private
>>> @@ -1174,6 +1208,21 @@ static void gen6_pm_rps_work(struct work_struct
>>> *work)
>>>       mutex_unlock(&dev_priv->rps.hw_lock);
>>>   }
>>>
>>> +static void gen9_guc2host_events_work(struct work_struct *work)
>>> +{
>>> +    struct drm_i915_private *dev_priv =
>>> +        container_of(work, struct drm_i915_private, guc.events_work);
>>> +
>>> +    spin_lock_irq(&dev_priv->irq_lock);
>>> +    /* Speed up work cancellation during disabling guc interrupts. */
>>> +    if (!dev_priv->guc.interrupts_enabled) {
>>> +        spin_unlock_irq(&dev_priv->irq_lock);
>>> +        return;
>>> +    }
>>> +    spin_unlock_irq(&dev_priv->irq_lock);
>>> +
>>> +    /* TODO: Handle the events for which GuC interrupted host */
>>> +}
>>>
>>>   /**
>>>    * ivybridge_parity_work - Workqueue called when a parity error
>>> interrupt
>>> @@ -1346,11 +1395,13 @@ static irqreturn_t gen8_gt_irq_ack(struct
>>> drm_i915_private *dev_priv,
>>>               DRM_ERROR("The master control interrupt lied (GT3)!\n");
>>>       }
>>>
>>> -    if (master_ctl & GEN8_GT_PM_IRQ) {
>>> +    if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
>>>           gt_iir[2] = I915_READ_FW(GEN8_GT_IIR(2));
>>> -        if (gt_iir[2] & dev_priv->pm_rps_events) {
>>> +        if (gt_iir[2] & (dev_priv->pm_rps_events |
>>> +                 dev_priv->pm_guc_events)) {
>>>               I915_WRITE_FW(GEN8_GT_IIR(2),
>>> -                      gt_iir[2] & dev_priv->pm_rps_events);
>>> +                      gt_iir[2] & (dev_priv->pm_rps_events |
>>> +                           dev_priv->pm_guc_events));
>>>               ret = IRQ_HANDLED;
>>>           } else
>>>               DRM_ERROR("The master control interrupt lied (PM)!\n");
>>> @@ -1382,6 +1433,9 @@ static void gen8_gt_irq_handler(struct
>>> drm_i915_private *dev_priv,
>>>
>>>       if (gt_iir[2] & dev_priv->pm_rps_events)
>>>           gen6_rps_irq_handler(dev_priv, gt_iir[2]);
>>> +
>>> +    if (gt_iir[2] & dev_priv->pm_guc_events)
>>> +        gen9_guc_irq_handler(dev_priv, gt_iir[2]);
>>>   }
>>>
>>>   static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
>>> @@ -1628,6 +1682,38 @@ static void gen6_rps_irq_handler(struct
>>> drm_i915_private *dev_priv, u32 pm_iir)
>>>       }
>>>   }
>>>
>>> +static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv,
>>> u32 gt_iir)
>>> +{
>>> +    if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) {
>>> +        spin_lock(&dev_priv->irq_lock);
>>> +        if (dev_priv->guc.interrupts_enabled) {
>>> +            /* Sample the log buffer flush related bits & clear them
>>> +             * out now itself from the message identity register to
>>> +             * minimize the probability of losing a flush interrupt,
>>> +             * when there are back to back flush interrupts.
>>> +             * There can be a new flush interrupt, for different log
>>> +             * buffer type (like for ISR), whilst Host is handling
>>> +             * one (for DPC). Since same bit is used in message
>>> +             * register for ISR & DPC, it could happen that GuC
>>> +             * sets the bit for 2nd interrupt but Host clears out
>>> +             * the bit on handling the 1st interrupt.
>>> +             */
>>> +            u32 msg = I915_READ(SOFT_SCRATCH(15)) &
>>> +                    (GUC2HOST_MSG_CRASH_DUMP_POSTED |
>>> +                     GUC2HOST_MSG_FLUSH_LOG_BUFFER);
>>> +            if (msg) {
>>> +                /* Clear the message bits that are handled */
>>> +                I915_WRITE(SOFT_SCRATCH(15),
>>> +                    I915_READ(SOFT_SCRATCH(15)) & ~msg);
>>> +
>>> +                /* Handle flush interrupt event in bottom half */
>>> +                queue_work(dev_priv->wq, &dev_priv->guc.events_work);
>>
>> Since the later patch is changing this to use a thread, since you have
>> established worker is too slow - especially the shared one - I would
>> really recommend you start with the kthread straight away. Not have the
>> worker for a while in the same series and then later change it to a
>> thread.
>>
> Actually it won't be appropriate to say that shared worker thread is too
> slow, but having a dedicated kthread definitely helps.
>
> I kept the kthread patch at the last so that as per the response,
> review comments can drop it also.

I think it should only be one implementation in the patch series. If we 
agreed on a kthread make it so from the start.

And describe in the commit message why it was selected etc.

>>> +            }
>>> +        }
>>> +        spin_unlock(&dev_priv->irq_lock);
>>
>> Why does the above needs to be done under the irq_lock ?
>>
> Using the irq_lock for 'guc.interrupts_enabled', especially useful
> while disabling the interrupt.

Why? I don't see how it gains you anything and so it seems preferable 
not to hold it over mmio accesses.

Regards,

Tvrtko


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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 05/17] drm/i915: Support for GuC interrupts
  2016-07-11 13:23       ` Tvrtko Ursulin
@ 2016-07-11 13:38         ` Goel, Akash
  2016-07-11 13:43           ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-11 13:38 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/11/2016 6:53 PM, Tvrtko Ursulin wrote:
>
> On 11/07/16 14:15, Goel, Akash wrote:
>> On 7/11/2016 4:00 PM, Tvrtko Ursulin wrote:
>>>

>>>> +static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv,
>>>> u32 gt_iir)
>>>> +{
>>>> +    if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) {
>>>> +        spin_lock(&dev_priv->irq_lock);
>>>> +        if (dev_priv->guc.interrupts_enabled) {
>>>> +            /* Sample the log buffer flush related bits & clear them
>>>> +             * out now itself from the message identity register to
>>>> +             * minimize the probability of losing a flush interrupt,
>>>> +             * when there are back to back flush interrupts.
>>>> +             * There can be a new flush interrupt, for different log
>>>> +             * buffer type (like for ISR), whilst Host is handling
>>>> +             * one (for DPC). Since same bit is used in message
>>>> +             * register for ISR & DPC, it could happen that GuC
>>>> +             * sets the bit for 2nd interrupt but Host clears out
>>>> +             * the bit on handling the 1st interrupt.
>>>> +             */
>>>> +            u32 msg = I915_READ(SOFT_SCRATCH(15)) &
>>>> +                    (GUC2HOST_MSG_CRASH_DUMP_POSTED |
>>>> +                     GUC2HOST_MSG_FLUSH_LOG_BUFFER);
>>>> +            if (msg) {
>>>> +                /* Clear the message bits that are handled */
>>>> +                I915_WRITE(SOFT_SCRATCH(15),
>>>> +                    I915_READ(SOFT_SCRATCH(15)) & ~msg);
>>>> +
>>>> +                /* Handle flush interrupt event in bottom half */
>>>> +                queue_work(dev_priv->wq, &dev_priv->guc.events_work);
>>>
>>> Since the later patch is changing this to use a thread, since you have
>>> established worker is too slow - especially the shared one - I would
>>> really recommend you start with the kthread straight away. Not have the
>>> worker for a while in the same series and then later change it to a
>>> thread.
>>>
>> Actually it won't be appropriate to say that shared worker thread is too
>> slow, but having a dedicated kthread definitely helps.
>>
>> I kept the kthread patch at the last so that as per the response,
>> review comments can drop it also.
>
> I think it should only be one implementation in the patch series. If we
> agreed on a kthread make it so from the start.
>
Agree but actually right now, added the kthread patch more as a RFC and
presumed this won't be the final version of the series.
Will do the needful, as per the review comments, in the next version.

> And describe in the commit message why it was selected etc.
>
>>>> +            }
>>>> +        }
>>>> +        spin_unlock(&dev_priv->irq_lock);
>>>
>>> Why does the above needs to be done under the irq_lock ?
>>>
>> Using the irq_lock for 'guc.interrupts_enabled', especially useful
>> while disabling the interrupt.
>
> Why? I don't see how it gains you anything and so it seems preferable
> not to hold it over mmio accesses.
>
Yes not needed for the mmio access part.
Just needed for the inspection of 'guc.interrupts_enabled' value.
Will reorder the code.

Best regards
Akash

> Regards,
>
> Tvrtko
>
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 05/17] drm/i915: Support for GuC interrupts
  2016-07-11 13:38         ` Goel, Akash
@ 2016-07-11 13:43           ` Tvrtko Ursulin
  2016-07-11 14:20             ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-11 13:43 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 11/07/16 14:38, Goel, Akash wrote:
> On 7/11/2016 6:53 PM, Tvrtko Ursulin wrote:
>>
>> On 11/07/16 14:15, Goel, Akash wrote:
>>> On 7/11/2016 4:00 PM, Tvrtko Ursulin wrote:
>>>>
>
>>>>> +static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv,
>>>>> u32 gt_iir)
>>>>> +{
>>>>> +    if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) {
>>>>> +        spin_lock(&dev_priv->irq_lock);
>>>>> +        if (dev_priv->guc.interrupts_enabled) {
>>>>> +            /* Sample the log buffer flush related bits & clear them
>>>>> +             * out now itself from the message identity register to
>>>>> +             * minimize the probability of losing a flush interrupt,
>>>>> +             * when there are back to back flush interrupts.
>>>>> +             * There can be a new flush interrupt, for different log
>>>>> +             * buffer type (like for ISR), whilst Host is handling
>>>>> +             * one (for DPC). Since same bit is used in message
>>>>> +             * register for ISR & DPC, it could happen that GuC
>>>>> +             * sets the bit for 2nd interrupt but Host clears out
>>>>> +             * the bit on handling the 1st interrupt.
>>>>> +             */
>>>>> +            u32 msg = I915_READ(SOFT_SCRATCH(15)) &
>>>>> +                    (GUC2HOST_MSG_CRASH_DUMP_POSTED |
>>>>> +                     GUC2HOST_MSG_FLUSH_LOG_BUFFER);
>>>>> +            if (msg) {
>>>>> +                /* Clear the message bits that are handled */
>>>>> +                I915_WRITE(SOFT_SCRATCH(15),
>>>>> +                    I915_READ(SOFT_SCRATCH(15)) & ~msg);
>>>>> +
>>>>> +                /* Handle flush interrupt event in bottom half */
>>>>> +                queue_work(dev_priv->wq, &dev_priv->guc.events_work);
>>>>
>>>> Since the later patch is changing this to use a thread, since you have
>>>> established worker is too slow - especially the shared one - I would
>>>> really recommend you start with the kthread straight away. Not have the
>>>> worker for a while in the same series and then later change it to a
>>>> thread.
>>>>
>>> Actually it won't be appropriate to say that shared worker thread is too
>>> slow, but having a dedicated kthread definitely helps.
>>>
>>> I kept the kthread patch at the last so that as per the response,
>>> review comments can drop it also.
>>
>> I think it should only be one implementation in the patch series. If we
>> agreed on a kthread make it so from the start.
>>
> Agree but actually right now, added the kthread patch more as a RFC and
> presumed this won't be the final version of the series.
> Will do the needful, as per the review comments, in the next version.

Ack.

>> And describe in the commit message why it was selected etc.
>>
>>>>> +            }
>>>>> +        }
>>>>> +        spin_unlock(&dev_priv->irq_lock);
>>>>
>>>> Why does the above needs to be done under the irq_lock ?
>>>>
>>> Using the irq_lock for 'guc.interrupts_enabled', especially useful
>>> while disabling the interrupt.
>>
>> Why? I don't see how it gains you anything and so it seems preferable
>> not to hold it over mmio accesses.
>>
> Yes not needed for the mmio access part.
> Just needed for the inspection of 'guc.interrupts_enabled' value.
> Will reorder the code.

You don't need it just for reading that value, you can just drop it.

Regards,

Tvrtko


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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 05/17] drm/i915: Support for GuC interrupts
  2016-07-11 13:43           ` Tvrtko Ursulin
@ 2016-07-11 14:20             ` Goel, Akash
  0 siblings, 0 replies; 87+ messages in thread
From: Goel, Akash @ 2016-07-11 14:20 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/11/2016 7:13 PM, Tvrtko Ursulin wrote:
>
> On 11/07/16 14:38, Goel, Akash wrote:
>> On 7/11/2016 6:53 PM, Tvrtko Ursulin wrote:
>>>
>>> On 11/07/16 14:15, Goel, Akash wrote:
>>>> On 7/11/2016 4:00 PM, Tvrtko Ursulin wrote:
>>>>>
>>
>>>>>> +static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv,
>>>>>> u32 gt_iir)
>>>>>> +{
>>>>>> +    if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT) {
>>>>>> +        spin_lock(&dev_priv->irq_lock);
>>>>>> +        if (dev_priv->guc.interrupts_enabled) {
>>>>>> +            /* Sample the log buffer flush related bits & clear them
>>>>>> +             * out now itself from the message identity register to
>>>>>> +             * minimize the probability of losing a flush interrupt,
>>>>>> +             * when there are back to back flush interrupts.
>>>>>> +             * There can be a new flush interrupt, for different log
>>>>>> +             * buffer type (like for ISR), whilst Host is handling
>>>>>> +             * one (for DPC). Since same bit is used in message
>>>>>> +             * register for ISR & DPC, it could happen that GuC
>>>>>> +             * sets the bit for 2nd interrupt but Host clears out
>>>>>> +             * the bit on handling the 1st interrupt.
>>>>>> +             */
>>>>>> +            u32 msg = I915_READ(SOFT_SCRATCH(15)) &
>>>>>> +                    (GUC2HOST_MSG_CRASH_DUMP_POSTED |
>>>>>> +                     GUC2HOST_MSG_FLUSH_LOG_BUFFER);
>>>>>> +            if (msg) {
>>>>>> +                /* Clear the message bits that are handled */
>>>>>> +                I915_WRITE(SOFT_SCRATCH(15),
>>>>>> +                    I915_READ(SOFT_SCRATCH(15)) & ~msg);
>>>>>> +
>>>>>> +                /* Handle flush interrupt event in bottom half */
>>>>>> +                queue_work(dev_priv->wq,
>>>>>> &dev_priv->guc.events_work);
>>>>>
>>>>> Since the later patch is changing this to use a thread, since you have
>>>>> established worker is too slow - especially the shared one - I would
>>>>> really recommend you start with the kthread straight away. Not have
>>>>> the
>>>>> worker for a while in the same series and then later change it to a
>>>>> thread.
>>>>>
>>>> Actually it won't be appropriate to say that shared worker thread is
>>>> too
>>>> slow, but having a dedicated kthread definitely helps.
>>>>
>>>> I kept the kthread patch at the last so that as per the response,
>>>> review comments can drop it also.
>>>
>>> I think it should only be one implementation in the patch series. If we
>>> agreed on a kthread make it so from the start.
>>>
>> Agree but actually right now, added the kthread patch more as a RFC and
>> presumed this won't be the final version of the series.
>> Will do the needful, as per the review comments, in the next version.
>
> Ack.
>
>>> And describe in the commit message why it was selected etc.
>>>
>>>>>> +            }
>>>>>> +        }
>>>>>> +        spin_unlock(&dev_priv->irq_lock);
>>>>>
>>>>> Why does the above needs to be done under the irq_lock ?
>>>>>
>>>> Using the irq_lock for 'guc.interrupts_enabled', especially useful
>>>> while disabling the interrupt.
>>>
>>> Why? I don't see how it gains you anything and so it seems preferable
>>> not to hold it over mmio accesses.
>>>
>> Yes not needed for the mmio access part.
>> Just needed for the inspection of 'guc.interrupts_enabled' value.
>> Will reorder the code.
>
> You don't need it just for reading that value, you can just drop it.
>

Its not strictly needed as its a mere read. But as per my limited
understanding, without the spinlock (which provides an implicit barrier
also) ISR might miss the reset of 'interrupts_enabled' flag, from a
thread on other CPU, and queue the new work. The update will be
visible eventually though. And same applies to the case when
'interrupts_enabled' flag is set from other CPU.
Good practice to use locks for accessing shared variables ?.

Best regards
Akash


> Regards,
>
> Tvrtko
>
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs
  2016-07-10 13:41 ` [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs akash.goel
@ 2016-07-15 11:15   ` Tvrtko Ursulin
  2016-07-15 15:36     ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-15 11:15 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Akash Goel <akash.goel@intel.com>
>
> On recieving the log buffer flush interrupt from GuC firmware, Driver
> stores the snapshot of the log buffer in a local buffer, from which
> Userspace can pull the logs. By default Driver store, up to, 4 snapshots
> of the log buffer in a local buffer (managed by relay).
> Added a new module (read only) param, 'guc_log_size', through which User
> can specify the number of snapshots of log buffer to be stored in local
> buffer. This can be used to ensure capturing of all boot time logs even
> with high verbosity level.
>
> v2: Rename module param to more apt name 'guc_log_buffer_nr'. (Nikula)
>
> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +--
>   drivers/gpu/drm/i915/i915_params.c         | 5 +++++
>   drivers/gpu/drm/i915/i915_params.h         | 1 +
>   3 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index 2e3b723..009d7c0 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -1046,8 +1046,7 @@ static int guc_create_log_relay_file(struct intel_guc *guc)
>
>   	/* Keep the size of sub buffers same as shared log buffer */
>   	subbuf_size = guc->log.obj->base.size;
> -	/* TODO: Decide based on the User's input */
> -	n_subbufs = 4;
> +	n_subbufs = i915.guc_log_buffer_nr;
>
>   	guc_log_relay_chan = relay_open("guc_log", log_dir,
>   			subbuf_size, n_subbufs, &relay_callbacks, dev);
> diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
> index 8b13bfa..d30c972 100644
> --- a/drivers/gpu/drm/i915/i915_params.c
> +++ b/drivers/gpu/drm/i915/i915_params.c
> @@ -57,6 +57,7 @@ struct i915_params i915 __read_mostly = {
>   	.enable_guc_loading = -1,
>   	.enable_guc_submission = -1,
>   	.guc_log_level = -1,
> +	.guc_log_buffer_nr = 4,
>   	.enable_dp_mst = true,
>   	.inject_load_failure = 0,
>   	.enable_dpcd_backlight = false,
> @@ -214,6 +215,10 @@ module_param_named(guc_log_level, i915.guc_log_level, int, 0400);
>   MODULE_PARM_DESC(guc_log_level,
>   	"GuC firmware logging level (-1:disabled (default), 0-3:enabled)");
>
> +module_param_named(guc_log_buffer_nr, i915.guc_log_buffer_nr, int, 0400);
> +MODULE_PARM_DESC(guc_log_buffer_nr,
> +	"Number of sub buffers to store GuC firmware logs (default: 4)");
> +
>   module_param_named_unsafe(enable_dp_mst, i915.enable_dp_mst, bool, 0600);
>   MODULE_PARM_DESC(enable_dp_mst,
>   	"Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)");
> diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
> index 0ad020b..14ca855 100644
> --- a/drivers/gpu/drm/i915/i915_params.h
> +++ b/drivers/gpu/drm/i915/i915_params.h
> @@ -48,6 +48,7 @@ struct i915_params {
>   	int enable_guc_loading;
>   	int enable_guc_submission;
>   	int guc_log_level;
> +	int guc_log_buffer_nr;
>   	int use_mmio_flip;
>   	int mmio_debug;
>   	int edp_vswing;
>

I did not figure out after a quick read of 
Documentation/filesystems/relay.txt whether we really need this to be 
configurable?

If I got it right number of sub-buffers here only has a relation to the 
userspace relay consumer latency. If the userspace is responsive should 
just two be enough? Or the existing default of four was shown in 
practice that it is better and good enough?

I am just not sure this is a useful module parameter without some more data.

Even if it is needed, as minimum I think the name should reflect this is 
about the relay side of things and not the GuC log buffer itself. So 
something like i915.guc_relay_log_subbuf_nr or something. With the 
matching description of course.

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/17] drm/i915: Support to create write combined type vmaps
  2016-07-10 13:41 ` [PATCH 11/17] drm/i915: Support to create write combined type vmaps akash.goel
@ 2016-07-15 11:31   ` Tvrtko Ursulin
  2016-07-15 11:45     ` Chris Wilson
  2016-07-15 16:30     ` Goel, Akash
  0 siblings, 2 replies; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-15 11:31 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Chris Wilson <chris@chris-wilson.co.uk>
>
> vmaps has a provision for controlling the page protection bits, with which
> we can use to control the mapping type, e.g. WB, WC, UC or even WT.
> To allow the caller to choose their mapping type, we add a parameter to
> i915_gem_object_pin_map - but we still only allow one vmap to be cached
> per object. If the object is currently not pinned, then we recreate the
> previous vmap with the new access type, but if it was pinned we report an
> error. This effectively limits the access via i915_gem_object_pin_map to a
> single mapping type for the lifetime of the object. Not usually a problem,
> but something to be aware of when setting up the object's vmap.
>
> We will want to vary the access type to enable WC mappings of ringbuffer
> and context objects on !llc platforms, as well as other objects where we
> need coherent access to the GPU's pages without going through the GTT
>
> v2: Remove the redundant braces around pin count check and fix the marker
>      in documentation (Chris)
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_drv.h            |  4 ++-
>   drivers/gpu/drm/i915/i915_gem.c            | 57 +++++++++++++++++++++++-------
>   drivers/gpu/drm/i915/i915_gem_dmabuf.c     |  2 +-
>   drivers/gpu/drm/i915/i915_guc_submission.c |  2 +-
>   drivers/gpu/drm/i915/intel_lrc.c           |  8 ++---
>   drivers/gpu/drm/i915/intel_ringbuffer.c    |  2 +-
>   6 files changed, 54 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 6e2ddfa..84afa17 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -3248,6 +3248,7 @@ static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
>   /**
>    * i915_gem_object_pin_map - return a contiguous mapping of the entire object
>    * @obj - the object to map into kernel address space
> + * @use_wc - whether the mapping should be using WC or WB pgprot_t
>    *
>    * Calls i915_gem_object_pin_pages() to prevent reaping of the object's
>    * pages and then returns a contiguous mapping of the backing storage into
> @@ -3259,7 +3260,8 @@ static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
>    * Returns the pointer through which to access the mapped object, or an
>    * ERR_PTR() on error.
>    */
> -void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object *obj);
> +void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object *obj,
> +					 bool use_wc);

Could you make it an enum instead of a bool? Commit message suggests 
more modes will potentially be added and if so, and we start with an 
enum straight away, it will make for less churn in the future.

func(something, true) is always also quite unreadabe in the code because 
one has to remember or remind himself what it really means.

Something like func(something, MAP_WC) would be simply self-documenting.

>
>   /**
>    * i915_gem_object_unpin_map - releases an earlier mapping
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 8f50919..c431b40 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -2471,10 +2471,11 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
>   	list_del(&obj->global_list);
>
>   	if (obj->mapping) {
> -		if (is_vmalloc_addr(obj->mapping))
> -			vunmap(obj->mapping);
> +		void *ptr = (void *)((uintptr_t)obj->mapping & ~1);

How many bits we have to play with here? Is there a suitable define 
somewhere we could use for a mask instead of hardcoded "1" or we could 
add one if you think that would be better?

> +		if (is_vmalloc_addr(ptr))
> +			vunmap(ptr);
>   		else
> -			kunmap(kmap_to_page(obj->mapping));
> +			kunmap(kmap_to_page(ptr));
>   		obj->mapping = NULL;
>   	}
>
> @@ -2647,7 +2648,8 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
>   }
>
>   /* The 'mapping' part of i915_gem_object_pin_map() below */
> -static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
> +static void *i915_gem_object_map(const struct drm_i915_gem_object *obj,
> +				bool use_wc)
>   {
>   	unsigned long n_pages = obj->base.size >> PAGE_SHIFT;
>   	struct sg_table *sgt = obj->pages;
> @@ -2659,7 +2661,7 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
>   	void *addr;
>
>   	/* A single page can always be kmapped */
> -	if (n_pages == 1)
> +	if (n_pages == 1 && !use_wc)
>   		return kmap(sg_page(sgt->sgl));
>
>   	if (n_pages > ARRAY_SIZE(stack_pages)) {
> @@ -2675,7 +2677,8 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
>   	/* Check that we have the expected number of pages */
>   	GEM_BUG_ON(i != n_pages);
>
> -	addr = vmap(pages, n_pages, 0, PAGE_KERNEL);
> +	addr = vmap(pages, n_pages, VM_NO_GUARD,
> +		    use_wc ? pgprot_writecombine(PAGE_KERNEL_IO) : PAGE_KERNEL);

For educational benefit, what is the importance and difference between 
PAGE_KERNEL and PAGE_KERNEL_IO here?

>
>   	if (pages != stack_pages)
>   		drm_free_large(pages);
> @@ -2684,27 +2687,55 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
>   }
>
>   /* get, pin, and map the pages of the object into kernel space */
> -void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj)
> +void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, bool use_wc)
>   {
> +	void *ptr;
> +	bool has_wc;
> +	bool pinned;
>   	int ret;
>
>   	lockdep_assert_held(&obj->base.dev->struct_mutex);
> +	GEM_BUG_ON((obj->ops->flags & I915_GEM_OBJECT_HAS_STRUCT_PAGE) == 0);
>
>   	ret = i915_gem_object_get_pages(obj);
>   	if (ret)
>   		return ERR_PTR(ret);
>
> +	GEM_BUG_ON(obj->pages == NULL);

Looks like belongs to i915_gem_object_get_pages and not to callers.

>   	i915_gem_object_pin_pages(obj);
>
> -	if (!obj->mapping) {
> -		obj->mapping = i915_gem_object_map(obj);
> -		if (!obj->mapping) {
> -			i915_gem_object_unpin_pages(obj);
> -			return ERR_PTR(-ENOMEM);
> +	pinned = obj->pages_pin_count > 1;
> +	ptr = (void *)((uintptr_t)obj->mapping & ~1);
> +	has_wc = (uintptr_t)obj->mapping & 1;
> +
> +	if (ptr && has_wc != use_wc) {
> +		if (pinned) {
> +			ret = -EBUSY;
> +			goto err;
> +		}
> +
> +		if (is_vmalloc_addr(ptr))
> +			vunmap(ptr);
> +		else
> +			kunmap(kmap_to_page(ptr));
> +		ptr = obj->mapping = NULL;
> +	}
> +
> +	if (!ptr) {
> +		ptr = i915_gem_object_map(obj, use_wc);
> +		if (!ptr) {
> +			ret = -ENOMEM;
> +			goto err;
>   		}
> +
> +		obj->mapping = (void *)((uintptr_t)ptr | use_wc);
>   	}
>
> -	return obj->mapping;
> +	return ptr;
> +
> +err:
> +	i915_gem_object_unpin_pages(obj);
> +	return ERR_PTR(ret);
>   }
>
>   void i915_vma_move_to_active(struct i915_vma *vma,
> diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
> index 80bbe43..edcadce 100644
> --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
> +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
> @@ -115,7 +115,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
>   	if (ret)
>   		return ERR_PTR(ret);
>
> -	addr = i915_gem_object_pin_map(obj);
> +	addr = i915_gem_object_pin_map(obj, false);
>   	mutex_unlock(&dev->struct_mutex);
>
>   	return addr;
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index 009d7c0..c468619 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -1096,7 +1096,7 @@ static int guc_create_log_extras(struct intel_guc *guc)
>
>   	if (!guc->log.buf_addr) {
>   		/* Create a vmalloc mapping of log buffer pages */
> -		vaddr = i915_gem_object_pin_map(guc->log.obj);
> +		vaddr = i915_gem_object_pin_map(guc->log.obj, false);
>   		if (IS_ERR(vaddr)) {
>   			ret = PTR_ERR(vaddr);
>   			DRM_ERROR("Couldn't map log buffer pages %d\n", ret);
> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
> index 70c6990..0d41047 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -971,7 +971,7 @@ static int intel_lr_context_pin(struct i915_gem_context *ctx,
>   	if (ret)
>   		goto err;
>
> -	vaddr = i915_gem_object_pin_map(ce->state);
> +	vaddr = i915_gem_object_pin_map(ce->state, false);
>   	if (IS_ERR(vaddr)) {
>   		ret = PTR_ERR(vaddr);
>   		goto unpin_ctx_obj;
> @@ -1993,7 +1993,7 @@ lrc_setup_hws(struct intel_engine_cs *engine,
>   	/* The HWSP is part of the default context object in LRC mode. */
>   	engine->status_page.gfx_addr = i915_gem_obj_ggtt_offset(dctx_obj) +
>   				       LRC_PPHWSP_PN * PAGE_SIZE;
> -	hws = i915_gem_object_pin_map(dctx_obj);
> +	hws = i915_gem_object_pin_map(dctx_obj, false);
>   	if (IS_ERR(hws))
>   		return PTR_ERR(hws);
>   	engine->status_page.page_addr = hws + LRC_PPHWSP_PN * PAGE_SIZE;
> @@ -2324,7 +2324,7 @@ populate_lr_context(struct i915_gem_context *ctx,
>   		return ret;
>   	}
>
> -	vaddr = i915_gem_object_pin_map(ctx_obj);
> +	vaddr = i915_gem_object_pin_map(ctx_obj, false);
>   	if (IS_ERR(vaddr)) {
>   		ret = PTR_ERR(vaddr);
>   		DRM_DEBUG_DRIVER("Could not map object pages! (%d)\n", ret);
> @@ -2558,7 +2558,7 @@ void intel_lr_context_reset(struct drm_i915_private *dev_priv,
>   		if (!ctx_obj)
>   			continue;
>
> -		vaddr = i915_gem_object_pin_map(ctx_obj);
> +		vaddr = i915_gem_object_pin_map(ctx_obj, false);
>   		if (WARN_ON(IS_ERR(vaddr)))
>   			continue;
>
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 736ddba..a195f65 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -2007,7 +2007,7 @@ int intel_pin_and_map_ringbuffer_obj(struct drm_i915_private *dev_priv,
>   		if (ret)
>   			goto err_unpin;
>
> -		addr = i915_gem_object_pin_map(obj);
> +		addr = i915_gem_object_pin_map(obj, false);
>   		if (IS_ERR(addr)) {
>   			ret = PTR_ERR(addr);
>   			goto err_unpin;
>

The rest looks fine to me.

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions
  2016-07-10 13:41 ` [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions akash.goel
@ 2016-07-15 11:40   ` Tvrtko Ursulin
  2016-07-15 15:51     ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-15 11:40 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Akash Goel <akash.goel@intel.com>
>
> With the addition of new Host2GuC actions related to GuC logging, there
> is a need of a lock to serialize them, as they can execute concurrently
> with each other and also with other existing actions.

After which patch in this series is this required?

>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +++
>   drivers/gpu/drm/i915/intel_guc.h           | 3 +++
>   2 files changed, 6 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index 6043166..c1e637f 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -88,6 +88,7 @@ static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
>   		return -EINVAL;
>
>   	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
> +	spin_lock(&guc->action_lock);

The code below can sleep waiting for a response from GuC so you cannot 
use a spinlock. Mutex I suppose...

>
>   	dev_priv->guc.action_count += 1;
>   	dev_priv->guc.action_cmd = data[0];
> @@ -126,6 +127,7 @@ static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
>   	}
>   	dev_priv->guc.action_status = status;
>
> +	spin_unlock(&guc->action_lock);
>   	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
>
>   	return ret;
> @@ -1304,6 +1306,7 @@ int i915_guc_submission_init(struct drm_i915_private *dev_priv)
>   		return -ENOMEM;
>
>   	ida_init(&guc->ctx_ids);
> +	spin_lock_init(&guc->action_lock);

I think this should go to guc_client_alloc which is where the guc client 
object is allocated and initialized.

>   	guc_create_log(guc);
>   	guc_create_ads(guc);
>
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index d56bde6..611f4a7 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -157,6 +157,9 @@ struct intel_guc {
>
>   	uint64_t submissions[I915_NUM_ENGINES];
>   	uint32_t last_seqno[I915_NUM_ENGINES];
> +
> +	/* To serialize the Host2GuC actions */
> +	spinlock_t action_lock;
>   };
>
>   /* intel_guc_loader.c */
>

Regards,

Tvrtko

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/17] drm/i915: Support to create write combined type vmaps
  2016-07-15 11:31   ` Tvrtko Ursulin
@ 2016-07-15 11:45     ` Chris Wilson
  2016-07-15 16:30     ` Goel, Akash
  1 sibling, 0 replies; 87+ messages in thread
From: Chris Wilson @ 2016-07-15 11:45 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: akash.goel, intel-gfx

On Fri, Jul 15, 2016 at 12:31:23PM +0100, Tvrtko Ursulin wrote:

[snip good ideas, leaving the questions]

> >  /**
> >   * i915_gem_object_unpin_map - releases an earlier mapping
> >diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> >index 8f50919..c431b40 100644
> >--- a/drivers/gpu/drm/i915/i915_gem.c
> >+++ b/drivers/gpu/drm/i915/i915_gem.c
> >@@ -2471,10 +2471,11 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
> >  	list_del(&obj->global_list);
> >
> >  	if (obj->mapping) {
> >-		if (is_vmalloc_addr(obj->mapping))
> >-			vunmap(obj->mapping);
> >+		void *ptr = (void *)((uintptr_t)obj->mapping & ~1);
> 
> How many bits we have to play with here? Is there a suitable define
> somewhere we could use for a mask instead of hardcoded "1" or we
> could add one if you think that would be better?

The mapping is always page-aligned, so bits 0-11 are available.

PAGE_MASK should do the trick

> >-	addr = vmap(pages, n_pages, 0, PAGE_KERNEL);
> >+	addr = vmap(pages, n_pages, VM_NO_GUARD,
> >+		    use_wc ? pgprot_writecombine(PAGE_KERNEL_IO) : PAGE_KERNEL);
> 
> For educational benefit, what is the importance and difference
> between PAGE_KERNEL and PAGE_KERNEL_IO here?

One day I'll find out. We've always tagged our WC mmapings as
PAGE_KERNEL_IO, so cargo-culted it in.
 
> >
> >  	if (pages != stack_pages)
> >  		drm_free_large(pages);
> >@@ -2684,27 +2687,55 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
> >  }
> >
> >  /* get, pin, and map the pages of the object into kernel space */
> >-void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj)
> >+void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, bool use_wc)
> >  {
> >+	void *ptr;
> >+	bool has_wc;
> >+	bool pinned;
> >  	int ret;
> >
> >  	lockdep_assert_held(&obj->base.dev->struct_mutex);
> >+	GEM_BUG_ON((obj->ops->flags & I915_GEM_OBJECT_HAS_STRUCT_PAGE) == 0);
> >
> >  	ret = i915_gem_object_get_pages(obj);
> >  	if (ret)
> >  		return ERR_PTR(ret);
> >
> >+	GEM_BUG_ON(obj->pages == NULL);
> 
> Looks like belongs to i915_gem_object_get_pages and not to callers.

This is from later where it did:

        pinned = true;
        if (!atomic_inc_not_zero(&obj->mm.pages_pin_count)) {
                ret = ____i915_gem_object_get_pages(obj);
                if (ret)
                        goto err_unlock;

                smp_mb__before_atomic();
                GEM_BUG_ON(atomic_read(&obj->mm.pages_pin_count));
                atomic_set(&obj->mm.pages_pin_count, 1);
                pinned = false;
        }

        GEM_BUG_ON(obj->mm.pages == NULL);

Right now the BUG_ON is superfluous.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts
  2016-07-10 13:41 ` [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts akash.goel
@ 2016-07-15 11:51   ` Tvrtko Ursulin
  2016-07-15 15:58     ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-15 11:51 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Akash Goel <akash.goel@intel.com>
>
> GuC firmware sends an interrupt to flush the log buffer when it
> becomes half full. GuC firmware also tracks how many times the
> buffer overflowed.
> It would be useful to maintain a statistics of how many flush
> interrupts were received and for which type of log buffer,
> along with the overflow count of each buffer type.
> Augmented i915_log_info debugfs to report back these statistics.
>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_debugfs.c        | 26 ++++++++++++++++++++++++++
>   drivers/gpu/drm/i915/i915_guc_submission.c |  8 ++++++++
>   drivers/gpu/drm/i915/i915_irq.c            |  1 +
>   drivers/gpu/drm/i915/intel_guc.h           |  6 ++++++
>   4 files changed, 41 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 3c9c7f7..888a18a 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -2538,6 +2538,30 @@ static int i915_guc_load_status_info(struct seq_file *m, void *data)
>   	return 0;
>   }
>
> +static void i915_guc_log_info(struct seq_file *m,
> +				 struct drm_i915_private *dev_priv)
> +{
> +	struct intel_guc *guc = &dev_priv->guc;
> +
> +	seq_printf(m, "\nGuC logging stats:\n");
> +
> +	seq_printf(m, "\tISR:   flush count %10u, overflow count %8u\n",
> +		guc->log.flush_count[GUC_ISR_LOG_BUFFER],
> +		guc->log.total_overflow_count[GUC_ISR_LOG_BUFFER]);
> +
> +	seq_printf(m, "\tDPC:   flush count %10u, overflow count %8u\n",
> +		guc->log.flush_count[GUC_DPC_LOG_BUFFER],
> +		guc->log.total_overflow_count[GUC_DPC_LOG_BUFFER]);
> +
> +	seq_printf(m, "\tCRASH: flush count %10u, overflow count %8u\n",
> +		guc->log.flush_count[GUC_CRASH_DUMP_LOG_BUFFER],
> +		guc->log.total_overflow_count[GUC_CRASH_DUMP_LOG_BUFFER]);
> +
> +	seq_printf(m, "\tTotal flush interrupt count: %u\n",
> +			guc->log.flush_interrupt_count);
> +
> +}
> +
>   static void i915_guc_client_info(struct seq_file *m,
>   				 struct drm_i915_private *dev_priv,
>   				 struct i915_guc_client *client)
> @@ -2611,6 +2635,8 @@ static int i915_guc_info(struct seq_file *m, void *data)
>   	seq_printf(m, "\nGuC execbuf client @ %p:\n", guc.execbuf_client);
>   	i915_guc_client_info(m, dev_priv, &client);
>
> +	i915_guc_log_info(m, dev_priv);
> +
>   	/* Add more as required ... */
>
>   	return 0;
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index c1e637f..9c94a43 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -914,6 +914,14 @@ static void guc_read_update_log_buffer(struct drm_device *dev)
>   		log_buffer_state_local = *log_buffer_state;
>   		buffer_size = log_buffer_state_local.size;
>
> +		guc->log.flush_count[i] += log_buffer_state_local.flush_to_file;
> +		if (log_buffer_state_local.buffer_full_cnt !=
> +					guc->log.prev_overflow_count[i]) {
> +			guc->log.prev_overflow_count[i] =
> +					log_buffer_state_local.buffer_full_cnt;
> +			guc->log.total_overflow_count[i]++;

Is log_buffer_state_local.buffer_full_cnt guaranteed to be one here? Or 
you would need to increase total_overflow_count by its value?

> +		}
> +
>   		if (log_buffer_copy_state) {
>   			/* First copy the state structure */
>   			memcpy(log_buffer_copy_state, &log_buffer_state_local,
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index bdd7a67..c3fb67e 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1711,6 +1711,7 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
>   						&dev_priv->guc.events_work);
>   			}
>   		}
> +		dev_priv->guc.log.flush_interrupt_count++;
>   		spin_unlock(&dev_priv->irq_lock);
>   	}
>   }
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index 611f4a7..e911a32 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -128,6 +128,12 @@ struct intel_guc_log {
>   	struct workqueue_struct *wq;
>   	void *buf_addr;
>   	struct rchan *relay_chan;
> +
> +	/* logging related stats */
> +	u32 flush_interrupt_count;
> +	u32 prev_overflow_count[GUC_MAX_LOG_BUFFER];
> +	u32 total_overflow_count[GUC_MAX_LOG_BUFFER];
> +	u32 flush_count[GUC_MAX_LOG_BUFFER];
>   };
>
>   struct intel_guc {
>

Regards,

Tvrtko

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce flush interrupts
  2016-07-10 13:41 ` [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce " akash.goel
@ 2016-07-15 11:57   ` Tvrtko Ursulin
  2016-07-15 14:42     ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-15 11:57 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Akash Goel <akash.goel@intel.com>
>
> In cases where GuC generate logs at a very high rate, correspondingly
> the rate of flush interrupts is also very high.
> So far total 8 pages were allocated for storing both ISR & DPC logs.
> As per the half-full draining protocol followed by GuC, by doubling
> the number of pages, the frequency of flush interrupts can be cut down
> to almost half, which then helps in reducing the logging overhead.
> So now allocating 8 pages apiece for ISR & DPC logs.
>
> Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/intel_guc_fwif.h | 8 ++++----
>   1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
> index 1de6928..7521ed5 100644
> --- a/drivers/gpu/drm/i915/intel_guc_fwif.h
> +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
> @@ -104,9 +104,9 @@
>   #define   GUC_LOG_ALLOC_IN_MEGABYTE	(1 << 3)
>   #define   GUC_LOG_CRASH_PAGES		1
>   #define   GUC_LOG_CRASH_SHIFT		4
> -#define   GUC_LOG_DPC_PAGES		3
> +#define   GUC_LOG_DPC_PAGES		7
>   #define   GUC_LOG_DPC_SHIFT		6
> -#define   GUC_LOG_ISR_PAGES		3
> +#define   GUC_LOG_ISR_PAGES		7
>   #define   GUC_LOG_ISR_SHIFT		9
>   #define   GUC_LOG_BUF_ADDR_SHIFT	12
>
> @@ -436,9 +436,9 @@ enum guc_log_buffer_type {
>    *        |   Crash dump state header     |
>    * Page1  +-------------------------------+
>    *        |           ISR logs            |
> - * Page5  +-------------------------------+
> - *        |           DPC logs            |
>    * Page9  +-------------------------------+
> + *        |           DPC logs            |
> + * Page17 +-------------------------------+
>    *        |         Crash Dump logs       |
>    *        +-------------------------------+
>    *
>

I don't mind - but does it help? And how much and for what? Haven't you 
later found that the uncached reads were the main issue?

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce flush interrupts
  2016-07-15 11:57   ` Tvrtko Ursulin
@ 2016-07-15 14:42     ` Goel, Akash
  2016-07-15 15:07       ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-15 14:42 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/15/2016 5:27 PM, Tvrtko Ursulin wrote:
>
> On 10/07/16 14:41, akash.goel@intel.com wrote:
>> From: Akash Goel <akash.goel@intel.com>
>>
>> In cases where GuC generate logs at a very high rate, correspondingly
>> the rate of flush interrupts is also very high.
>> So far total 8 pages were allocated for storing both ISR & DPC logs.
>> As per the half-full draining protocol followed by GuC, by doubling
>> the number of pages, the frequency of flush interrupts can be cut down
>> to almost half, which then helps in reducing the logging overhead.
>> So now allocating 8 pages apiece for ISR & DPC logs.
>>
>> Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>> ---
>>   drivers/gpu/drm/i915/intel_guc_fwif.h | 8 ++++----
>>   1 file changed, 4 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h
>> b/drivers/gpu/drm/i915/intel_guc_fwif.h
>> index 1de6928..7521ed5 100644
>> --- a/drivers/gpu/drm/i915/intel_guc_fwif.h
>> +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
>> @@ -104,9 +104,9 @@
>>   #define   GUC_LOG_ALLOC_IN_MEGABYTE    (1 << 3)
>>   #define   GUC_LOG_CRASH_PAGES        1
>>   #define   GUC_LOG_CRASH_SHIFT        4
>> -#define   GUC_LOG_DPC_PAGES        3
>> +#define   GUC_LOG_DPC_PAGES        7
>>   #define   GUC_LOG_DPC_SHIFT        6
>> -#define   GUC_LOG_ISR_PAGES        3
>> +#define   GUC_LOG_ISR_PAGES        7
>>   #define   GUC_LOG_ISR_SHIFT        9
>>   #define   GUC_LOG_BUF_ADDR_SHIFT    12
>>
>> @@ -436,9 +436,9 @@ enum guc_log_buffer_type {
>>    *        |   Crash dump state header     |
>>    * Page1  +-------------------------------+
>>    *        |           ISR logs            |
>> - * Page5  +-------------------------------+
>> - *        |           DPC logs            |
>>    * Page9  +-------------------------------+
>> + *        |           DPC logs            |
>> + * Page17 +-------------------------------+
>>    *        |         Crash Dump logs       |
>>    *        +-------------------------------+
>>    *
>>
>
> I don't mind - but does it help? And how much and for what? Haven't you
> later found that the uncached reads were the main issue?
This change along with kthread patch, helped reduce the overflow counts 
and even eliminate them for some benchmarks.

Though with the impending optimization for Uncached reads there should 
be further improvements but in my view, notwithstanding the improvement 
w.r.t overflow count, its still a better configuration to work with as 
flush interrupt frequency is cut down to half and not able to see any 
apparent downsides to it.

Best Regards
Akash
>
> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce flush interrupts
  2016-07-15 14:42     ` Goel, Akash
@ 2016-07-15 15:07       ` Tvrtko Ursulin
  2016-07-15 16:20         ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-15 15:07 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 15/07/16 15:42, Goel, Akash wrote:
> On 7/15/2016 5:27 PM, Tvrtko Ursulin wrote:
>>
>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>> From: Akash Goel <akash.goel@intel.com>
>>>
>>> In cases where GuC generate logs at a very high rate, correspondingly
>>> the rate of flush interrupts is also very high.
>>> So far total 8 pages were allocated for storing both ISR & DPC logs.
>>> As per the half-full draining protocol followed by GuC, by doubling
>>> the number of pages, the frequency of flush interrupts can be cut down
>>> to almost half, which then helps in reducing the logging overhead.
>>> So now allocating 8 pages apiece for ISR & DPC logs.
>>>
>>> Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>> ---
>>>   drivers/gpu/drm/i915/intel_guc_fwif.h | 8 ++++----
>>>   1 file changed, 4 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h
>>> b/drivers/gpu/drm/i915/intel_guc_fwif.h
>>> index 1de6928..7521ed5 100644
>>> --- a/drivers/gpu/drm/i915/intel_guc_fwif.h
>>> +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
>>> @@ -104,9 +104,9 @@
>>>   #define   GUC_LOG_ALLOC_IN_MEGABYTE    (1 << 3)
>>>   #define   GUC_LOG_CRASH_PAGES        1
>>>   #define   GUC_LOG_CRASH_SHIFT        4
>>> -#define   GUC_LOG_DPC_PAGES        3
>>> +#define   GUC_LOG_DPC_PAGES        7
>>>   #define   GUC_LOG_DPC_SHIFT        6
>>> -#define   GUC_LOG_ISR_PAGES        3
>>> +#define   GUC_LOG_ISR_PAGES        7
>>>   #define   GUC_LOG_ISR_SHIFT        9
>>>   #define   GUC_LOG_BUF_ADDR_SHIFT    12
>>>
>>> @@ -436,9 +436,9 @@ enum guc_log_buffer_type {
>>>    *        |   Crash dump state header     |
>>>    * Page1  +-------------------------------+
>>>    *        |           ISR logs            |
>>> - * Page5  +-------------------------------+
>>> - *        |           DPC logs            |
>>>    * Page9  +-------------------------------+
>>> + *        |           DPC logs            |
>>> + * Page17 +-------------------------------+
>>>    *        |         Crash Dump logs       |
>>>    *        +-------------------------------+
>>>    *
>>>
>>
>> I don't mind - but does it help? And how much and for what? Haven't you
>> later found that the uncached reads were the main issue?
> This change along with kthread patch, helped reduce the overflow counts
> and even eliminate them for some benchmarks.
>
> Though with the impending optimization for Uncached reads there should
> be further improvements but in my view, notwithstanding the improvement
> w.r.t overflow count, its still a better configuration to work with as
> flush interrupt frequency is cut down to half and not able to see any
> apparent downsides to it.

I was primarily thinking to go with a minimal and simplest set of 
patches to implement the feature.

Logic was that apparently none of the smart and complex optimisations 
managed to solve the dropped interrupt issue, until the slowness of the 
uncached read was discovered to be the real/main issue.

So it seems that is something that definitely needs to be implemented. 
(Whether or not it will be possible to use SSE instructions to do the 
read I don't know.)

Assuming it is possible, then the question is whether there is need for 
all the other optimisations. Ie. do we need the kthread with rtprio or 
would a simple worker be enough? Do we need the new i915 param for 
tweaking the relay sub-buffers? Do we need the increase of the log 
buffer size? The extra patch to do smarter reads?

If we do not have the issue of the dropped interrupts with none of these 
extra patches applied, then we could afford to not bother with them now. 
Would make the series shorter and review easier and the feature in quicker.

Or maybe we do need all the advanced stuff, I don't know, I am just 
asking the question and would like to see some data.

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs
  2016-07-15 11:15   ` Tvrtko Ursulin
@ 2016-07-15 15:36     ` Goel, Akash
  2016-07-18 10:06       ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-15 15:36 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/15/2016 4:45 PM, Tvrtko Ursulin wrote:
>
> On 10/07/16 14:41, akash.goel@intel.com wrote:
>> From: Akash Goel <akash.goel@intel.com>
>>
>> On recieving the log buffer flush interrupt from GuC firmware, Driver
>> stores the snapshot of the log buffer in a local buffer, from which
>> Userspace can pull the logs. By default Driver store, up to, 4 snapshots
>> of the log buffer in a local buffer (managed by relay).
>> Added a new module (read only) param, 'guc_log_size', through which User
>> can specify the number of snapshots of log buffer to be stored in local
>> buffer. This can be used to ensure capturing of all boot time logs even
>> with high verbosity level.
>>
>> v2: Rename module param to more apt name 'guc_log_buffer_nr'. (Nikula)
>>
>> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>> ---
>>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +--
>>   drivers/gpu/drm/i915/i915_params.c         | 5 +++++
>>   drivers/gpu/drm/i915/i915_params.h         | 1 +
>>   3 files changed, 7 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>> index 2e3b723..009d7c0 100644
>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>> @@ -1046,8 +1046,7 @@ static int guc_create_log_relay_file(struct
>> intel_guc *guc)
>>
>>       /* Keep the size of sub buffers same as shared log buffer */
>>       subbuf_size = guc->log.obj->base.size;
>> -    /* TODO: Decide based on the User's input */
>> -    n_subbufs = 4;
>> +    n_subbufs = i915.guc_log_buffer_nr;
>>
>>       guc_log_relay_chan = relay_open("guc_log", log_dir,
>>               subbuf_size, n_subbufs, &relay_callbacks, dev);
>> diff --git a/drivers/gpu/drm/i915/i915_params.c
>> b/drivers/gpu/drm/i915/i915_params.c
>> index 8b13bfa..d30c972 100644
>> --- a/drivers/gpu/drm/i915/i915_params.c
>> +++ b/drivers/gpu/drm/i915/i915_params.c
>> @@ -57,6 +57,7 @@ struct i915_params i915 __read_mostly = {
>>       .enable_guc_loading = -1,
>>       .enable_guc_submission = -1,
>>       .guc_log_level = -1,
>> +    .guc_log_buffer_nr = 4,
>>       .enable_dp_mst = true,
>>       .inject_load_failure = 0,
>>       .enable_dpcd_backlight = false,
>> @@ -214,6 +215,10 @@ module_param_named(guc_log_level,
>> i915.guc_log_level, int, 0400);
>>   MODULE_PARM_DESC(guc_log_level,
>>       "GuC firmware logging level (-1:disabled (default), 0-3:enabled)");
>>
>> +module_param_named(guc_log_buffer_nr, i915.guc_log_buffer_nr, int,
>> 0400);
>> +MODULE_PARM_DESC(guc_log_buffer_nr,
>> +    "Number of sub buffers to store GuC firmware logs (default: 4)");
>> +
>>   module_param_named_unsafe(enable_dp_mst, i915.enable_dp_mst, bool,
>> 0600);
>>   MODULE_PARM_DESC(enable_dp_mst,
>>       "Enable multi-stream transport (MST) for new DisplayPort sinks.
>> (default: true)");
>> diff --git a/drivers/gpu/drm/i915/i915_params.h
>> b/drivers/gpu/drm/i915/i915_params.h
>> index 0ad020b..14ca855 100644
>> --- a/drivers/gpu/drm/i915/i915_params.h
>> +++ b/drivers/gpu/drm/i915/i915_params.h
>> @@ -48,6 +48,7 @@ struct i915_params {
>>       int enable_guc_loading;
>>       int enable_guc_submission;
>>       int guc_log_level;
>> +    int guc_log_buffer_nr;
>>       int use_mmio_flip;
>>       int mmio_debug;
>>       int edp_vswing;
>>
>
> I did not figure out after a quick read of
> Documentation/filesystems/relay.txt whether we really need this to be
> configurable?
>
> If I got it right number of sub-buffers here only has a relation to the
> userspace relay consumer latency. If the userspace is responsive should
> just two be enough? Or the existing default of four was shown in
> practice that it is better and good enough?
>
Yes one of the use of this module parameter is to give User some leeway 
i.e. more time to collect logs from the relay buffer. User may not be 
always able to match the rate at which logs are being produced from the 
GuC side.

2 could be too less.
Even 4, when running a benchmark, was proving less and not able to match 
the Driver rate (this might change after some optimization is done from 
User space side also, like splice).

The other use is to ensure capturing of all boot time logs, even with 
maximum verbosity level. The default number of sub buffers may not 
always be sufficient to store all the logs from boot, by the time User 
is ready to capture the logs.
Saw about 8 flush interrupts coming from GuC during the boot.

> I am just not sure this is a useful module parameter without some more
> data.
>
> Even if it is needed, as minimum I think the name should reflect this is
> about the relay side of things and not the GuC log buffer itself. So
> something like i915.guc_relay_log_subbuf_nr or something.
Fine will use this name.

> With the matching description of course.
>
Is the current description not apt ?
"Number of sub buffers to store GuC firmware logs (default: 4)");"

Best regards
Akash

> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions
  2016-07-15 11:40   ` Tvrtko Ursulin
@ 2016-07-15 15:51     ` Goel, Akash
  2016-07-18 10:12       ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-15 15:51 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/15/2016 5:10 PM, Tvrtko Ursulin wrote:
>
> On 10/07/16 14:41, akash.goel@intel.com wrote:
>> From: Akash Goel <akash.goel@intel.com>
>>
>> With the addition of new Host2GuC actions related to GuC logging, there
>> is a need of a lock to serialize them, as they can execute concurrently
>> with each other and also with other existing actions.
>
> After which patch in this series is this required?
>
 From patch 6 or 7 saw the problem, when enabled flush interrupts from 
boot (guc_log_level >= 0).

Also new HOST2GUC actions LOG_BUFFER_FILE_FLUSH_COMPLETE & 
UK_LOG_ENABLE_LOGGING can execute concurrently with each other.

>>
>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>> ---
>>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +++
>>   drivers/gpu/drm/i915/intel_guc.h           | 3 +++
>>   2 files changed, 6 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>> index 6043166..c1e637f 100644
>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>> @@ -88,6 +88,7 @@ static int host2guc_action(struct intel_guc *guc,
>> u32 *data, u32 len)
>>           return -EINVAL;
>>
>>       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
>> +    spin_lock(&guc->action_lock);
>
> The code below can sleep waiting for a response from GuC so you cannot
> use a spinlock. Mutex I suppose...

Sorry I missed the sleep.
Probably I did not see any problem, in spite of a spinlock, as _wait_for 
macro does not sleep when used in atomic context, does a busy wait instead.

Best Regards
Akash

>
>>
>>       dev_priv->guc.action_count += 1;
>>       dev_priv->guc.action_cmd = data[0];
>> @@ -126,6 +127,7 @@ static int host2guc_action(struct intel_guc *guc,
>> u32 *data, u32 len)
>>       }
>>       dev_priv->guc.action_status = status;
>>
>> +    spin_unlock(&guc->action_lock);
>>       intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
>>
>>       return ret;
>> @@ -1304,6 +1306,7 @@ int i915_guc_submission_init(struct
>> drm_i915_private *dev_priv)
>>           return -ENOMEM;
>>
>>       ida_init(&guc->ctx_ids);
>> +    spin_lock_init(&guc->action_lock);
>
> I think this should go to guc_client_alloc which is where the guc client
> object is allocated and initialized.
>
>>       guc_create_log(guc);
>>       guc_create_ads(guc);
>>
>> diff --git a/drivers/gpu/drm/i915/intel_guc.h
>> b/drivers/gpu/drm/i915/intel_guc.h
>> index d56bde6..611f4a7 100644
>> --- a/drivers/gpu/drm/i915/intel_guc.h
>> +++ b/drivers/gpu/drm/i915/intel_guc.h
>> @@ -157,6 +157,9 @@ struct intel_guc {
>>
>>       uint64_t submissions[I915_NUM_ENGINES];
>>       uint32_t last_seqno[I915_NUM_ENGINES];
>> +
>> +    /* To serialize the Host2GuC actions */
>> +    spinlock_t action_lock;
>>   };
>>
>>   /* intel_guc_loader.c */
>>
>
> Regards,
>
> Tvrtko
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts
  2016-07-15 11:51   ` Tvrtko Ursulin
@ 2016-07-15 15:58     ` Goel, Akash
  2016-07-18 10:16       ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-15 15:58 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/15/2016 5:21 PM, Tvrtko Ursulin wrote:
>
> On 10/07/16 14:41, akash.goel@intel.com wrote:
>> From: Akash Goel <akash.goel@intel.com>
>>
>> GuC firmware sends an interrupt to flush the log buffer when it
>> becomes half full. GuC firmware also tracks how many times the
>> buffer overflowed.
>> It would be useful to maintain a statistics of how many flush
>> interrupts were received and for which type of log buffer,
>> along with the overflow count of each buffer type.
>> Augmented i915_log_info debugfs to report back these statistics.
>>
>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>> ---
>>   drivers/gpu/drm/i915/i915_debugfs.c        | 26
>> ++++++++++++++++++++++++++
>>   drivers/gpu/drm/i915/i915_guc_submission.c |  8 ++++++++
>>   drivers/gpu/drm/i915/i915_irq.c            |  1 +
>>   drivers/gpu/drm/i915/intel_guc.h           |  6 ++++++
>>   4 files changed, 41 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>> b/drivers/gpu/drm/i915/i915_debugfs.c
>> index 3c9c7f7..888a18a 100644
>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>> @@ -2538,6 +2538,30 @@ static int i915_guc_load_status_info(struct
>> seq_file *m, void *data)
>>       return 0;
>>   }
>>
>> +static void i915_guc_log_info(struct seq_file *m,
>> +                 struct drm_i915_private *dev_priv)
>> +{
>> +    struct intel_guc *guc = &dev_priv->guc;
>> +
>> +    seq_printf(m, "\nGuC logging stats:\n");
>> +
>> +    seq_printf(m, "\tISR:   flush count %10u, overflow count %8u\n",
>> +        guc->log.flush_count[GUC_ISR_LOG_BUFFER],
>> +        guc->log.total_overflow_count[GUC_ISR_LOG_BUFFER]);
>> +
>> +    seq_printf(m, "\tDPC:   flush count %10u, overflow count %8u\n",
>> +        guc->log.flush_count[GUC_DPC_LOG_BUFFER],
>> +        guc->log.total_overflow_count[GUC_DPC_LOG_BUFFER]);
>> +
>> +    seq_printf(m, "\tCRASH: flush count %10u, overflow count %8u\n",
>> +        guc->log.flush_count[GUC_CRASH_DUMP_LOG_BUFFER],
>> +        guc->log.total_overflow_count[GUC_CRASH_DUMP_LOG_BUFFER]);
>> +
>> +    seq_printf(m, "\tTotal flush interrupt count: %u\n",
>> +            guc->log.flush_interrupt_count);
>> +
>> +}
>> +
>>   static void i915_guc_client_info(struct seq_file *m,
>>                    struct drm_i915_private *dev_priv,
>>                    struct i915_guc_client *client)
>> @@ -2611,6 +2635,8 @@ static int i915_guc_info(struct seq_file *m,
>> void *data)
>>       seq_printf(m, "\nGuC execbuf client @ %p:\n", guc.execbuf_client);
>>       i915_guc_client_info(m, dev_priv, &client);
>>
>> +    i915_guc_log_info(m, dev_priv);
>> +
>>       /* Add more as required ... */
>>
>>       return 0;
>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>> index c1e637f..9c94a43 100644
>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>> @@ -914,6 +914,14 @@ static void guc_read_update_log_buffer(struct
>> drm_device *dev)
>>           log_buffer_state_local = *log_buffer_state;
>>           buffer_size = log_buffer_state_local.size;
>>
>> +        guc->log.flush_count[i] += log_buffer_state_local.flush_to_file;
>> +        if (log_buffer_state_local.buffer_full_cnt !=
>> +                    guc->log.prev_overflow_count[i]) {
>> +            guc->log.prev_overflow_count[i] =
>> +                    log_buffer_state_local.buffer_full_cnt;
>> +            guc->log.total_overflow_count[i]++;
>
> Is log_buffer_state_local.buffer_full_cnt guaranteed to be one here? Or
> you would need to increase total_overflow_count by its value?
>

buffer_full_cnt will not remain as one. Its a 4 bit counter, will be 
incremented monotonically by GuC firmware on every new detection of 
overflow, so will increase from 0 to 15 & then wrap around.
Hence have to use '!=' in the condition instead of '>'.

Best regards
Akash

>> +        }
>> +
>>           if (log_buffer_copy_state) {
>>               /* First copy the state structure */
>>               memcpy(log_buffer_copy_state, &log_buffer_state_local,
>> diff --git a/drivers/gpu/drm/i915/i915_irq.c
>> b/drivers/gpu/drm/i915/i915_irq.c
>> index bdd7a67..c3fb67e 100644
>> --- a/drivers/gpu/drm/i915/i915_irq.c
>> +++ b/drivers/gpu/drm/i915/i915_irq.c
>> @@ -1711,6 +1711,7 @@ static void gen9_guc_irq_handler(struct
>> drm_i915_private *dev_priv, u32 gt_iir)
>>                           &dev_priv->guc.events_work);
>>               }
>>           }
>> +        dev_priv->guc.log.flush_interrupt_count++;
>>           spin_unlock(&dev_priv->irq_lock);
>>       }
>>   }
>> diff --git a/drivers/gpu/drm/i915/intel_guc.h
>> b/drivers/gpu/drm/i915/intel_guc.h
>> index 611f4a7..e911a32 100644
>> --- a/drivers/gpu/drm/i915/intel_guc.h
>> +++ b/drivers/gpu/drm/i915/intel_guc.h
>> @@ -128,6 +128,12 @@ struct intel_guc_log {
>>       struct workqueue_struct *wq;
>>       void *buf_addr;
>>       struct rchan *relay_chan;
>> +
>> +    /* logging related stats */
>> +    u32 flush_interrupt_count;
>> +    u32 prev_overflow_count[GUC_MAX_LOG_BUFFER];
>> +    u32 total_overflow_count[GUC_MAX_LOG_BUFFER];
>> +    u32 flush_count[GUC_MAX_LOG_BUFFER];
>>   };
>>
>>   struct intel_guc {
>>
>
> Regards,
>
> Tvrtko
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce flush interrupts
  2016-07-15 15:07       ` Tvrtko Ursulin
@ 2016-07-15 16:20         ` Goel, Akash
  2016-07-18  9:54           ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-15 16:20 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/15/2016 8:37 PM, Tvrtko Ursulin wrote:
>
> On 15/07/16 15:42, Goel, Akash wrote:
>> On 7/15/2016 5:27 PM, Tvrtko Ursulin wrote:
>>>
>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>> From: Akash Goel <akash.goel@intel.com>
>>>>
>>>> In cases where GuC generate logs at a very high rate, correspondingly
>>>> the rate of flush interrupts is also very high.
>>>> So far total 8 pages were allocated for storing both ISR & DPC logs.
>>>> As per the half-full draining protocol followed by GuC, by doubling
>>>> the number of pages, the frequency of flush interrupts can be cut down
>>>> to almost half, which then helps in reducing the logging overhead.
>>>> So now allocating 8 pages apiece for ISR & DPC logs.
>>>>
>>>> Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>> ---
>>>>   drivers/gpu/drm/i915/intel_guc_fwif.h | 8 ++++----
>>>>   1 file changed, 4 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>> b/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>> index 1de6928..7521ed5 100644
>>>> --- a/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>> +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>> @@ -104,9 +104,9 @@
>>>>   #define   GUC_LOG_ALLOC_IN_MEGABYTE    (1 << 3)
>>>>   #define   GUC_LOG_CRASH_PAGES        1
>>>>   #define   GUC_LOG_CRASH_SHIFT        4
>>>> -#define   GUC_LOG_DPC_PAGES        3
>>>> +#define   GUC_LOG_DPC_PAGES        7
>>>>   #define   GUC_LOG_DPC_SHIFT        6
>>>> -#define   GUC_LOG_ISR_PAGES        3
>>>> +#define   GUC_LOG_ISR_PAGES        7
>>>>   #define   GUC_LOG_ISR_SHIFT        9
>>>>   #define   GUC_LOG_BUF_ADDR_SHIFT    12
>>>>
>>>> @@ -436,9 +436,9 @@ enum guc_log_buffer_type {
>>>>    *        |   Crash dump state header     |
>>>>    * Page1  +-------------------------------+
>>>>    *        |           ISR logs            |
>>>> - * Page5  +-------------------------------+
>>>> - *        |           DPC logs            |
>>>>    * Page9  +-------------------------------+
>>>> + *        |           DPC logs            |
>>>> + * Page17 +-------------------------------+
>>>>    *        |         Crash Dump logs       |
>>>>    *        +-------------------------------+
>>>>    *
>>>>
>>>
>>> I don't mind - but does it help? And how much and for what? Haven't you
>>> later found that the uncached reads were the main issue?
>> This change along with kthread patch, helped reduce the overflow counts
>> and even eliminate them for some benchmarks.
>>
>> Though with the impending optimization for Uncached reads there should
>> be further improvements but in my view, notwithstanding the improvement
>> w.r.t overflow count, its still a better configuration to work with as
>> flush interrupt frequency is cut down to half and not able to see any
>> apparent downsides to it.
>
> I was primarily thinking to go with a minimal and simplest set of
> patches to implement the feature.
>
I second that and working with the same intent.

> Logic was that apparently none of the smart and complex optimisations
> managed to solve the dropped interrupt issue, until the slowness of the
> uncached read was discovered to be the real/main issue.
>
> So it seems that is something that definitely needs to be implemented.
> (Whether or not it will be possible to use SSE instructions to do the
> read I don't know.)
>

log buffer resizing and rt priority kthread changes have definitely 
helped significantly.

Only of late we realized that there is a potential way to speed up 
Uncached reads also. Moreover I am yet to test that on kernel side.
So until that is tested & proves to be enough, we have to rely on the 
other optimizations & can't dismiss them

> Assuming it is possible, then the question is whether there is need for
> all the other optimisations. Ie. do we need the kthread with rtprio or
> would a simple worker be enough?
I think we can take a call, once we have the results with Uncached read 
optimization.

> Do we need the new i915 param for tweaking the relay sub-buffers?
In my opinion it will be really useful to have this provision, as I
tried to explain in the other mail.

> Do we need the increase of the log buffer size?
Though this seems to be a benign change which is definitely good to 
have, but again can decide upon it once we have the results.

The extra patch to do smarter reads?
>
> If we do not have the issue of the dropped interrupts with none of these
> extra patches applied, then we could afford to not bother with them now.
> Would make the series shorter and review easier and the feature in quicker.
>
Agree with you.
Had none of these optimizations in the initial version of the series, 
but was compelled to add them later when realized the rate at which GuC 
was generating the logs.

Best regards
Akash

> Or maybe we do need all the advanced stuff, I don't know, I am just
> asking the question and would like to see some data.
>
> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/17] drm/i915: Support to create write combined type vmaps
  2016-07-15 11:31   ` Tvrtko Ursulin
  2016-07-15 11:45     ` Chris Wilson
@ 2016-07-15 16:30     ` Goel, Akash
  2016-07-18 10:18       ` Tvrtko Ursulin
  1 sibling, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-15 16:30 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/15/2016 5:01 PM, Tvrtko Ursulin wrote:
>
> On 10/07/16 14:41, akash.goel@intel.com wrote:
>> From: Chris Wilson <chris@chris-wilson.co.uk>
>>
>> vmaps has a provision for controlling the page protection bits, with
>> which
>> we can use to control the mapping type, e.g. WB, WC, UC or even WT.
>> To allow the caller to choose their mapping type, we add a parameter to
>> i915_gem_object_pin_map - but we still only allow one vmap to be cached
>> per object. If the object is currently not pinned, then we recreate the
>> previous vmap with the new access type, but if it was pinned we report an
>> error. This effectively limits the access via i915_gem_object_pin_map
>> to a
>> single mapping type for the lifetime of the object. Not usually a
>> problem,
>> but something to be aware of when setting up the object's vmap.
>>
>> We will want to vary the access type to enable WC mappings of ringbuffer
>> and context objects on !llc platforms, as well as other objects where we
>> need coherent access to the GPU's pages without going through the GTT
>>
>> v2: Remove the redundant braces around pin count check and fix the marker
>>      in documentation (Chris)
>>
>> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>> ---
>>   drivers/gpu/drm/i915/i915_drv.h            |  4 ++-
>>   drivers/gpu/drm/i915/i915_gem.c            | 57
>> +++++++++++++++++++++++-------
>>   drivers/gpu/drm/i915/i915_gem_dmabuf.c     |  2 +-
>>   drivers/gpu/drm/i915/i915_guc_submission.c |  2 +-
>>   drivers/gpu/drm/i915/intel_lrc.c           |  8 ++---
>>   drivers/gpu/drm/i915/intel_ringbuffer.c    |  2 +-
>>   6 files changed, 54 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_drv.h
>> b/drivers/gpu/drm/i915/i915_drv.h
>> index 6e2ddfa..84afa17 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.h
>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> @@ -3248,6 +3248,7 @@ static inline void
>> i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
>>   /**
>>    * i915_gem_object_pin_map - return a contiguous mapping of the
>> entire object
>>    * @obj - the object to map into kernel address space
>> + * @use_wc - whether the mapping should be using WC or WB pgprot_t
>>    *
>>    * Calls i915_gem_object_pin_pages() to prevent reaping of the object's
>>    * pages and then returns a contiguous mapping of the backing
>> storage into
>> @@ -3259,7 +3260,8 @@ static inline void
>> i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
>>    * Returns the pointer through which to access the mapped object, or an
>>    * ERR_PTR() on error.
>>    */
>> -void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object
>> *obj);
>> +void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object
>> *obj,
>> +                     bool use_wc);
>
> Could you make it an enum instead of a bool? Commit message suggests
> more modes will potentially be added and if so, and we start with an
> enum straight away, it will make for less churn in the future.
>
> func(something, true) is always also quite unreadabe in the code because
> one has to remember or remind himself what it really means.
>
> Something like func(something, MAP_WC) would be simply self-documenting.
>
Thanks nice suggestion, will do that.
enum only or macros also will do ?
#define MAP_CACHED	0x1
#define MAP_WC		0x2

>>
>>   /**
>>    * i915_gem_object_unpin_map - releases an earlier mapping
>> diff --git a/drivers/gpu/drm/i915/i915_gem.c
>> b/drivers/gpu/drm/i915/i915_gem.c
>> index 8f50919..c431b40 100644
>> --- a/drivers/gpu/drm/i915/i915_gem.c
>> +++ b/drivers/gpu/drm/i915/i915_gem.c
>> @@ -2471,10 +2471,11 @@ i915_gem_object_put_pages(struct
>> drm_i915_gem_object *obj)
>>       list_del(&obj->global_list);
>>
>>       if (obj->mapping) {
>> -        if (is_vmalloc_addr(obj->mapping))
>> -            vunmap(obj->mapping);
>> +        void *ptr = (void *)((uintptr_t)obj->mapping & ~1);
>
> How many bits we have to play with here? Is there a suitable define
> somewhere we could use for a mask instead of hardcoded "1" or we could
> add one if you think that would be better?

As Chris said, will use PAGE_MASK.

>
>> +        if (is_vmalloc_addr(ptr))
>> +            vunmap(ptr);
>>           else
>> -            kunmap(kmap_to_page(obj->mapping));
>> +            kunmap(kmap_to_page(ptr));
>>           obj->mapping = NULL;
>>       }
>>
>> @@ -2647,7 +2648,8 @@ i915_gem_object_get_pages(struct
>> drm_i915_gem_object *obj)
>>   }
>>
>>   /* The 'mapping' part of i915_gem_object_pin_map() below */
>> -static void *i915_gem_object_map(const struct drm_i915_gem_object *obj)
>> +static void *i915_gem_object_map(const struct drm_i915_gem_object *obj,
>> +                bool use_wc)
>>   {
>>       unsigned long n_pages = obj->base.size >> PAGE_SHIFT;
>>       struct sg_table *sgt = obj->pages;
>> @@ -2659,7 +2661,7 @@ static void *i915_gem_object_map(const struct
>> drm_i915_gem_object *obj)
>>       void *addr;
>>
>>       /* A single page can always be kmapped */
>> -    if (n_pages == 1)
>> +    if (n_pages == 1 && !use_wc)
>>           return kmap(sg_page(sgt->sgl));
>>
>>       if (n_pages > ARRAY_SIZE(stack_pages)) {
>> @@ -2675,7 +2677,8 @@ static void *i915_gem_object_map(const struct
>> drm_i915_gem_object *obj)
>>       /* Check that we have the expected number of pages */
>>       GEM_BUG_ON(i != n_pages);
>>
>> -    addr = vmap(pages, n_pages, 0, PAGE_KERNEL);
>> +    addr = vmap(pages, n_pages, VM_NO_GUARD,
>> +            use_wc ? pgprot_writecombine(PAGE_KERNEL_IO) : PAGE_KERNEL);
>
> For educational benefit, what is the importance and difference between
> PAGE_KERNEL and PAGE_KERNEL_IO here?
>
>>
>>       if (pages != stack_pages)
>>           drm_free_large(pages);
>> @@ -2684,27 +2687,55 @@ static void *i915_gem_object_map(const struct
>> drm_i915_gem_object *obj)
>>   }
>>
>>   /* get, pin, and map the pages of the object into kernel space */
>> -void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj)
>> +void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, bool
>> use_wc)
>>   {
>> +    void *ptr;
>> +    bool has_wc;
>> +    bool pinned;
>>       int ret;
>>
>>       lockdep_assert_held(&obj->base.dev->struct_mutex);
>> +    GEM_BUG_ON((obj->ops->flags & I915_GEM_OBJECT_HAS_STRUCT_PAGE) ==
>> 0);
>>
>>       ret = i915_gem_object_get_pages(obj);
>>       if (ret)
>>           return ERR_PTR(ret);
>>
>> +    GEM_BUG_ON(obj->pages == NULL);
>
> Looks like belongs to i915_gem_object_get_pages and not to callers.
>

As Chris said, this is superfluous, so will remove it.

Best regards
Akash

>>       i915_gem_object_pin_pages(obj);
>>
>> -    if (!obj->mapping) {
>> -        obj->mapping = i915_gem_object_map(obj);
>> -        if (!obj->mapping) {
>> -            i915_gem_object_unpin_pages(obj);
>> -            return ERR_PTR(-ENOMEM);
>> +    pinned = obj->pages_pin_count > 1;
>> +    ptr = (void *)((uintptr_t)obj->mapping & ~1);
>> +    has_wc = (uintptr_t)obj->mapping & 1;
>> +
>> +    if (ptr && has_wc != use_wc) {
>> +        if (pinned) {
>> +            ret = -EBUSY;
>> +            goto err;
>> +        }
>> +
>> +        if (is_vmalloc_addr(ptr))
>> +            vunmap(ptr);
>> +        else
>> +            kunmap(kmap_to_page(ptr));
>> +        ptr = obj->mapping = NULL;
>> +    }
>> +
>> +    if (!ptr) {
>> +        ptr = i915_gem_object_map(obj, use_wc);
>> +        if (!ptr) {
>> +            ret = -ENOMEM;
>> +            goto err;
>>           }
>> +
>> +        obj->mapping = (void *)((uintptr_t)ptr | use_wc);
>>       }
>>
>> -    return obj->mapping;
>> +    return ptr;
>> +
>> +err:
>> +    i915_gem_object_unpin_pages(obj);
>> +    return ERR_PTR(ret);
>>   }
>>
>>   void i915_vma_move_to_active(struct i915_vma *vma,
>> diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
>> b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
>> index 80bbe43..edcadce 100644
>> --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
>> +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
>> @@ -115,7 +115,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf
>> *dma_buf)
>>       if (ret)
>>           return ERR_PTR(ret);
>>
>> -    addr = i915_gem_object_pin_map(obj);
>> +    addr = i915_gem_object_pin_map(obj, false);
>>       mutex_unlock(&dev->struct_mutex);
>>
>>       return addr;
>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>> index 009d7c0..c468619 100644
>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>> @@ -1096,7 +1096,7 @@ static int guc_create_log_extras(struct
>> intel_guc *guc)
>>
>>       if (!guc->log.buf_addr) {
>>           /* Create a vmalloc mapping of log buffer pages */
>> -        vaddr = i915_gem_object_pin_map(guc->log.obj);
>> +        vaddr = i915_gem_object_pin_map(guc->log.obj, false);
>>           if (IS_ERR(vaddr)) {
>>               ret = PTR_ERR(vaddr);
>>               DRM_ERROR("Couldn't map log buffer pages %d\n", ret);
>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c
>> b/drivers/gpu/drm/i915/intel_lrc.c
>> index 70c6990..0d41047 100644
>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>> @@ -971,7 +971,7 @@ static int intel_lr_context_pin(struct
>> i915_gem_context *ctx,
>>       if (ret)
>>           goto err;
>>
>> -    vaddr = i915_gem_object_pin_map(ce->state);
>> +    vaddr = i915_gem_object_pin_map(ce->state, false);
>>       if (IS_ERR(vaddr)) {
>>           ret = PTR_ERR(vaddr);
>>           goto unpin_ctx_obj;
>> @@ -1993,7 +1993,7 @@ lrc_setup_hws(struct intel_engine_cs *engine,
>>       /* The HWSP is part of the default context object in LRC mode. */
>>       engine->status_page.gfx_addr = i915_gem_obj_ggtt_offset(dctx_obj) +
>>                          LRC_PPHWSP_PN * PAGE_SIZE;
>> -    hws = i915_gem_object_pin_map(dctx_obj);
>> +    hws = i915_gem_object_pin_map(dctx_obj, false);
>>       if (IS_ERR(hws))
>>           return PTR_ERR(hws);
>>       engine->status_page.page_addr = hws + LRC_PPHWSP_PN * PAGE_SIZE;
>> @@ -2324,7 +2324,7 @@ populate_lr_context(struct i915_gem_context *ctx,
>>           return ret;
>>       }
>>
>> -    vaddr = i915_gem_object_pin_map(ctx_obj);
>> +    vaddr = i915_gem_object_pin_map(ctx_obj, false);
>>       if (IS_ERR(vaddr)) {
>>           ret = PTR_ERR(vaddr);
>>           DRM_DEBUG_DRIVER("Could not map object pages! (%d)\n", ret);
>> @@ -2558,7 +2558,7 @@ void intel_lr_context_reset(struct
>> drm_i915_private *dev_priv,
>>           if (!ctx_obj)
>>               continue;
>>
>> -        vaddr = i915_gem_object_pin_map(ctx_obj);
>> +        vaddr = i915_gem_object_pin_map(ctx_obj, false);
>>           if (WARN_ON(IS_ERR(vaddr)))
>>               continue;
>>
>> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c
>> b/drivers/gpu/drm/i915/intel_ringbuffer.c
>> index 736ddba..a195f65 100644
>> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
>> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
>> @@ -2007,7 +2007,7 @@ int intel_pin_and_map_ringbuffer_obj(struct
>> drm_i915_private *dev_priv,
>>           if (ret)
>>               goto err_unpin;
>>
>> -        addr = i915_gem_object_pin_map(obj);
>> +        addr = i915_gem_object_pin_map(obj, false);
>>           if (IS_ERR(addr)) {
>>               ret = PTR_ERR(addr);
>>               goto err_unpin;
>>
>
> The rest looks fine to me.
>
> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce flush interrupts
  2016-07-15 16:20         ` Goel, Akash
@ 2016-07-18  9:54           ` Tvrtko Ursulin
  2016-07-18 12:35             ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-18  9:54 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 15/07/16 17:20, Goel, Akash wrote:
> On 7/15/2016 8:37 PM, Tvrtko Ursulin wrote:
>> On 15/07/16 15:42, Goel, Akash wrote:
>>> On 7/15/2016 5:27 PM, Tvrtko Ursulin wrote:
>>>>
>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>> From: Akash Goel <akash.goel@intel.com>
>>>>>
>>>>> In cases where GuC generate logs at a very high rate, correspondingly
>>>>> the rate of flush interrupts is also very high.
>>>>> So far total 8 pages were allocated for storing both ISR & DPC logs.
>>>>> As per the half-full draining protocol followed by GuC, by doubling
>>>>> the number of pages, the frequency of flush interrupts can be cut down
>>>>> to almost half, which then helps in reducing the logging overhead.
>>>>> So now allocating 8 pages apiece for ISR & DPC logs.
>>>>>
>>>>> Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>> ---
>>>>>   drivers/gpu/drm/i915/intel_guc_fwif.h | 8 ++++----
>>>>>   1 file changed, 4 insertions(+), 4 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>> b/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>> index 1de6928..7521ed5 100644
>>>>> --- a/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>> +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>> @@ -104,9 +104,9 @@
>>>>>   #define   GUC_LOG_ALLOC_IN_MEGABYTE    (1 << 3)
>>>>>   #define   GUC_LOG_CRASH_PAGES        1
>>>>>   #define   GUC_LOG_CRASH_SHIFT        4
>>>>> -#define   GUC_LOG_DPC_PAGES        3
>>>>> +#define   GUC_LOG_DPC_PAGES        7
>>>>>   #define   GUC_LOG_DPC_SHIFT        6
>>>>> -#define   GUC_LOG_ISR_PAGES        3
>>>>> +#define   GUC_LOG_ISR_PAGES        7
>>>>>   #define   GUC_LOG_ISR_SHIFT        9
>>>>>   #define   GUC_LOG_BUF_ADDR_SHIFT    12
>>>>>
>>>>> @@ -436,9 +436,9 @@ enum guc_log_buffer_type {
>>>>>    *        |   Crash dump state header     |
>>>>>    * Page1  +-------------------------------+
>>>>>    *        |           ISR logs            |
>>>>> - * Page5  +-------------------------------+
>>>>> - *        |           DPC logs            |
>>>>>    * Page9  +-------------------------------+
>>>>> + *        |           DPC logs            |
>>>>> + * Page17 +-------------------------------+
>>>>>    *        |         Crash Dump logs       |
>>>>>    *        +-------------------------------+
>>>>>    *
>>>>>
>>>>
>>>> I don't mind - but does it help? And how much and for what? Haven't you
>>>> later found that the uncached reads were the main issue?
>>> This change along with kthread patch, helped reduce the overflow counts
>>> and even eliminate them for some benchmarks.
>>>
>>> Though with the impending optimization for Uncached reads there should
>>> be further improvements but in my view, notwithstanding the improvement
>>> w.r.t overflow count, its still a better configuration to work with as
>>> flush interrupt frequency is cut down to half and not able to see any
>>> apparent downsides to it.
>>
>> I was primarily thinking to go with a minimal and simplest set of
>> patches to implement the feature.
>>
> I second that and working with the same intent.
>
>> Logic was that apparently none of the smart and complex optimisations
>> managed to solve the dropped interrupt issue, until the slowness of the
>> uncached read was discovered to be the real/main issue.
>>
>> So it seems that is something that definitely needs to be implemented.
>> (Whether or not it will be possible to use SSE instructions to do the
>> read I don't know.)
>>
>
> log buffer resizing and rt priority kthread changes have definitely
> helped significantly.
>
> Only of late we realized that there is a potential way to speed up
> Uncached reads also. Moreover I am yet to test that on kernel side.
> So until that is tested & proves to be enough, we have to rely on the
> other optimizations & can't dismiss them

Maybe, depends if, what I thought was the case, none of the other 
optimizations actually enabled a drop-free logging in all interesting 
scenarios.

If we conclude that simply improving the copy speed removes the need for 
any other optimisations and complications, we can talk about whether 
every individual one of those still makes sense.

>> Assuming it is possible, then the question is whether there is need for
>> all the other optimisations. Ie. do we need the kthread with rtprio or
>> would a simple worker be enough?
> I think we can take a call, once we have the results with Uncached read
> optimization.

Agreed. Lets see how that works out and the discuss on how the final 
series should look like.

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs
  2016-07-15 15:36     ` Goel, Akash
@ 2016-07-18 10:06       ` Tvrtko Ursulin
  2016-07-18 12:19         ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-18 10:06 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 15/07/16 16:36, Goel, Akash wrote:
> On 7/15/2016 4:45 PM, Tvrtko Ursulin wrote:
>>
>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>> From: Akash Goel <akash.goel@intel.com>
>>>
>>> On recieving the log buffer flush interrupt from GuC firmware, Driver
>>> stores the snapshot of the log buffer in a local buffer, from which
>>> Userspace can pull the logs. By default Driver store, up to, 4 snapshots
>>> of the log buffer in a local buffer (managed by relay).
>>> Added a new module (read only) param, 'guc_log_size', through which User
>>> can specify the number of snapshots of log buffer to be stored in local
>>> buffer. This can be used to ensure capturing of all boot time logs even
>>> with high verbosity level.
>>>
>>> v2: Rename module param to more apt name 'guc_log_buffer_nr'. (Nikula)
>>>
>>> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>> ---
>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +--
>>>   drivers/gpu/drm/i915/i915_params.c         | 5 +++++
>>>   drivers/gpu/drm/i915/i915_params.h         | 1 +
>>>   3 files changed, 7 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> index 2e3b723..009d7c0 100644
>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> @@ -1046,8 +1046,7 @@ static int guc_create_log_relay_file(struct
>>> intel_guc *guc)
>>>
>>>       /* Keep the size of sub buffers same as shared log buffer */
>>>       subbuf_size = guc->log.obj->base.size;
>>> -    /* TODO: Decide based on the User's input */
>>> -    n_subbufs = 4;
>>> +    n_subbufs = i915.guc_log_buffer_nr;
>>>
>>>       guc_log_relay_chan = relay_open("guc_log", log_dir,
>>>               subbuf_size, n_subbufs, &relay_callbacks, dev);
>>> diff --git a/drivers/gpu/drm/i915/i915_params.c
>>> b/drivers/gpu/drm/i915/i915_params.c
>>> index 8b13bfa..d30c972 100644
>>> --- a/drivers/gpu/drm/i915/i915_params.c
>>> +++ b/drivers/gpu/drm/i915/i915_params.c
>>> @@ -57,6 +57,7 @@ struct i915_params i915 __read_mostly = {
>>>       .enable_guc_loading = -1,
>>>       .enable_guc_submission = -1,
>>>       .guc_log_level = -1,
>>> +    .guc_log_buffer_nr = 4,
>>>       .enable_dp_mst = true,
>>>       .inject_load_failure = 0,
>>>       .enable_dpcd_backlight = false,
>>> @@ -214,6 +215,10 @@ module_param_named(guc_log_level,
>>> i915.guc_log_level, int, 0400);
>>>   MODULE_PARM_DESC(guc_log_level,
>>>       "GuC firmware logging level (-1:disabled (default),
>>> 0-3:enabled)");
>>>
>>> +module_param_named(guc_log_buffer_nr, i915.guc_log_buffer_nr, int,
>>> 0400);
>>> +MODULE_PARM_DESC(guc_log_buffer_nr,
>>> +    "Number of sub buffers to store GuC firmware logs (default: 4)");
>>> +
>>>   module_param_named_unsafe(enable_dp_mst, i915.enable_dp_mst, bool,
>>> 0600);
>>>   MODULE_PARM_DESC(enable_dp_mst,
>>>       "Enable multi-stream transport (MST) for new DisplayPort sinks.
>>> (default: true)");
>>> diff --git a/drivers/gpu/drm/i915/i915_params.h
>>> b/drivers/gpu/drm/i915/i915_params.h
>>> index 0ad020b..14ca855 100644
>>> --- a/drivers/gpu/drm/i915/i915_params.h
>>> +++ b/drivers/gpu/drm/i915/i915_params.h
>>> @@ -48,6 +48,7 @@ struct i915_params {
>>>       int enable_guc_loading;
>>>       int enable_guc_submission;
>>>       int guc_log_level;
>>> +    int guc_log_buffer_nr;
>>>       int use_mmio_flip;
>>>       int mmio_debug;
>>>       int edp_vswing;
>>>
>>
>> I did not figure out after a quick read of
>> Documentation/filesystems/relay.txt whether we really need this to be
>> configurable?
>>
>> If I got it right number of sub-buffers here only has a relation to the
>> userspace relay consumer latency. If the userspace is responsive should
>> just two be enough? Or the existing default of four was shown in
>> practice that it is better and good enough?
>>
> Yes one of the use of this module parameter is to give User some leeway
> i.e. more time to collect logs from the relay buffer. User may not be
> always able to match the rate at which logs are being produced from the
> GuC side.
>
> 2 could be too less.
> Even 4, when running a benchmark, was proving less and not able to match
> the Driver rate (this might change after some optimization is done from
> User space side also, like splice).

Okay, it makes sense for it to be bigger than four by default then, correct?

> The other use is to ensure capturing of all boot time logs, even with
> maximum verbosity level. The default number of sub buffers may not
> always be sufficient to store all the logs from boot, by the time User
> is ready to capture the logs.
> Saw about 8 flush interrupts coming from GuC during the boot.

How important it is for a default value to capture all activity since boot?

I think we need to keep in mind here that amount of that activity may be 
a lot different with different setups so it might not be that 
interesting after all.

Someone will log in via a display manager, which may generate a widely 
differing amount of GPU activity, until they start the logger. Someone 
else on the other hand might be booting to vt only, starting the logger, 
and only then starting the graphical UI.

>> I am just not sure this is a useful module parameter without some more
>> data.
>>
>> Even if it is needed, as minimum I think the name should reflect this is
>> about the relay side of things and not the GuC log buffer itself. So
>> something like i915.guc_relay_log_subbuf_nr or something.
> Fine will use this name.
>
>> With the matching description of course.
>>
> Is the current description not apt ?
> "Number of sub buffers to store GuC firmware logs (default: 4)");"

My thinking is, what will this parameter mostly be used for? I think the 
default needs to be such that a reasonable implementation of an 
userspace logger can cope with the flush rate. I am not so sure that 
capturing boot time activity by default is that critical.

Assuming you find a value to satisfy the above, what are the scenarios 
someone will need/want to tweak it and what description of the tunable 
would help them understand what it is for?

Should we say, in the description, something like "increase this if you 
want to capture all boot time activity until you can start the logging" 
and/or "increase this if experiencing logging drops" ?

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions
  2016-07-15 15:51     ` Goel, Akash
@ 2016-07-18 10:12       ` Tvrtko Ursulin
  2016-07-18 10:46         ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-18 10:12 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 15/07/16 16:51, Goel, Akash wrote:
>
>
> On 7/15/2016 5:10 PM, Tvrtko Ursulin wrote:
>>
>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>> From: Akash Goel <akash.goel@intel.com>
>>>
>>> With the addition of new Host2GuC actions related to GuC logging, there
>>> is a need of a lock to serialize them, as they can execute concurrently
>>> with each other and also with other existing actions.
>>
>> After which patch in this series is this required?
>>
>  From patch 6 or 7 saw the problem, when enabled flush interrupts from
> boot (guc_log_level >= 0).

That means this patch should come before 6 or 7. :)

> Also new HOST2GUC actions LOG_BUFFER_FILE_FLUSH_COMPLETE &
> UK_LOG_ENABLE_LOGGING can execute concurrently with each other.

Right I see, from the worker/thread vs debugfs activity.

>>>
>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>> ---
>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +++
>>>   drivers/gpu/drm/i915/intel_guc.h           | 3 +++
>>>   2 files changed, 6 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> index 6043166..c1e637f 100644
>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> @@ -88,6 +88,7 @@ static int host2guc_action(struct intel_guc *guc,
>>> u32 *data, u32 len)
>>>           return -EINVAL;
>>>
>>>       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
>>> +    spin_lock(&guc->action_lock);
>>
>> The code below can sleep waiting for a response from GuC so you cannot
>> use a spinlock. Mutex I suppose...
>
> Sorry I missed the sleep.
> Probably I did not see any problem, in spite of a spinlock, as _wait_for
> macro does not sleep when used in atomic context, does a busy wait instead.

I wonder about that in general, since in_atomic is not a reliable 
indicator. But that is beside the point. You probably haven't seen it 
because the action completes in the first shorter, atomic sleep, check.

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts
  2016-07-15 15:58     ` Goel, Akash
@ 2016-07-18 10:16       ` Tvrtko Ursulin
  2016-07-18 10:59         ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-18 10:16 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 15/07/16 16:58, Goel, Akash wrote:
> On 7/15/2016 5:21 PM, Tvrtko Ursulin wrote:
>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>> From: Akash Goel <akash.goel@intel.com>
>>>
>>> GuC firmware sends an interrupt to flush the log buffer when it
>>> becomes half full. GuC firmware also tracks how many times the
>>> buffer overflowed.
>>> It would be useful to maintain a statistics of how many flush
>>> interrupts were received and for which type of log buffer,
>>> along with the overflow count of each buffer type.
>>> Augmented i915_log_info debugfs to report back these statistics.
>>>
>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>> ---
>>>   drivers/gpu/drm/i915/i915_debugfs.c        | 26
>>> ++++++++++++++++++++++++++
>>>   drivers/gpu/drm/i915/i915_guc_submission.c |  8 ++++++++
>>>   drivers/gpu/drm/i915/i915_irq.c            |  1 +
>>>   drivers/gpu/drm/i915/intel_guc.h           |  6 ++++++
>>>   4 files changed, 41 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>>> b/drivers/gpu/drm/i915/i915_debugfs.c
>>> index 3c9c7f7..888a18a 100644
>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>> @@ -2538,6 +2538,30 @@ static int i915_guc_load_status_info(struct
>>> seq_file *m, void *data)
>>>       return 0;
>>>   }
>>>
>>> +static void i915_guc_log_info(struct seq_file *m,
>>> +                 struct drm_i915_private *dev_priv)
>>> +{
>>> +    struct intel_guc *guc = &dev_priv->guc;
>>> +
>>> +    seq_printf(m, "\nGuC logging stats:\n");
>>> +
>>> +    seq_printf(m, "\tISR:   flush count %10u, overflow count %8u\n",
>>> +        guc->log.flush_count[GUC_ISR_LOG_BUFFER],
>>> +        guc->log.total_overflow_count[GUC_ISR_LOG_BUFFER]);
>>> +
>>> +    seq_printf(m, "\tDPC:   flush count %10u, overflow count %8u\n",
>>> +        guc->log.flush_count[GUC_DPC_LOG_BUFFER],
>>> +        guc->log.total_overflow_count[GUC_DPC_LOG_BUFFER]);
>>> +
>>> +    seq_printf(m, "\tCRASH: flush count %10u, overflow count %8u\n",
>>> +        guc->log.flush_count[GUC_CRASH_DUMP_LOG_BUFFER],
>>> +        guc->log.total_overflow_count[GUC_CRASH_DUMP_LOG_BUFFER]);
>>> +
>>> +    seq_printf(m, "\tTotal flush interrupt count: %u\n",
>>> +            guc->log.flush_interrupt_count);
>>> +
>>> +}
>>> +
>>>   static void i915_guc_client_info(struct seq_file *m,
>>>                    struct drm_i915_private *dev_priv,
>>>                    struct i915_guc_client *client)
>>> @@ -2611,6 +2635,8 @@ static int i915_guc_info(struct seq_file *m,
>>> void *data)
>>>       seq_printf(m, "\nGuC execbuf client @ %p:\n", guc.execbuf_client);
>>>       i915_guc_client_info(m, dev_priv, &client);
>>>
>>> +    i915_guc_log_info(m, dev_priv);
>>> +
>>>       /* Add more as required ... */
>>>
>>>       return 0;
>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> index c1e637f..9c94a43 100644
>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> @@ -914,6 +914,14 @@ static void guc_read_update_log_buffer(struct
>>> drm_device *dev)
>>>           log_buffer_state_local = *log_buffer_state;
>>>           buffer_size = log_buffer_state_local.size;
>>>
>>> +        guc->log.flush_count[i] +=
>>> log_buffer_state_local.flush_to_file;
>>> +        if (log_buffer_state_local.buffer_full_cnt !=
>>> +                    guc->log.prev_overflow_count[i]) {
>>> +            guc->log.prev_overflow_count[i] =
>>> +                    log_buffer_state_local.buffer_full_cnt;
>>> +            guc->log.total_overflow_count[i]++;
>>
>> Is log_buffer_state_local.buffer_full_cnt guaranteed to be one here? Or
>> you would need to increase total_overflow_count by its value?
>>
>
> buffer_full_cnt will not remain as one. Its a 4 bit counter, will be
> incremented monotonically by GuC firmware on every new detection of
> overflow, so will increase from 0 to 15 & then wrap around.
> Hence have to use '!=' in the condition instead of '>'.

But can it happen that it jumps by more than one between being sampled 
here? In which case you would need to replace:

guc->log.total_overflow_count[i]++;

by something like:


guc->log.total_overflow_count[i] += 
log_buffer_state_local.buffer_full_cnt - guc->log.prev_overflow_count[i];

(Doesn't handle the wrap though, just to illustrate my point.)

Regards,

Tvrtko




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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/17] drm/i915: Support to create write combined type vmaps
  2016-07-15 16:30     ` Goel, Akash
@ 2016-07-18 10:18       ` Tvrtko Ursulin
  0 siblings, 0 replies; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-18 10:18 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 15/07/16 17:30, Goel, Akash wrote:
> On 7/15/2016 5:01 PM, Tvrtko Ursulin wrote:
>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>> From: Chris Wilson <chris@chris-wilson.co.uk>
>>>
>>> vmaps has a provision for controlling the page protection bits, with
>>> which
>>> we can use to control the mapping type, e.g. WB, WC, UC or even WT.
>>> To allow the caller to choose their mapping type, we add a parameter to
>>> i915_gem_object_pin_map - but we still only allow one vmap to be cached
>>> per object. If the object is currently not pinned, then we recreate the
>>> previous vmap with the new access type, but if it was pinned we
>>> report an
>>> error. This effectively limits the access via i915_gem_object_pin_map
>>> to a
>>> single mapping type for the lifetime of the object. Not usually a
>>> problem,
>>> but something to be aware of when setting up the object's vmap.
>>>
>>> We will want to vary the access type to enable WC mappings of ringbuffer
>>> and context objects on !llc platforms, as well as other objects where we
>>> need coherent access to the GPU's pages without going through the GTT
>>>
>>> v2: Remove the redundant braces around pin count check and fix the
>>> marker
>>>      in documentation (Chris)
>>>
>>> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>> ---
>>>   drivers/gpu/drm/i915/i915_drv.h            |  4 ++-
>>>   drivers/gpu/drm/i915/i915_gem.c            | 57
>>> +++++++++++++++++++++++-------
>>>   drivers/gpu/drm/i915/i915_gem_dmabuf.c     |  2 +-
>>>   drivers/gpu/drm/i915/i915_guc_submission.c |  2 +-
>>>   drivers/gpu/drm/i915/intel_lrc.c           |  8 ++---
>>>   drivers/gpu/drm/i915/intel_ringbuffer.c    |  2 +-
>>>   6 files changed, 54 insertions(+), 21 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_drv.h
>>> b/drivers/gpu/drm/i915/i915_drv.h
>>> index 6e2ddfa..84afa17 100644
>>> --- a/drivers/gpu/drm/i915/i915_drv.h
>>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>>> @@ -3248,6 +3248,7 @@ static inline void
>>> i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
>>>   /**
>>>    * i915_gem_object_pin_map - return a contiguous mapping of the
>>> entire object
>>>    * @obj - the object to map into kernel address space
>>> + * @use_wc - whether the mapping should be using WC or WB pgprot_t
>>>    *
>>>    * Calls i915_gem_object_pin_pages() to prevent reaping of the
>>> object's
>>>    * pages and then returns a contiguous mapping of the backing
>>> storage into
>>> @@ -3259,7 +3260,8 @@ static inline void
>>> i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj)
>>>    * Returns the pointer through which to access the mapped object,
>>> or an
>>>    * ERR_PTR() on error.
>>>    */
>>> -void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object
>>> *obj);
>>> +void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object
>>> *obj,
>>> +                     bool use_wc);
>>
>> Could you make it an enum instead of a bool? Commit message suggests
>> more modes will potentially be added and if so, and we start with an
>> enum straight away, it will make for less churn in the future.
>>
>> func(something, true) is always also quite unreadabe in the code because
>> one has to remember or remind himself what it really means.
>>
>> Something like func(something, MAP_WC) would be simply self-documenting.
>>
> Thanks nice suggestion, will do that.
> enum only or macros also will do ?
> #define MAP_CACHED    0x1
> #define MAP_WC        0x2

I think enum is better since you then have type checking on the arguments.

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions
  2016-07-18 10:12       ` Tvrtko Ursulin
@ 2016-07-18 10:46         ` Goel, Akash
  2016-07-18 11:18           ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-18 10:46 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/18/2016 3:42 PM, Tvrtko Ursulin wrote:
>
> On 15/07/16 16:51, Goel, Akash wrote:
>>
>>
>> On 7/15/2016 5:10 PM, Tvrtko Ursulin wrote:
>>>
>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>> From: Akash Goel <akash.goel@intel.com>
>>>>
>>>> With the addition of new Host2GuC actions related to GuC logging, there
>>>> is a need of a lock to serialize them, as they can execute concurrently
>>>> with each other and also with other existing actions.
>>>
>>> After which patch in this series is this required?
>>>
>>  From patch 6 or 7 saw the problem, when enabled flush interrupts from
>> boot (guc_log_level >= 0).
>
> That means this patch should come before 6 or 7. :)
>
>> Also new HOST2GUC actions LOG_BUFFER_FILE_FLUSH_COMPLETE &
>> UK_LOG_ENABLE_LOGGING can execute concurrently with each other.
>
> Right I see, from the worker/thread vs debugfs activity.
>
Will use mutex to serialize and place the patch earlier in the series.
Please suggest which would be better,
mutex_lock()
or
mutex_lock_interruptible().

>>>>
>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>> ---
>>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +++
>>>>   drivers/gpu/drm/i915/intel_guc.h           | 3 +++
>>>>   2 files changed, 6 insertions(+)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> index 6043166..c1e637f 100644
>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> @@ -88,6 +88,7 @@ static int host2guc_action(struct intel_guc *guc,
>>>> u32 *data, u32 len)
>>>>           return -EINVAL;
>>>>
>>>>       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
>>>> +    spin_lock(&guc->action_lock);
>>>
>>> The code below can sleep waiting for a response from GuC so you cannot
>>> use a spinlock. Mutex I suppose...
>>
>> Sorry I missed the sleep.
>> Probably I did not see any problem, in spite of a spinlock, as _wait_for
>> macro does not sleep when used in atomic context, does a busy wait
>> instead.
>
> I wonder about that in general, since in_atomic is not a reliable
> indicator. But that is beside the point. You probably haven't seen it
> because the action completes in the first shorter, atomic sleep, check.
>
Actually I had profiled host2guc_logbuffer_flush_complete() and saw that 
on some occasions it was taking more than 100 micro seconds,
so presumably it would have went past the first wait.
But most of the times it was less than 10 micro seconds only.

ret = wait_for_us(host2guc_action_response(dev_priv, &status), 10);
if (ret)
	ret = wait_for(host2guc_action_response(dev_priv, &status), 10);

Best regards
Akash
> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts
  2016-07-18 10:16       ` Tvrtko Ursulin
@ 2016-07-18 10:59         ` Goel, Akash
  2016-07-18 11:33           ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-18 10:59 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/18/2016 3:46 PM, Tvrtko Ursulin wrote:
>
> On 15/07/16 16:58, Goel, Akash wrote:
>> On 7/15/2016 5:21 PM, Tvrtko Ursulin wrote:
>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>> From: Akash Goel <akash.goel@intel.com>
>>>>
>>>> GuC firmware sends an interrupt to flush the log buffer when it
>>>> becomes half full. GuC firmware also tracks how many times the
>>>> buffer overflowed.
>>>> It would be useful to maintain a statistics of how many flush
>>>> interrupts were received and for which type of log buffer,
>>>> along with the overflow count of each buffer type.
>>>> Augmented i915_log_info debugfs to report back these statistics.
>>>>
>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>> ---
>>>>   drivers/gpu/drm/i915/i915_debugfs.c        | 26
>>>> ++++++++++++++++++++++++++
>>>>   drivers/gpu/drm/i915/i915_guc_submission.c |  8 ++++++++
>>>>   drivers/gpu/drm/i915/i915_irq.c            |  1 +
>>>>   drivers/gpu/drm/i915/intel_guc.h           |  6 ++++++
>>>>   4 files changed, 41 insertions(+)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>>>> b/drivers/gpu/drm/i915/i915_debugfs.c
>>>> index 3c9c7f7..888a18a 100644
>>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>>> @@ -2538,6 +2538,30 @@ static int i915_guc_load_status_info(struct
>>>> seq_file *m, void *data)
>>>>       return 0;
>>>>   }
>>>>
>>>> +static void i915_guc_log_info(struct seq_file *m,
>>>> +                 struct drm_i915_private *dev_priv)
>>>> +{
>>>> +    struct intel_guc *guc = &dev_priv->guc;
>>>> +
>>>> +    seq_printf(m, "\nGuC logging stats:\n");
>>>> +
>>>> +    seq_printf(m, "\tISR:   flush count %10u, overflow count %8u\n",
>>>> +        guc->log.flush_count[GUC_ISR_LOG_BUFFER],
>>>> +        guc->log.total_overflow_count[GUC_ISR_LOG_BUFFER]);
>>>> +
>>>> +    seq_printf(m, "\tDPC:   flush count %10u, overflow count %8u\n",
>>>> +        guc->log.flush_count[GUC_DPC_LOG_BUFFER],
>>>> +        guc->log.total_overflow_count[GUC_DPC_LOG_BUFFER]);
>>>> +
>>>> +    seq_printf(m, "\tCRASH: flush count %10u, overflow count %8u\n",
>>>> +        guc->log.flush_count[GUC_CRASH_DUMP_LOG_BUFFER],
>>>> +        guc->log.total_overflow_count[GUC_CRASH_DUMP_LOG_BUFFER]);
>>>> +
>>>> +    seq_printf(m, "\tTotal flush interrupt count: %u\n",
>>>> +            guc->log.flush_interrupt_count);
>>>> +
>>>> +}
>>>> +
>>>>   static void i915_guc_client_info(struct seq_file *m,
>>>>                    struct drm_i915_private *dev_priv,
>>>>                    struct i915_guc_client *client)
>>>> @@ -2611,6 +2635,8 @@ static int i915_guc_info(struct seq_file *m,
>>>> void *data)
>>>>       seq_printf(m, "\nGuC execbuf client @ %p:\n",
>>>> guc.execbuf_client);
>>>>       i915_guc_client_info(m, dev_priv, &client);
>>>>
>>>> +    i915_guc_log_info(m, dev_priv);
>>>> +
>>>>       /* Add more as required ... */
>>>>
>>>>       return 0;
>>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> index c1e637f..9c94a43 100644
>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> @@ -914,6 +914,14 @@ static void guc_read_update_log_buffer(struct
>>>> drm_device *dev)
>>>>           log_buffer_state_local = *log_buffer_state;
>>>>           buffer_size = log_buffer_state_local.size;
>>>>
>>>> +        guc->log.flush_count[i] +=
>>>> log_buffer_state_local.flush_to_file;
>>>> +        if (log_buffer_state_local.buffer_full_cnt !=
>>>> +                    guc->log.prev_overflow_count[i]) {
>>>> +            guc->log.prev_overflow_count[i] =
>>>> +                    log_buffer_state_local.buffer_full_cnt;
>>>> +            guc->log.total_overflow_count[i]++;
>>>
>>> Is log_buffer_state_local.buffer_full_cnt guaranteed to be one here? Or
>>> you would need to increase total_overflow_count by its value?
>>>
>>
>> buffer_full_cnt will not remain as one. Its a 4 bit counter, will be
>> incremented monotonically by GuC firmware on every new detection of
>> overflow, so will increase from 0 to 15 & then wrap around.
>> Hence have to use '!=' in the condition instead of '>'.
>
> But can it happen that it jumps by more than one between being sampled
> here? In which case you would need to replace:
>
> guc->log.total_overflow_count[i]++;
>
> by something like:
>
>
> guc->log.total_overflow_count[i] +=
> log_buffer_state_local.buffer_full_cnt - guc->log.prev_overflow_count[i];
>
> (Doesn't handle the wrap though, just to illustrate my point.)
>
Actually logic in GuC firmware is such that overflow counter cannot 
increment by more than 1 without Driver coming into picture in between, 
by the virtue of flush interrupt.
But nevertheless the logic on Driver side should be like the way you
suggested.

Does this revised logic looks fine ?

if (log_buffer_state_local.buffer_full_cnt !=
		guc->log.prev_overflow_count[i]) {
	new_overflow = 1;
	guc->log.total_overflow_count[i] += 
(log_buffer_state_local.buffer_full_cnt - guc->log.prev_overflow_count[i]);

	if (log_buffer_state_local.buffer_full_cnt < 
guc->log.prev_overflow_count[i])
		guc->log.total_overflow_count[i] += 15;

	log_buffer_state_local.buffer_full_cnt = guc->log.prev_overflow_count[i];
}


> Regards,
>
> Tvrtko
>
>
>
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions
  2016-07-18 10:46         ` Goel, Akash
@ 2016-07-18 11:18           ` Tvrtko Ursulin
  2016-07-18 11:31             ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-18 11:18 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 18/07/16 11:46, Goel, Akash wrote:
> On 7/18/2016 3:42 PM, Tvrtko Ursulin wrote:
>>
>> On 15/07/16 16:51, Goel, Akash wrote:
>>>
>>>
>>> On 7/15/2016 5:10 PM, Tvrtko Ursulin wrote:
>>>>
>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>> From: Akash Goel <akash.goel@intel.com>
>>>>>
>>>>> With the addition of new Host2GuC actions related to GuC logging,
>>>>> there
>>>>> is a need of a lock to serialize them, as they can execute
>>>>> concurrently
>>>>> with each other and also with other existing actions.
>>>>
>>>> After which patch in this series is this required?
>>>>
>>>  From patch 6 or 7 saw the problem, when enabled flush interrupts from
>>> boot (guc_log_level >= 0).
>>
>> That means this patch should come before 6 or 7. :)
>>
>>> Also new HOST2GUC actions LOG_BUFFER_FILE_FLUSH_COMPLETE &
>>> UK_LOG_ENABLE_LOGGING can execute concurrently with each other.
>>
>> Right I see, from the worker/thread vs debugfs activity.
>>
> Will use mutex to serialize and place the patch earlier in the series.
> Please suggest which would be better,
> mutex_lock()
> or
> mutex_lock_interruptible().

Interruptible from the debugfs paths, otherwise not.

>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>> ---
>>>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +++
>>>>>   drivers/gpu/drm/i915/intel_guc.h           | 3 +++
>>>>>   2 files changed, 6 insertions(+)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> index 6043166..c1e637f 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> @@ -88,6 +88,7 @@ static int host2guc_action(struct intel_guc *guc,
>>>>> u32 *data, u32 len)
>>>>>           return -EINVAL;
>>>>>
>>>>>       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
>>>>> +    spin_lock(&guc->action_lock);
>>>>
>>>> The code below can sleep waiting for a response from GuC so you cannot
>>>> use a spinlock. Mutex I suppose...
>>>
>>> Sorry I missed the sleep.
>>> Probably I did not see any problem, in spite of a spinlock, as _wait_for
>>> macro does not sleep when used in atomic context, does a busy wait
>>> instead.
>>
>> I wonder about that in general, since in_atomic is not a reliable
>> indicator. But that is beside the point. You probably haven't seen it
>> because the action completes in the first shorter, atomic sleep, check.
>>
> Actually I had profiled host2guc_logbuffer_flush_complete() and saw that
> on some occasions it was taking more than 100 micro seconds,
> so presumably it would have went past the first wait.
> But most of the times it was less than 10 micro seconds only.
>
> ret = wait_for_us(host2guc_action_response(dev_priv, &status), 10);
> if (ret)
>      ret = wait_for(host2guc_action_response(dev_priv, &status), 10);

Yes presumably so. In that case keep in mind that in_atomic always 
returns false in spinlock sections unless the kernel has 
CONFIG_PREEMPT_COUNT enabled.

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions
  2016-07-18 11:18           ` Tvrtko Ursulin
@ 2016-07-18 11:31             ` Goel, Akash
  2016-07-18 11:36               ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-18 11:31 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/18/2016 4:48 PM, Tvrtko Ursulin wrote:
>
> On 18/07/16 11:46, Goel, Akash wrote:
>> On 7/18/2016 3:42 PM, Tvrtko Ursulin wrote:
>>>
>>> On 15/07/16 16:51, Goel, Akash wrote:
>>>>
>>>>
>>>> On 7/15/2016 5:10 PM, Tvrtko Ursulin wrote:
>>>>>
>>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>>> From: Akash Goel <akash.goel@intel.com>
>>>>>>
>>>>>> With the addition of new Host2GuC actions related to GuC logging,
>>>>>> there
>>>>>> is a need of a lock to serialize them, as they can execute
>>>>>> concurrently
>>>>>> with each other and also with other existing actions.
>>>>>
>>>>> After which patch in this series is this required?
>>>>>
>>>>  From patch 6 or 7 saw the problem, when enabled flush interrupts from
>>>> boot (guc_log_level >= 0).
>>>
>>> That means this patch should come before 6 or 7. :)
>>>
>>>> Also new HOST2GUC actions LOG_BUFFER_FILE_FLUSH_COMPLETE &
>>>> UK_LOG_ENABLE_LOGGING can execute concurrently with each other.
>>>
>>> Right I see, from the worker/thread vs debugfs activity.
>>>
>> Will use mutex to serialize and place the patch earlier in the series.
>> Please suggest which would be better,
>> mutex_lock()
>> or
>> mutex_lock_interruptible().
>
> Interruptible from the debugfs paths, otherwise not.

Yes calls from debugfs path should ideally use interruptible version,
but then how to determine that whether the given host2guc_action call
came from debugfs path.
Should I add a new argument 'interruptible_wait' to host2guc_action() or
to keep things simple use mutex_lock() only ?
I thought it would be cleaner to abstract the lock usage, for 
serialization, entirely inside the host2guc_action only.

>>>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>>> @@ -88,6 +88,7 @@ static int host2guc_action(struct intel_guc *guc,
>>>>>> u32 *data, u32 len)
>>>>>>           return -EINVAL;
>>>>>>
>>>>>>       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
>>>>>> +    spin_lock(&guc->action_lock);
>>>>>
>>>>> The code below can sleep waiting for a response from GuC so you cannot
>>>>> use a spinlock. Mutex I suppose...
>>>>
>>>> Sorry I missed the sleep.
>>>> Probably I did not see any problem, in spite of a spinlock, as
>>>> _wait_for
>>>> macro does not sleep when used in atomic context, does a busy wait
>>>> instead.
>>>
>>> I wonder about that in general, since in_atomic is not a reliable
>>> indicator. But that is beside the point. You probably haven't seen it
>>> because the action completes in the first shorter, atomic sleep, check.
>>>
>> Actually I had profiled host2guc_logbuffer_flush_complete() and saw that
>> on some occasions it was taking more than 100 micro seconds,
>> so presumably it would have went past the first wait.
>> But most of the times it was less than 10 micro seconds only.
>>
>> ret = wait_for_us(host2guc_action_response(dev_priv, &status), 10);
>> if (ret)
>>      ret = wait_for(host2guc_action_response(dev_priv, &status), 10);
>
> Yes presumably so. In that case keep in mind that in_atomic always
> returns false in spinlock sections unless the kernel has
> CONFIG_PREEMPT_COUNT enabled.
>
Thanks for this info, will be mindful of this in future.

Best regards
Akash

> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts
  2016-07-18 10:59         ` Goel, Akash
@ 2016-07-18 11:33           ` Tvrtko Ursulin
  2016-07-18 11:47             ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-18 11:33 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 18/07/16 11:59, Goel, Akash wrote:
> On 7/18/2016 3:46 PM, Tvrtko Ursulin wrote:
>>
>> On 15/07/16 16:58, Goel, Akash wrote:
>>> On 7/15/2016 5:21 PM, Tvrtko Ursulin wrote:
>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>> From: Akash Goel <akash.goel@intel.com>
>>>>>
>>>>> GuC firmware sends an interrupt to flush the log buffer when it
>>>>> becomes half full. GuC firmware also tracks how many times the
>>>>> buffer overflowed.
>>>>> It would be useful to maintain a statistics of how many flush
>>>>> interrupts were received and for which type of log buffer,
>>>>> along with the overflow count of each buffer type.
>>>>> Augmented i915_log_info debugfs to report back these statistics.
>>>>>
>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>> ---
>>>>>   drivers/gpu/drm/i915/i915_debugfs.c        | 26
>>>>> ++++++++++++++++++++++++++
>>>>>   drivers/gpu/drm/i915/i915_guc_submission.c |  8 ++++++++
>>>>>   drivers/gpu/drm/i915/i915_irq.c            |  1 +
>>>>>   drivers/gpu/drm/i915/intel_guc.h           |  6 ++++++
>>>>>   4 files changed, 41 insertions(+)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>>>>> b/drivers/gpu/drm/i915/i915_debugfs.c
>>>>> index 3c9c7f7..888a18a 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>>>> @@ -2538,6 +2538,30 @@ static int i915_guc_load_status_info(struct
>>>>> seq_file *m, void *data)
>>>>>       return 0;
>>>>>   }
>>>>>
>>>>> +static void i915_guc_log_info(struct seq_file *m,
>>>>> +                 struct drm_i915_private *dev_priv)
>>>>> +{
>>>>> +    struct intel_guc *guc = &dev_priv->guc;
>>>>> +
>>>>> +    seq_printf(m, "\nGuC logging stats:\n");
>>>>> +
>>>>> +    seq_printf(m, "\tISR:   flush count %10u, overflow count %8u\n",
>>>>> +        guc->log.flush_count[GUC_ISR_LOG_BUFFER],
>>>>> +        guc->log.total_overflow_count[GUC_ISR_LOG_BUFFER]);
>>>>> +
>>>>> +    seq_printf(m, "\tDPC:   flush count %10u, overflow count %8u\n",
>>>>> +        guc->log.flush_count[GUC_DPC_LOG_BUFFER],
>>>>> +        guc->log.total_overflow_count[GUC_DPC_LOG_BUFFER]);
>>>>> +
>>>>> +    seq_printf(m, "\tCRASH: flush count %10u, overflow count %8u\n",
>>>>> +        guc->log.flush_count[GUC_CRASH_DUMP_LOG_BUFFER],
>>>>> +        guc->log.total_overflow_count[GUC_CRASH_DUMP_LOG_BUFFER]);
>>>>> +
>>>>> +    seq_printf(m, "\tTotal flush interrupt count: %u\n",
>>>>> +            guc->log.flush_interrupt_count);
>>>>> +
>>>>> +}
>>>>> +
>>>>>   static void i915_guc_client_info(struct seq_file *m,
>>>>>                    struct drm_i915_private *dev_priv,
>>>>>                    struct i915_guc_client *client)
>>>>> @@ -2611,6 +2635,8 @@ static int i915_guc_info(struct seq_file *m,
>>>>> void *data)
>>>>>       seq_printf(m, "\nGuC execbuf client @ %p:\n",
>>>>> guc.execbuf_client);
>>>>>       i915_guc_client_info(m, dev_priv, &client);
>>>>>
>>>>> +    i915_guc_log_info(m, dev_priv);
>>>>> +
>>>>>       /* Add more as required ... */
>>>>>
>>>>>       return 0;
>>>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> index c1e637f..9c94a43 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> @@ -914,6 +914,14 @@ static void guc_read_update_log_buffer(struct
>>>>> drm_device *dev)
>>>>>           log_buffer_state_local = *log_buffer_state;
>>>>>           buffer_size = log_buffer_state_local.size;
>>>>>
>>>>> +        guc->log.flush_count[i] +=
>>>>> log_buffer_state_local.flush_to_file;
>>>>> +        if (log_buffer_state_local.buffer_full_cnt !=
>>>>> +                    guc->log.prev_overflow_count[i]) {
>>>>> +            guc->log.prev_overflow_count[i] =
>>>>> +                    log_buffer_state_local.buffer_full_cnt;
>>>>> +            guc->log.total_overflow_count[i]++;
>>>>
>>>> Is log_buffer_state_local.buffer_full_cnt guaranteed to be one here? Or
>>>> you would need to increase total_overflow_count by its value?
>>>>
>>>
>>> buffer_full_cnt will not remain as one. Its a 4 bit counter, will be
>>> incremented monotonically by GuC firmware on every new detection of
>>> overflow, so will increase from 0 to 15 & then wrap around.
>>> Hence have to use '!=' in the condition instead of '>'.
>>
>> But can it happen that it jumps by more than one between being sampled
>> here? In which case you would need to replace:
>>
>> guc->log.total_overflow_count[i]++;
>>
>> by something like:
>>
>>
>> guc->log.total_overflow_count[i] +=
>> log_buffer_state_local.buffer_full_cnt - guc->log.prev_overflow_count[i];
>>
>> (Doesn't handle the wrap though, just to illustrate my point.)
>>
> Actually logic in GuC firmware is such that overflow counter cannot
> increment by more than 1 without Driver coming into picture in between,
> by the virtue of flush interrupt.

Hm, and what happens to the data and overflow counter if the driver is 
not responsive enough?

> But nevertheless the logic on Driver side should be like the way you
> suggested.
>
> Does this revised logic looks fine ?
>
> if (log_buffer_state_local.buffer_full_cnt !=
>          guc->log.prev_overflow_count[i]) {
>      new_overflow = 1;
>      guc->log.total_overflow_count[i] +=
> (log_buffer_state_local.buffer_full_cnt - guc->log.prev_overflow_count[i]);
>
>      if (log_buffer_state_local.buffer_full_cnt <
> guc->log.prev_overflow_count[i])
>          guc->log.total_overflow_count[i] += 15;
>
>      log_buffer_state_local.buffer_full_cnt =
> guc->log.prev_overflow_count[i];
> }

Not sure, maybe += 16 ? If counter goes from 15 to zero, then -15, +15 = 
no change which is wrong?

But in general if the condition should not happen I would also put a 
WARN_ON_ONCE or a rate limited DRM_ERROR in that case.

Regards,

Tvrtko


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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions
  2016-07-18 11:31             ` Goel, Akash
@ 2016-07-18 11:36               ` Tvrtko Ursulin
  0 siblings, 0 replies; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-18 11:36 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 18/07/16 12:31, Goel, Akash wrote:
>
>
> On 7/18/2016 4:48 PM, Tvrtko Ursulin wrote:
>>
>> On 18/07/16 11:46, Goel, Akash wrote:
>>> On 7/18/2016 3:42 PM, Tvrtko Ursulin wrote:
>>>>
>>>> On 15/07/16 16:51, Goel, Akash wrote:
>>>>>
>>>>>
>>>>> On 7/15/2016 5:10 PM, Tvrtko Ursulin wrote:
>>>>>>
>>>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>>>> From: Akash Goel <akash.goel@intel.com>
>>>>>>>
>>>>>>> With the addition of new Host2GuC actions related to GuC logging,
>>>>>>> there
>>>>>>> is a need of a lock to serialize them, as they can execute
>>>>>>> concurrently
>>>>>>> with each other and also with other existing actions.
>>>>>>
>>>>>> After which patch in this series is this required?
>>>>>>
>>>>>  From patch 6 or 7 saw the problem, when enabled flush interrupts from
>>>>> boot (guc_log_level >= 0).
>>>>
>>>> That means this patch should come before 6 or 7. :)
>>>>
>>>>> Also new HOST2GUC actions LOG_BUFFER_FILE_FLUSH_COMPLETE &
>>>>> UK_LOG_ENABLE_LOGGING can execute concurrently with each other.
>>>>
>>>> Right I see, from the worker/thread vs debugfs activity.
>>>>
>>> Will use mutex to serialize and place the patch earlier in the series.
>>> Please suggest which would be better,
>>> mutex_lock()
>>> or
>>> mutex_lock_interruptible().
>>
>> Interruptible from the debugfs paths, otherwise not.
>
> Yes calls from debugfs path should ideally use interruptible version,
> but then how to determine that whether the given host2guc_action call
> came from debugfs path.
> Should I add a new argument 'interruptible_wait' to host2guc_action() or
> to keep things simple use mutex_lock() only ?
> I thought it would be cleaner to abstract the lock usage, for
> serialization, entirely inside the host2guc_action only.

Hm yes, good point. I think a simple mutex lock should be fine then. You 
don't expect to be holding it for more than 10ms in the absolutely worst 
case and I think simplicity of the implementation wins in this case even 
if it stalls userspace a bit.

Regards,

Tvrtko


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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts
  2016-07-18 11:33           ` Tvrtko Ursulin
@ 2016-07-18 11:47             ` Goel, Akash
  0 siblings, 0 replies; 87+ messages in thread
From: Goel, Akash @ 2016-07-18 11:47 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx, akash.goel



On 7/18/2016 5:03 PM, Tvrtko Ursulin wrote:
>
> On 18/07/16 11:59, Goel, Akash wrote:
>> On 7/18/2016 3:46 PM, Tvrtko Ursulin wrote:
>>>
>>> On 15/07/16 16:58, Goel, Akash wrote:
>>>> On 7/15/2016 5:21 PM, Tvrtko Ursulin wrote:
>>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>>> From: Akash Goel <akash.goel@intel.com>
>>>>>>
>>>>>> GuC firmware sends an interrupt to flush the log buffer when it
>>>>>> becomes half full. GuC firmware also tracks how many times the
>>>>>> buffer overflowed.
>>>>>> It would be useful to maintain a statistics of how many flush
>>>>>> interrupts were received and for which type of log buffer,
>>>>>> along with the overflow count of each buffer type.
>>>>>> Augmented i915_log_info debugfs to report back these statistics.
>>>>>>
>>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>>> ---
>>>>>>   drivers/gpu/drm/i915/i915_debugfs.c        | 26
>>>>>> ++++++++++++++++++++++++++
>>>>>>   drivers/gpu/drm/i915/i915_guc_submission.c |  8 ++++++++
>>>>>>   drivers/gpu/drm/i915/i915_irq.c            |  1 +
>>>>>>   drivers/gpu/drm/i915/intel_guc.h           |  6 ++++++
>>>>>>   4 files changed, 41 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> b/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> index 3c9c7f7..888a18a 100644
>>>>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> @@ -2538,6 +2538,30 @@ static int i915_guc_load_status_info(struct
>>>>>> seq_file *m, void *data)
>>>>>>       return 0;
>>>>>>   }
>>>>>>
>>>>>> +static void i915_guc_log_info(struct seq_file *m,
>>>>>> +                 struct drm_i915_private *dev_priv)
>>>>>> +{
>>>>>> +    struct intel_guc *guc = &dev_priv->guc;
>>>>>> +
>>>>>> +    seq_printf(m, "\nGuC logging stats:\n");
>>>>>> +
>>>>>> +    seq_printf(m, "\tISR:   flush count %10u, overflow count %8u\n",
>>>>>> +        guc->log.flush_count[GUC_ISR_LOG_BUFFER],
>>>>>> +        guc->log.total_overflow_count[GUC_ISR_LOG_BUFFER]);
>>>>>> +
>>>>>> +    seq_printf(m, "\tDPC:   flush count %10u, overflow count %8u\n",
>>>>>> +        guc->log.flush_count[GUC_DPC_LOG_BUFFER],
>>>>>> +        guc->log.total_overflow_count[GUC_DPC_LOG_BUFFER]);
>>>>>> +
>>>>>> +    seq_printf(m, "\tCRASH: flush count %10u, overflow count %8u\n",
>>>>>> +        guc->log.flush_count[GUC_CRASH_DUMP_LOG_BUFFER],
>>>>>> +        guc->log.total_overflow_count[GUC_CRASH_DUMP_LOG_BUFFER]);
>>>>>> +
>>>>>> +    seq_printf(m, "\tTotal flush interrupt count: %u\n",
>>>>>> +            guc->log.flush_interrupt_count);
>>>>>> +
>>>>>> +}
>>>>>> +
>>>>>>   static void i915_guc_client_info(struct seq_file *m,
>>>>>>                    struct drm_i915_private *dev_priv,
>>>>>>                    struct i915_guc_client *client)
>>>>>> @@ -2611,6 +2635,8 @@ static int i915_guc_info(struct seq_file *m,
>>>>>> void *data)
>>>>>>       seq_printf(m, "\nGuC execbuf client @ %p:\n",
>>>>>> guc.execbuf_client);
>>>>>>       i915_guc_client_info(m, dev_priv, &client);
>>>>>>
>>>>>> +    i915_guc_log_info(m, dev_priv);
>>>>>> +
>>>>>>       /* Add more as required ... */
>>>>>>
>>>>>>       return 0;
>>>>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>>> index c1e637f..9c94a43 100644
>>>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>>> @@ -914,6 +914,14 @@ static void guc_read_update_log_buffer(struct
>>>>>> drm_device *dev)
>>>>>>           log_buffer_state_local = *log_buffer_state;
>>>>>>           buffer_size = log_buffer_state_local.size;
>>>>>>
>>>>>> +        guc->log.flush_count[i] +=
>>>>>> log_buffer_state_local.flush_to_file;
>>>>>> +        if (log_buffer_state_local.buffer_full_cnt !=
>>>>>> +                    guc->log.prev_overflow_count[i]) {
>>>>>> +            guc->log.prev_overflow_count[i] =
>>>>>> +                    log_buffer_state_local.buffer_full_cnt;
>>>>>> +            guc->log.total_overflow_count[i]++;
>>>>>
>>>>> Is log_buffer_state_local.buffer_full_cnt guaranteed to be one
>>>>> here? Or
>>>>> you would need to increase total_overflow_count by its value?
>>>>>
>>>>
>>>> buffer_full_cnt will not remain as one. Its a 4 bit counter, will be
>>>> incremented monotonically by GuC firmware on every new detection of
>>>> overflow, so will increase from 0 to 15 & then wrap around.
>>>> Hence have to use '!=' in the condition instead of '>'.
>>>
>>> But can it happen that it jumps by more than one between being sampled
>>> here? In which case you would need to replace:
>>>
>>> guc->log.total_overflow_count[i]++;
>>>
>>> by something like:
>>>
>>>
>>> guc->log.total_overflow_count[i] +=
>>> log_buffer_state_local.buffer_full_cnt -
>>> guc->log.prev_overflow_count[i];
>>>
>>> (Doesn't handle the wrap though, just to illustrate my point.)
>>>
>> Actually logic in GuC firmware is such that overflow counter cannot
>> increment by more than 1 without Driver coming into picture in between,
>> by the virtue of flush interrupt.
>
> Hm, and what happens to the data and overflow counter if the driver is
> not responsive enough?
>
GuC will not stall and keep writing the logs into the buffer, if Driver 
is slow in responding to the previous flush interrupt.

But the overflow detection is done through a bit weird logic, which is 
executed only when GuC receives the response of the last flush interrupt 
from Driver, and increment is done by 1 only irrespective of how late 
the acknowledgement came from Driver side.

>> But nevertheless the logic on Driver side should be like the way you
>> suggested.
>>
>> Does this revised logic looks fine ?
>>
>> if (log_buffer_state_local.buffer_full_cnt !=
>>          guc->log.prev_overflow_count[i]) {
>>      new_overflow = 1;
>>      guc->log.total_overflow_count[i] +=
>> (log_buffer_state_local.buffer_full_cnt -
>> guc->log.prev_overflow_count[i]);
>>
>>      if (log_buffer_state_local.buffer_full_cnt <
>> guc->log.prev_overflow_count[i])
>>          guc->log.total_overflow_count[i] += 15;
>>
>>      log_buffer_state_local.buffer_full_cnt =
>> guc->log.prev_overflow_count[i];
>> }
>
> Not sure, maybe += 16 ? If counter goes from 15 to zero, then -15, +15 =
> no change which is wrong?
>
Right, it should be 16. Sorry, my bad.

> But in general if the condition should not happen I would also put a
> WARN_ON_ONCE or a rate limited DRM_ERROR in that case.
>
I think rate limited DRM_ERROR would be apt here.

Best regards
Akash
> Regards,
>
> Tvrtko
>
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs
  2016-07-18 10:06       ` Tvrtko Ursulin
@ 2016-07-18 12:19         ` Goel, Akash
  2016-07-18 13:06           ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-18 12:19 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/18/2016 3:36 PM, Tvrtko Ursulin wrote:
>
> On 15/07/16 16:36, Goel, Akash wrote:
>> On 7/15/2016 4:45 PM, Tvrtko Ursulin wrote:
>>>
>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>> From: Akash Goel <akash.goel@intel.com>
>>>>
>>>> On recieving the log buffer flush interrupt from GuC firmware, Driver
>>>> stores the snapshot of the log buffer in a local buffer, from which
>>>> Userspace can pull the logs. By default Driver store, up to, 4
>>>> snapshots
>>>> of the log buffer in a local buffer (managed by relay).
>>>> Added a new module (read only) param, 'guc_log_size', through which
>>>> User
>>>> can specify the number of snapshots of log buffer to be stored in local
>>>> buffer. This can be used to ensure capturing of all boot time logs even
>>>> with high verbosity level.
>>>>
>>>> v2: Rename module param to more apt name 'guc_log_buffer_nr'. (Nikula)
>>>>
>>>> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>> ---
>>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +--
>>>>   drivers/gpu/drm/i915/i915_params.c         | 5 +++++
>>>>   drivers/gpu/drm/i915/i915_params.h         | 1 +
>>>>   3 files changed, 7 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> index 2e3b723..009d7c0 100644
>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> @@ -1046,8 +1046,7 @@ static int guc_create_log_relay_file(struct
>>>> intel_guc *guc)
>>>>
>>>>       /* Keep the size of sub buffers same as shared log buffer */
>>>>       subbuf_size = guc->log.obj->base.size;
>>>> -    /* TODO: Decide based on the User's input */
>>>> -    n_subbufs = 4;
>>>> +    n_subbufs = i915.guc_log_buffer_nr;
>>>>
>>>>       guc_log_relay_chan = relay_open("guc_log", log_dir,
>>>>               subbuf_size, n_subbufs, &relay_callbacks, dev);
>>>> diff --git a/drivers/gpu/drm/i915/i915_params.c
>>>> b/drivers/gpu/drm/i915/i915_params.c
>>>> index 8b13bfa..d30c972 100644
>>>> --- a/drivers/gpu/drm/i915/i915_params.c
>>>> +++ b/drivers/gpu/drm/i915/i915_params.c
>>>> @@ -57,6 +57,7 @@ struct i915_params i915 __read_mostly = {
>>>>       .enable_guc_loading = -1,
>>>>       .enable_guc_submission = -1,
>>>>       .guc_log_level = -1,
>>>> +    .guc_log_buffer_nr = 4,
>>>>       .enable_dp_mst = true,
>>>>       .inject_load_failure = 0,
>>>>       .enable_dpcd_backlight = false,
>>>> @@ -214,6 +215,10 @@ module_param_named(guc_log_level,
>>>> i915.guc_log_level, int, 0400);
>>>>   MODULE_PARM_DESC(guc_log_level,
>>>>       "GuC firmware logging level (-1:disabled (default),
>>>> 0-3:enabled)");
>>>>
>>>> +module_param_named(guc_log_buffer_nr, i915.guc_log_buffer_nr, int,
>>>> 0400);
>>>> +MODULE_PARM_DESC(guc_log_buffer_nr,
>>>> +    "Number of sub buffers to store GuC firmware logs (default: 4)");
>>>> +
>>>>   module_param_named_unsafe(enable_dp_mst, i915.enable_dp_mst, bool,
>>>> 0600);
>>>>   MODULE_PARM_DESC(enable_dp_mst,
>>>>       "Enable multi-stream transport (MST) for new DisplayPort sinks.
>>>> (default: true)");
>>>> diff --git a/drivers/gpu/drm/i915/i915_params.h
>>>> b/drivers/gpu/drm/i915/i915_params.h
>>>> index 0ad020b..14ca855 100644
>>>> --- a/drivers/gpu/drm/i915/i915_params.h
>>>> +++ b/drivers/gpu/drm/i915/i915_params.h
>>>> @@ -48,6 +48,7 @@ struct i915_params {
>>>>       int enable_guc_loading;
>>>>       int enable_guc_submission;
>>>>       int guc_log_level;
>>>> +    int guc_log_buffer_nr;
>>>>       int use_mmio_flip;
>>>>       int mmio_debug;
>>>>       int edp_vswing;
>>>>
>>>
>>> I did not figure out after a quick read of
>>> Documentation/filesystems/relay.txt whether we really need this to be
>>> configurable?
>>>
>>> If I got it right number of sub-buffers here only has a relation to the
>>> userspace relay consumer latency. If the userspace is responsive should
>>> just two be enough? Or the existing default of four was shown in
>>> practice that it is better and good enough?
>>>
>> Yes one of the use of this module parameter is to give User some leeway
>> i.e. more time to collect logs from the relay buffer. User may not be
>> always able to match the rate at which logs are being produced from the
>> GuC side.
>>
>> 2 could be too less.
>> Even 4, when running a benchmark, was proving less and not able to match
>> the Driver rate (this might change after some optimization is done from
>> User space side also, like splice).
>
> Okay, it makes sense for it to be bigger than four by default then,
> correct?
>
>> The other use is to ensure capturing of all boot time logs, even with
>> maximum verbosity level. The default number of sub buffers may not
>> always be sufficient to store all the logs from boot, by the time User
>> is ready to capture the logs.
>> Saw about 8 flush interrupts coming from GuC during the boot.
>
> How important it is for a default value to capture all activity since boot?
>
> I think we need to keep in mind here that amount of that activity may be
> a lot different with different setups so it might not be that
> interesting after all.
>
> Someone will log in via a display manager, which may generate a widely
> differing amount of GPU activity, until they start the logger. Someone
> else on the other hand might be booting to vt only, starting the logger,
> and only then starting the graphical UI.
>

Agree, that's why its useful to have a provision for altering the
size of buffer.

>>> I am just not sure this is a useful module parameter without some more
>>> data.
>>>
>>> Even if it is needed, as minimum I think the name should reflect this is
>>> about the relay side of things and not the GuC log buffer itself. So
>>> something like i915.guc_relay_log_subbuf_nr or something.
>> Fine will use this name.
>>
>>> With the matching description of course.
>>>
>> Is the current description not apt ?
>> "Number of sub buffers to store GuC firmware logs (default: 4)");"
>
> My thinking is, what will this parameter mostly be used for? I think the
> default needs to be such that a reasonable implementation of an
> userspace logger can cope with the flush rate. I am not so sure that
> capturing boot time activity by default is that critical.
>
The default value can be kept as 2 also, as you suggested .

Actually since logging would generally be disabled by default, so if 
User has a need to capture all boot time logs, it will have to anyways 
enable the logging (i915.guc_log_level >= 0) first and so at that time
it can also chose a suitable i915.guc_relay_log_subbuf_nr value.
The logging stats from the output of 'i915_guc_info' debugfs can be used 
to know how many sub buffers will be required to capture all boot time logs.

Similarly for run time logging, User can tune the value according to the 
benchmarks, as for some of the benchmarks the amount of logs
generated is comparatively much more.

> Assuming you find a value to satisfy the above, what are the scenarios
> someone will need/want to tweak it and what description of the tunable
> would help them understand what it is for?
>
> Should we say, in the description, something like "increase this if you
> want to capture all boot time activity until you can start the logging"
> and/or "increase this if experiencing logging drops" ?
>
Yes this would be much better description, in fact I myself wanted to 
use a similar description initially, but for brevity sake did not use it 
(though sorry could have captured that in commit message).
Will use this only now.

Best regards
Akash
> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce flush interrupts
  2016-07-18  9:54           ` Tvrtko Ursulin
@ 2016-07-18 12:35             ` Goel, Akash
  2016-07-18 13:08               ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-18 12:35 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/18/2016 3:24 PM, Tvrtko Ursulin wrote:
>
> On 15/07/16 17:20, Goel, Akash wrote:
>> On 7/15/2016 8:37 PM, Tvrtko Ursulin wrote:
>>> On 15/07/16 15:42, Goel, Akash wrote:
>>>> On 7/15/2016 5:27 PM, Tvrtko Ursulin wrote:
>>>>>
>>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>>> From: Akash Goel <akash.goel@intel.com>
>>>>>>
>>>>>> In cases where GuC generate logs at a very high rate, correspondingly
>>>>>> the rate of flush interrupts is also very high.
>>>>>> So far total 8 pages were allocated for storing both ISR & DPC logs.
>>>>>> As per the half-full draining protocol followed by GuC, by doubling
>>>>>> the number of pages, the frequency of flush interrupts can be cut
>>>>>> down
>>>>>> to almost half, which then helps in reducing the logging overhead.
>>>>>> So now allocating 8 pages apiece for ISR & DPC logs.
>>>>>>
>>>>>> Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>>> ---
>>>>>>   drivers/gpu/drm/i915/intel_guc_fwif.h | 8 ++++----
>>>>>>   1 file changed, 4 insertions(+), 4 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>>> b/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>>> index 1de6928..7521ed5 100644
>>>>>> --- a/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>>> +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>>> @@ -104,9 +104,9 @@
>>>>>>   #define   GUC_LOG_ALLOC_IN_MEGABYTE    (1 << 3)
>>>>>>   #define   GUC_LOG_CRASH_PAGES        1
>>>>>>   #define   GUC_LOG_CRASH_SHIFT        4
>>>>>> -#define   GUC_LOG_DPC_PAGES        3
>>>>>> +#define   GUC_LOG_DPC_PAGES        7
>>>>>>   #define   GUC_LOG_DPC_SHIFT        6
>>>>>> -#define   GUC_LOG_ISR_PAGES        3
>>>>>> +#define   GUC_LOG_ISR_PAGES        7
>>>>>>   #define   GUC_LOG_ISR_SHIFT        9
>>>>>>   #define   GUC_LOG_BUF_ADDR_SHIFT    12
>>>>>>
>>>>>> @@ -436,9 +436,9 @@ enum guc_log_buffer_type {
>>>>>>    *        |   Crash dump state header     |
>>>>>>    * Page1  +-------------------------------+
>>>>>>    *        |           ISR logs            |
>>>>>> - * Page5  +-------------------------------+
>>>>>> - *        |           DPC logs            |
>>>>>>    * Page9  +-------------------------------+
>>>>>> + *        |           DPC logs            |
>>>>>> + * Page17 +-------------------------------+
>>>>>>    *        |         Crash Dump logs       |
>>>>>>    *        +-------------------------------+
>>>>>>    *
>>>>>>
>>>>>
>>>>> I don't mind - but does it help? And how much and for what? Haven't
>>>>> you
>>>>> later found that the uncached reads were the main issue?
>>>> This change along with kthread patch, helped reduce the overflow counts
>>>> and even eliminate them for some benchmarks.
>>>>
>>>> Though with the impending optimization for Uncached reads there should
>>>> be further improvements but in my view, notwithstanding the improvement
>>>> w.r.t overflow count, its still a better configuration to work with as
>>>> flush interrupt frequency is cut down to half and not able to see any
>>>> apparent downsides to it.
>>>
>>> I was primarily thinking to go with a minimal and simplest set of
>>> patches to implement the feature.
>>>
>> I second that and working with the same intent.
>>
>>> Logic was that apparently none of the smart and complex optimisations
>>> managed to solve the dropped interrupt issue, until the slowness of the
>>> uncached read was discovered to be the real/main issue.
>>>
>>> So it seems that is something that definitely needs to be implemented.
>>> (Whether or not it will be possible to use SSE instructions to do the
>>> read I don't know.)
>>>
>>
>> log buffer resizing and rt priority kthread changes have definitely
>> helped significantly.
>>
>> Only of late we realized that there is a potential way to speed up
>> Uncached reads also. Moreover I am yet to test that on kernel side.
>> So until that is tested & proves to be enough, we have to rely on the
>> other optimizations & can't dismiss them
>
> Maybe, depends if, what I thought was the case, none of the other
> optimizations actually enabled a drop-free logging in all interesting
> scenarios.
>
> If we conclude that simply improving the copy speed removes the need for
> any other optimisations and complications, we can talk about whether
> every individual one of those still makes sense.
>
In my opinion we should keep this change, regardless of the copying 
speed up. Moreover this is a straight forward change.

Actually this also helps in reducing the output log file size, apart
from reducing the flush interrupt count.
With the original settings, 44 KB was needed for one snapshot.
With the modified settings, 76 KB is needed for one snapshot but it
will be equivalent to 2 snapshots of the original setting.
So 12KB saving, every 88 KB, over the original setting.

Best regards
Akash

>>> Assuming it is possible, then the question is whether there is need for
>>> all the other optimisations. Ie. do we need the kthread with rtprio or
>>> would a simple worker be enough?
>> I think we can take a call, once we have the results with Uncached read
>> optimization.
>
> Agreed. Lets see how that works out and the discuss on how the final
> series should look like.
>
> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs
  2016-07-18 12:19         ` Goel, Akash
@ 2016-07-18 13:06           ` Tvrtko Ursulin
  2016-07-18 13:40             ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-18 13:06 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 18/07/16 13:19, Goel, Akash wrote:
> On 7/18/2016 3:36 PM, Tvrtko Ursulin wrote:
>> On 15/07/16 16:36, Goel, Akash wrote:
>>> On 7/15/2016 4:45 PM, Tvrtko Ursulin wrote:
>>>>
>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>> From: Akash Goel <akash.goel@intel.com>
>>>>>
>>>>> On recieving the log buffer flush interrupt from GuC firmware, Driver
>>>>> stores the snapshot of the log buffer in a local buffer, from which
>>>>> Userspace can pull the logs. By default Driver store, up to, 4
>>>>> snapshots
>>>>> of the log buffer in a local buffer (managed by relay).
>>>>> Added a new module (read only) param, 'guc_log_size', through which
>>>>> User
>>>>> can specify the number of snapshots of log buffer to be stored in
>>>>> local
>>>>> buffer. This can be used to ensure capturing of all boot time logs
>>>>> even
>>>>> with high verbosity level.
>>>>>
>>>>> v2: Rename module param to more apt name 'guc_log_buffer_nr'. (Nikula)
>>>>>
>>>>> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>> ---
>>>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +--
>>>>>   drivers/gpu/drm/i915/i915_params.c         | 5 +++++
>>>>>   drivers/gpu/drm/i915/i915_params.h         | 1 +
>>>>>   3 files changed, 7 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> index 2e3b723..009d7c0 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> @@ -1046,8 +1046,7 @@ static int guc_create_log_relay_file(struct
>>>>> intel_guc *guc)
>>>>>
>>>>>       /* Keep the size of sub buffers same as shared log buffer */
>>>>>       subbuf_size = guc->log.obj->base.size;
>>>>> -    /* TODO: Decide based on the User's input */
>>>>> -    n_subbufs = 4;
>>>>> +    n_subbufs = i915.guc_log_buffer_nr;
>>>>>
>>>>>       guc_log_relay_chan = relay_open("guc_log", log_dir,
>>>>>               subbuf_size, n_subbufs, &relay_callbacks, dev);
>>>>> diff --git a/drivers/gpu/drm/i915/i915_params.c
>>>>> b/drivers/gpu/drm/i915/i915_params.c
>>>>> index 8b13bfa..d30c972 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_params.c
>>>>> +++ b/drivers/gpu/drm/i915/i915_params.c
>>>>> @@ -57,6 +57,7 @@ struct i915_params i915 __read_mostly = {
>>>>>       .enable_guc_loading = -1,
>>>>>       .enable_guc_submission = -1,
>>>>>       .guc_log_level = -1,
>>>>> +    .guc_log_buffer_nr = 4,
>>>>>       .enable_dp_mst = true,
>>>>>       .inject_load_failure = 0,
>>>>>       .enable_dpcd_backlight = false,
>>>>> @@ -214,6 +215,10 @@ module_param_named(guc_log_level,
>>>>> i915.guc_log_level, int, 0400);
>>>>>   MODULE_PARM_DESC(guc_log_level,
>>>>>       "GuC firmware logging level (-1:disabled (default),
>>>>> 0-3:enabled)");
>>>>>
>>>>> +module_param_named(guc_log_buffer_nr, i915.guc_log_buffer_nr, int,
>>>>> 0400);
>>>>> +MODULE_PARM_DESC(guc_log_buffer_nr,
>>>>> +    "Number of sub buffers to store GuC firmware logs (default: 4)");
>>>>> +
>>>>>   module_param_named_unsafe(enable_dp_mst, i915.enable_dp_mst, bool,
>>>>> 0600);
>>>>>   MODULE_PARM_DESC(enable_dp_mst,
>>>>>       "Enable multi-stream transport (MST) for new DisplayPort sinks.
>>>>> (default: true)");
>>>>> diff --git a/drivers/gpu/drm/i915/i915_params.h
>>>>> b/drivers/gpu/drm/i915/i915_params.h
>>>>> index 0ad020b..14ca855 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_params.h
>>>>> +++ b/drivers/gpu/drm/i915/i915_params.h
>>>>> @@ -48,6 +48,7 @@ struct i915_params {
>>>>>       int enable_guc_loading;
>>>>>       int enable_guc_submission;
>>>>>       int guc_log_level;
>>>>> +    int guc_log_buffer_nr;
>>>>>       int use_mmio_flip;
>>>>>       int mmio_debug;
>>>>>       int edp_vswing;
>>>>>
>>>>
>>>> I did not figure out after a quick read of
>>>> Documentation/filesystems/relay.txt whether we really need this to be
>>>> configurable?
>>>>
>>>> If I got it right number of sub-buffers here only has a relation to the
>>>> userspace relay consumer latency. If the userspace is responsive should
>>>> just two be enough? Or the existing default of four was shown in
>>>> practice that it is better and good enough?
>>>>
>>> Yes one of the use of this module parameter is to give User some leeway
>>> i.e. more time to collect logs from the relay buffer. User may not be
>>> always able to match the rate at which logs are being produced from the
>>> GuC side.
>>>
>>> 2 could be too less.
>>> Even 4, when running a benchmark, was proving less and not able to match
>>> the Driver rate (this might change after some optimization is done from
>>> User space side also, like splice).
>>
>> Okay, it makes sense for it to be bigger than four by default then,
>> correct?
>>
>>> The other use is to ensure capturing of all boot time logs, even with
>>> maximum verbosity level. The default number of sub buffers may not
>>> always be sufficient to store all the logs from boot, by the time User
>>> is ready to capture the logs.
>>> Saw about 8 flush interrupts coming from GuC during the boot.
>>
>> How important it is for a default value to capture all activity since
>> boot?
>>
>> I think we need to keep in mind here that amount of that activity may be
>> a lot different with different setups so it might not be that
>> interesting after all.
>>
>> Someone will log in via a display manager, which may generate a widely
>> differing amount of GPU activity, until they start the logger. Someone
>> else on the other hand might be booting to vt only, starting the logger,
>> and only then starting the graphical UI.
>>
>
> Agree, that's why its useful to have a provision for altering the
> size of buffer.

Maybe. :) I have to be critical here since bar for adding new params is 
high. If we can have a default value which works for everyone it would 
be better. Of course if the size is not too big then.

That's why I asked how important is being able to capture everything 
since boot. Is that a real use case and how important it is?

>>>> I am just not sure this is a useful module parameter without some more
>>>> data.
>>>>
>>>> Even if it is needed, as minimum I think the name should reflect
>>>> this is
>>>> about the relay side of things and not the GuC log buffer itself. So
>>>> something like i915.guc_relay_log_subbuf_nr or something.
>>> Fine will use this name.
>>>
>>>> With the matching description of course.
>>>>
>>> Is the current description not apt ?
>>> "Number of sub buffers to store GuC firmware logs (default: 4)");"
>>
>> My thinking is, what will this parameter mostly be used for? I think the
>> default needs to be such that a reasonable implementation of an
>> userspace logger can cope with the flush rate. I am not so sure that
>> capturing boot time activity by default is that critical.
>>
> The default value can be kept as 2 also, as you suggested .

But you said even 4 was not enough to ensure userspace logger can keep up?

> Actually since logging would generally be disabled by default, so if
> User has a need to capture all boot time logs, it will have to anyways
> enable the logging (i915.guc_log_level >= 0) first and so at that time
> it can also chose a suitable i915.guc_relay_log_subbuf_nr value.
> The logging stats from the output of 'i915_guc_info' debugfs can be used
> to know how many sub buffers will be required to capture all boot time
> logs.
>
> Similarly for run time logging, User can tune the value according to the
> benchmarks, as for some of the benchmarks the amount of logs
> generated is comparatively much more.

I don't see why would they need to tune this depending on the benchmark. 
My assumption is they start the logger and then start the benchmark. The 
only important thing it that number of sub-buffers is large enough for 
userspace to cope with the flush rate.

>> Assuming you find a value to satisfy the above, what are the scenarios
>> someone will need/want to tweak it and what description of the tunable
>> would help them understand what it is for?
>>
>> Should we say, in the description, something like "increase this if you
>> want to capture all boot time activity until you can start the logging"
>> and/or "increase this if experiencing logging drops" ?
>>
> Yes this would be much better description, in fact I myself wanted to
> use a similar description initially, but for brevity sake did not use it
> (though sorry could have captured that in commit message).
> Will use this only now.

Cool.

Regards,

Tvrtko

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce flush interrupts
  2016-07-18 12:35             ` Goel, Akash
@ 2016-07-18 13:08               ` Tvrtko Ursulin
  0 siblings, 0 replies; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-18 13:08 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 18/07/16 13:35, Goel, Akash wrote:
>
>
> On 7/18/2016 3:24 PM, Tvrtko Ursulin wrote:
>>
>> On 15/07/16 17:20, Goel, Akash wrote:
>>> On 7/15/2016 8:37 PM, Tvrtko Ursulin wrote:
>>>> On 15/07/16 15:42, Goel, Akash wrote:
>>>>> On 7/15/2016 5:27 PM, Tvrtko Ursulin wrote:
>>>>>>
>>>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>>>> From: Akash Goel <akash.goel@intel.com>
>>>>>>>
>>>>>>> In cases where GuC generate logs at a very high rate,
>>>>>>> correspondingly
>>>>>>> the rate of flush interrupts is also very high.
>>>>>>> So far total 8 pages were allocated for storing both ISR & DPC logs.
>>>>>>> As per the half-full draining protocol followed by GuC, by doubling
>>>>>>> the number of pages, the frequency of flush interrupts can be cut
>>>>>>> down
>>>>>>> to almost half, which then helps in reducing the logging overhead.
>>>>>>> So now allocating 8 pages apiece for ISR & DPC logs.
>>>>>>>
>>>>>>> Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>>>> ---
>>>>>>>   drivers/gpu/drm/i915/intel_guc_fwif.h | 8 ++++----
>>>>>>>   1 file changed, 4 insertions(+), 4 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>>>> b/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>>>> index 1de6928..7521ed5 100644
>>>>>>> --- a/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>>>> +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
>>>>>>> @@ -104,9 +104,9 @@
>>>>>>>   #define   GUC_LOG_ALLOC_IN_MEGABYTE    (1 << 3)
>>>>>>>   #define   GUC_LOG_CRASH_PAGES        1
>>>>>>>   #define   GUC_LOG_CRASH_SHIFT        4
>>>>>>> -#define   GUC_LOG_DPC_PAGES        3
>>>>>>> +#define   GUC_LOG_DPC_PAGES        7
>>>>>>>   #define   GUC_LOG_DPC_SHIFT        6
>>>>>>> -#define   GUC_LOG_ISR_PAGES        3
>>>>>>> +#define   GUC_LOG_ISR_PAGES        7
>>>>>>>   #define   GUC_LOG_ISR_SHIFT        9
>>>>>>>   #define   GUC_LOG_BUF_ADDR_SHIFT    12
>>>>>>>
>>>>>>> @@ -436,9 +436,9 @@ enum guc_log_buffer_type {
>>>>>>>    *        |   Crash dump state header     |
>>>>>>>    * Page1  +-------------------------------+
>>>>>>>    *        |           ISR logs            |
>>>>>>> - * Page5  +-------------------------------+
>>>>>>> - *        |           DPC logs            |
>>>>>>>    * Page9  +-------------------------------+
>>>>>>> + *        |           DPC logs            |
>>>>>>> + * Page17 +-------------------------------+
>>>>>>>    *        |         Crash Dump logs       |
>>>>>>>    *        +-------------------------------+
>>>>>>>    *
>>>>>>>
>>>>>>
>>>>>> I don't mind - but does it help? And how much and for what? Haven't
>>>>>> you
>>>>>> later found that the uncached reads were the main issue?
>>>>> This change along with kthread patch, helped reduce the overflow
>>>>> counts
>>>>> and even eliminate them for some benchmarks.
>>>>>
>>>>> Though with the impending optimization for Uncached reads there should
>>>>> be further improvements but in my view, notwithstanding the
>>>>> improvement
>>>>> w.r.t overflow count, its still a better configuration to work with as
>>>>> flush interrupt frequency is cut down to half and not able to see any
>>>>> apparent downsides to it.
>>>>
>>>> I was primarily thinking to go with a minimal and simplest set of
>>>> patches to implement the feature.
>>>>
>>> I second that and working with the same intent.
>>>
>>>> Logic was that apparently none of the smart and complex optimisations
>>>> managed to solve the dropped interrupt issue, until the slowness of the
>>>> uncached read was discovered to be the real/main issue.
>>>>
>>>> So it seems that is something that definitely needs to be implemented.
>>>> (Whether or not it will be possible to use SSE instructions to do the
>>>> read I don't know.)
>>>>
>>>
>>> log buffer resizing and rt priority kthread changes have definitely
>>> helped significantly.
>>>
>>> Only of late we realized that there is a potential way to speed up
>>> Uncached reads also. Moreover I am yet to test that on kernel side.
>>> So until that is tested & proves to be enough, we have to rely on the
>>> other optimizations & can't dismiss them
>>
>> Maybe, depends if, what I thought was the case, none of the other
>> optimizations actually enabled a drop-free logging in all interesting
>> scenarios.
>>
>> If we conclude that simply improving the copy speed removes the need for
>> any other optimisations and complications, we can talk about whether
>> every individual one of those still makes sense.
>>
> In my opinion we should keep this change, regardless of the copying
> speed up. Moreover this is a straight forward change.
>
> Actually this also helps in reducing the output log file size, apart
> from reducing the flush interrupt count.
> With the original settings, 44 KB was needed for one snapshot.
> With the modified settings, 76 KB is needed for one snapshot but it
> will be equivalent to 2 snapshots of the original setting.
> So 12KB saving, every 88 KB, over the original setting.

That is indeed a good benefit. Did not realize there is this space 
wastage problem.

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Regards,

Tvrtko



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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs
  2016-07-18 13:06           ` Tvrtko Ursulin
@ 2016-07-18 13:40             ` Goel, Akash
  0 siblings, 0 replies; 87+ messages in thread
From: Goel, Akash @ 2016-07-18 13:40 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/18/2016 6:36 PM, Tvrtko Ursulin wrote:
>
> On 18/07/16 13:19, Goel, Akash wrote:
>> On 7/18/2016 3:36 PM, Tvrtko Ursulin wrote:
>>> On 15/07/16 16:36, Goel, Akash wrote:
>>>> On 7/15/2016 4:45 PM, Tvrtko Ursulin wrote:
>>>>>
>>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>>> From: Akash Goel <akash.goel@intel.com>
>>>>>>
>>>>>> On recieving the log buffer flush interrupt from GuC firmware, Driver
>>>>>> stores the snapshot of the log buffer in a local buffer, from which
>>>>>> Userspace can pull the logs. By default Driver store, up to, 4
>>>>>> snapshots
>>>>>> of the log buffer in a local buffer (managed by relay).
>>>>>> Added a new module (read only) param, 'guc_log_size', through which
>>>>>> User
>>>>>> can specify the number of snapshots of log buffer to be stored in
>>>>>> local
>>>>>> buffer. This can be used to ensure capturing of all boot time logs
>>>>>> even
>>>>>> with high verbosity level.
>>>>>>
>>>>>> v2: Rename module param to more apt name 'guc_log_buffer_nr'.
>>>>>> (Nikula)
>>>>>>
>>>>>> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
>>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>>> ---
>>>>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 3 +--
>>>>>>   drivers/gpu/drm/i915/i915_params.c         | 5 +++++
>>>>>>   drivers/gpu/drm/i915/i915_params.h         | 1 +
>>>>>>   3 files changed, 7 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>>> index 2e3b723..009d7c0 100644
>>>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>>> @@ -1046,8 +1046,7 @@ static int guc_create_log_relay_file(struct
>>>>>> intel_guc *guc)
>>>>>>
>>>>>>       /* Keep the size of sub buffers same as shared log buffer */
>>>>>>       subbuf_size = guc->log.obj->base.size;
>>>>>> -    /* TODO: Decide based on the User's input */
>>>>>> -    n_subbufs = 4;
>>>>>> +    n_subbufs = i915.guc_log_buffer_nr;
>>>>>>
>>>>>>       guc_log_relay_chan = relay_open("guc_log", log_dir,
>>>>>>               subbuf_size, n_subbufs, &relay_callbacks, dev);
>>>>>> diff --git a/drivers/gpu/drm/i915/i915_params.c
>>>>>> b/drivers/gpu/drm/i915/i915_params.c
>>>>>> index 8b13bfa..d30c972 100644
>>>>>> --- a/drivers/gpu/drm/i915/i915_params.c
>>>>>> +++ b/drivers/gpu/drm/i915/i915_params.c
>>>>>> @@ -57,6 +57,7 @@ struct i915_params i915 __read_mostly = {
>>>>>>       .enable_guc_loading = -1,
>>>>>>       .enable_guc_submission = -1,
>>>>>>       .guc_log_level = -1,
>>>>>> +    .guc_log_buffer_nr = 4,
>>>>>>       .enable_dp_mst = true,
>>>>>>       .inject_load_failure = 0,
>>>>>>       .enable_dpcd_backlight = false,
>>>>>> @@ -214,6 +215,10 @@ module_param_named(guc_log_level,
>>>>>> i915.guc_log_level, int, 0400);
>>>>>>   MODULE_PARM_DESC(guc_log_level,
>>>>>>       "GuC firmware logging level (-1:disabled (default),
>>>>>> 0-3:enabled)");
>>>>>>
>>>>>> +module_param_named(guc_log_buffer_nr, i915.guc_log_buffer_nr, int,
>>>>>> 0400);
>>>>>> +MODULE_PARM_DESC(guc_log_buffer_nr,
>>>>>> +    "Number of sub buffers to store GuC firmware logs (default:
>>>>>> 4)");
>>>>>> +
>>>>>>   module_param_named_unsafe(enable_dp_mst, i915.enable_dp_mst, bool,
>>>>>> 0600);
>>>>>>   MODULE_PARM_DESC(enable_dp_mst,
>>>>>>       "Enable multi-stream transport (MST) for new DisplayPort sinks.
>>>>>> (default: true)");
>>>>>> diff --git a/drivers/gpu/drm/i915/i915_params.h
>>>>>> b/drivers/gpu/drm/i915/i915_params.h
>>>>>> index 0ad020b..14ca855 100644
>>>>>> --- a/drivers/gpu/drm/i915/i915_params.h
>>>>>> +++ b/drivers/gpu/drm/i915/i915_params.h
>>>>>> @@ -48,6 +48,7 @@ struct i915_params {
>>>>>>       int enable_guc_loading;
>>>>>>       int enable_guc_submission;
>>>>>>       int guc_log_level;
>>>>>> +    int guc_log_buffer_nr;
>>>>>>       int use_mmio_flip;
>>>>>>       int mmio_debug;
>>>>>>       int edp_vswing;
>>>>>>
>>>>>
>>>>> I did not figure out after a quick read of
>>>>> Documentation/filesystems/relay.txt whether we really need this to be
>>>>> configurable?
>>>>>
>>>>> If I got it right number of sub-buffers here only has a relation to
>>>>> the
>>>>> userspace relay consumer latency. If the userspace is responsive
>>>>> should
>>>>> just two be enough? Or the existing default of four was shown in
>>>>> practice that it is better and good enough?
>>>>>
>>>> Yes one of the use of this module parameter is to give User some leeway
>>>> i.e. more time to collect logs from the relay buffer. User may not be
>>>> always able to match the rate at which logs are being produced from the
>>>> GuC side.
>>>>
>>>> 2 could be too less.
>>>> Even 4, when running a benchmark, was proving less and not able to
>>>> match
>>>> the Driver rate (this might change after some optimization is done from
>>>> User space side also, like splice).
>>>
>>> Okay, it makes sense for it to be bigger than four by default then,
>>> correct?
>>>
>>>> The other use is to ensure capturing of all boot time logs, even with
>>>> maximum verbosity level. The default number of sub buffers may not
>>>> always be sufficient to store all the logs from boot, by the time User
>>>> is ready to capture the logs.
>>>> Saw about 8 flush interrupts coming from GuC during the boot.
>>>
>>> How important it is for a default value to capture all activity since
>>> boot?
>>>
>>> I think we need to keep in mind here that amount of that activity may be
>>> a lot different with different setups so it might not be that
>>> interesting after all.
>>>
>>> Someone will log in via a display manager, which may generate a widely
>>> differing amount of GPU activity, until they start the logger. Someone
>>> else on the other hand might be booting to vt only, starting the logger,
>>> and only then starting the graphical UI.
>>>
>>
>> Agree, that's why its useful to have a provision for altering the
>> size of buffer.
>
> Maybe. :) I have to be critical here since bar for adding new params is
> high. If we can have a default value which works for everyone it would
> be better. Of course if the size is not too big then.
>
Sorry that's what I unable to say right now, a default value which can 
cater to most workloads and is not too high also.

> That's why I asked how important is being able to capture everything
> since boot. Is that a real use case and how important it is?
>
It might be needed in certain cases, probably while enabling new platforms.

>>>>> I am just not sure this is a useful module parameter without some more
>>>>> data.
>>>>>
>>>>> Even if it is needed, as minimum I think the name should reflect
>>>>> this is
>>>>> about the relay side of things and not the GuC log buffer itself. So
>>>>> something like i915.guc_relay_log_subbuf_nr or something.
>>>> Fine will use this name.
>>>>
>>>>> With the matching description of course.
>>>>>
>>>> Is the current description not apt ?
>>>> "Number of sub buffers to store GuC firmware logs (default: 4)");"
>>>
>>> My thinking is, what will this parameter mostly be used for? I think the
>>> default needs to be such that a reasonable implementation of an
>>> userspace logger can cope with the flush rate. I am not so sure that
>>> capturing boot time activity by default is that critical.
>>>
>> The default value can be kept as 2 also, as you suggested .
>
> But you said even 4 was not enough to ensure userspace logger can keep up?
>

Yes 4 doesn't seems to be enough for runtime logging with certain 
benchmarks at least.

>> Actually since logging would generally be disabled by default, so if
>> User has a need to capture all boot time logs, it will have to anyways
>> enable the logging (i915.guc_log_level >= 0) first and so at that time
>> it can also chose a suitable i915.guc_relay_log_subbuf_nr value.
>> The logging stats from the output of 'i915_guc_info' debugfs can be used
>> to know how many sub buffers will be required to capture all boot time
>> logs.
>>
>> Similarly for run time logging, User can tune the value according to the
>> benchmarks, as for some of the benchmarks the amount of logs
>> generated is comparatively much more.
>
> I don't see why would they need to tune this depending on the benchmark.
> My assumption is they start the logger and then start the benchmark. The
> only important thing it that number of sub-buffers is large enough for
> userspace to cope with the flush rate.
>

Yes if a reasonable default value can be figured out, which can cover 
most workloads, then no need of this parameter.

>>> Assuming you find a value to satisfy the above, what are the scenarios
>>> someone will need/want to tweak it and what description of the tunable
>>> would help them understand what it is for?
>>>
>>> Should we say, in the description, something like "increase this if you
>>> want to capture all boot time activity until you can start the logging"
>>> and/or "increase this if experiencing logging drops" ?
>>>
>> Yes this would be much better description, in fact I myself wanted to
>> use a similar description initially, but for brevity sake did not use it
>> (though sorry could have captured that in commit message).
>> Will use this only now.
>
> Cool.
>
> Regards,
>
> Tvrtko
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 06/17] drm/i915: Handle log buffer flush interrupt event from GuC
  2016-07-10 13:41 ` [PATCH 06/17] drm/i915: Handle log buffer flush interrupt event from GuC akash.goel
@ 2016-07-19 10:58   ` Tvrtko Ursulin
  2016-07-20  3:29     ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-19 10:58 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>
> GuC ukernel sends an interrupt to Host to flush the log buffer
> and expects Host to correspondingly update the read pointer
> information in the state structure, once it has consumed the
> log buffer contents by copying them to a file or buffer.
> Even if Host couldn't copy the contents, it can still update the
> read pointer so that logging state is not disturbed on GuC side.
>
> v2:
> - Use a dedicated workqueue for handling flush interrupt. (Tvrtko)
> - Reduce the overall log buffer copying time by skipping the copy of
>    crash buffer area for regular cases and copying only the state
>    structure data in first page.
>
> v3:
>   - Create a vmalloc mapping of log buffer. (Chris)
>   - Cover the flush acknowledgment under rpm get & put.(Chris)
>   - Revert the change of skipping the copy of crash dump area, as
>     not really needed, will be covered by subsequent patch.
>
> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_drv.c            |  13 +++
>   drivers/gpu/drm/i915/i915_guc_submission.c | 148 +++++++++++++++++++++++++++++
>   drivers/gpu/drm/i915/i915_irq.c            |   5 +-
>   drivers/gpu/drm/i915/intel_guc.h           |   3 +
>   4 files changed, 167 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index b9a8117..25c6b9b 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -791,8 +791,20 @@ static int i915_workqueues_init(struct drm_i915_private *dev_priv)
>   	if (dev_priv->hotplug.dp_wq == NULL)
>   		goto out_free_wq;
>
> +	if (HAS_GUC_SCHED(dev_priv)) {
> +		/* Need a dedicated wq to process log buffer flush interrupts
> +		 * from GuC without much delay so as to avoid any loss of logs.
> +		 */
> +		dev_priv->guc.log.wq =
> +			alloc_ordered_workqueue("i915-guc_log", 0);
> +		if (dev_priv->guc.log.wq == NULL)
> +			goto out_free_hotplug_dp_wq;
> +	}
> +
>   	return 0;
>
> +out_free_hotplug_dp_wq:
> +	destroy_workqueue(dev_priv->hotplug.dp_wq);
>   out_free_wq:
>   	destroy_workqueue(dev_priv->wq);
>   out_err:
> @@ -803,6 +815,7 @@ out_err:
>
>   static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv)
>   {
> +	destroy_workqueue(dev_priv->guc.log.wq);

I am ignoring the wq parts of the patch since the next series may look 
different in this respect.

However you may need to have wq destruction under the same HAS_GUC_SCHED 
condition as when you create it.

>   	destroy_workqueue(dev_priv->hotplug.dp_wq);
>   	destroy_workqueue(dev_priv->wq);
>   }
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index 0bac172..d3dbb8e 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -172,6 +172,15 @@ static int host2guc_sample_forcewake(struct intel_guc *guc,
>   	return host2guc_action(guc, data, ARRAY_SIZE(data));
>   }
>
> +static int host2guc_logbuffer_flush_complete(struct intel_guc *guc)
> +{
> +	u32 data[1];
> +
> +	data[0] = HOST2GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE;
> +
> +	return host2guc_action(guc, data, 1);
> +}
> +
>   /*
>    * Initialise, update, or clear doorbell data shared with the GuC
>    *
> @@ -825,6 +834,123 @@ err:
>   	return NULL;
>   }
>
> +static void guc_move_to_next_buf(struct intel_guc *guc)
> +{
> +	return;
> +}
> +
> +static void* guc_get_write_buffer(struct intel_guc *guc)
> +{
> +	return NULL;
> +}
> +
> +static void guc_read_update_log_buffer(struct drm_device *dev)

dev_priv should be passed in for driver internal functions.

> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_guc *guc = &dev_priv->guc;
> +	struct guc_log_buffer_state *log_buffer_state, *log_buffer_copy_state;
> +	struct guc_log_buffer_state log_buffer_state_local;
> +	void *src_data_ptr, *dst_data_ptr;
> +	u32 i, buffer_size;
> +
> +	if (!guc->log.obj || !guc->log.buf_addr)
> +		return;
> +
> +	log_buffer_state = src_data_ptr = guc->log.buf_addr;
> +
> +	/* Get the pointer to local buffer to store the logs */
> +	dst_data_ptr = log_buffer_copy_state = guc_get_write_buffer(guc);

This will return NULL so the loop below doesn't do anything much. I 
assume at this point in the patch series things are not wired up yet?

> +
> +	/* Actual logs are present from the 2nd page */
> +	src_data_ptr += PAGE_SIZE;
> +	dst_data_ptr += PAGE_SIZE;
> +
> +	for (i = 0; i < GUC_MAX_LOG_BUFFER; i++) {
> +		log_buffer_state_local = *log_buffer_state;
> +		buffer_size = log_buffer_state_local.size;
> +
> +		if (log_buffer_copy_state) {
> +			/* First copy the state structure */
> +			memcpy(log_buffer_copy_state, &log_buffer_state_local,
> +					sizeof(struct guc_log_buffer_state));

For some reason I find it hard to grasp the meaning of the different 
variables with slightly different names:

log_buffer_state
log_buffer_copy_state,
log_buffer_state_local

The _local one for example, it seems to be copied into from the GuC 
mapping and then copied again into log_buffer_copy_state.

Why do you need two copies of it?

And why sometimes the code does a structure copy and sometimes explicit 
memcpy?

I think even worse, when it does a structure copy:

log_buffer_state_local = *log_buffer state;

The log_buffer_state is a GEM object mapping. So in my mind it would be 
better the do the explicit memcpy there.

And then this memcpy between the local copy and write buffer, that will 
be into the relay sub buffer?

It seems to me there is no real need for log_buffer_state_local since 
the bottom of the loop still accesses it via the GEM obj mapping 
(log_buffer_state)

So don't know, I find it all confusing.

> +
> +			/* The write pointer could have been updated by the GuC
> +			 * firmware, after sending the flush interrupt to Host,
> +			 * for consistency set the write pointer value to same
> +			 * value of sampled_write_ptr in the snapshot buffer.
> +			 */
> +			log_buffer_copy_state->write_ptr =
> +				log_buffer_copy_state->sampled_write_ptr;
> +
> +			log_buffer_copy_state++;
> +
> +			/* Now copy the actual logs */
> +			memcpy(dst_data_ptr, src_data_ptr, buffer_size);

Doesn't this copy (and overwrite) the same location 
log_buffer_copy_state points to? So the memcpy above and the write_ptr 
update (why?) are then overwritten by this memcpy because dst_data_ptr 
== log_buffer_copy_state at this point unless I am missing something.

> +
> +			src_data_ptr += buffer_size;
> +			dst_data_ptr += buffer_size;
> +		}
> +
> +		/* FIXME: invalidate/flush for log buffer needed */
> +
> +		/* Update the read pointer in the shared log buffer */
> +		log_buffer_state->read_ptr =
> +			log_buffer_state_local.sampled_write_ptr;
> +
> +		/* Clear the 'flush to file' flag */
> +		log_buffer_state->flush_to_file = 0;
> +		log_buffer_state++;
> +	}
> +
> +	if (log_buffer_copy_state)
> +		guc_move_to_next_buf(guc);
> +}
> +
> +static void guc_log_cleanup(struct drm_i915_private *dev_priv)
> +{
> +	struct intel_guc *guc = &dev_priv->guc;
> +
> +	lockdep_assert_held(&dev_priv->drm.struct_mutex);
> +
> +	if (i915.guc_log_level < 0)
> +		return;
> +
> +	/* First disable the flush interrupt */
> +	gen9_disable_guc_interrupts(dev_priv);
> +
> +	if (guc->log.buf_addr)
> +		i915_gem_object_unpin_map(guc->log.obj);
> +
> +	guc->log.buf_addr = NULL;
> +}
> +
> +static int guc_create_log_extras(struct intel_guc *guc)
> +{
> +	struct drm_i915_private *dev_priv = guc_to_i915(guc);
> +	void *vaddr;
> +	int ret;
> +
> +	lockdep_assert_held(&dev_priv->drm.struct_mutex);
> +
> +	/* Nothing to do */
> +	if (i915.guc_log_level < 0)
> +		return 0;
> +
> +	if (!guc->log.buf_addr) {
> +		/* Create a vmalloc mapping of log buffer pages */
> +		vaddr = i915_gem_object_pin_map(guc->log.obj);
> +		if (IS_ERR(vaddr)) {
> +			ret = PTR_ERR(vaddr);
> +			DRM_ERROR("Couldn't map log buffer pages %d\n", ret);
> +			return ret;
> +		}
> +
> +		guc->log.buf_addr = vaddr;
> +	}
> +
> +	return 0;
> +}
> +
>   static void guc_create_log(struct intel_guc *guc)
>   {
>   	struct drm_i915_private *dev_priv = guc_to_i915(guc);
> @@ -851,6 +977,13 @@ static void guc_create_log(struct intel_guc *guc)
>   		}
>
>   		guc->log.obj = obj;
> +
> +		if (guc_create_log_extras(guc)) {
> +			gem_release_guc_obj(guc->log.obj);
> +			guc->log.obj = NULL;
> +			i915.guc_log_level = -1;
> +			return;
> +		}
>   	}
>
>   	/* each allocated unit is a page */
> @@ -1021,6 +1154,7 @@ void i915_guc_submission_fini(struct drm_i915_private *dev_priv)
>   	gem_release_guc_obj(dev_priv->guc.ads_obj);
>   	guc->ads_obj = NULL;
>
> +	guc_log_cleanup(dev_priv);
>   	gem_release_guc_obj(dev_priv->guc.log.obj);
>   	guc->log.obj = NULL;
>
> @@ -1084,3 +1218,17 @@ int intel_guc_resume(struct drm_device *dev)
>
>   	return host2guc_action(guc, data, ARRAY_SIZE(data));
>   }
> +
> +void i915_guc_capture_logs(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +
> +	guc_read_update_log_buffer(dev);
> +
> +	/* Generally device is expected to be active only at this
> +	 * time, so get/put should be really quick.
> +	 */
> +	intel_runtime_pm_get(dev_priv);
> +	host2guc_logbuffer_flush_complete(&dev_priv->guc);
> +	intel_runtime_pm_put(dev_priv);
> +}
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index fd73c94..f90d3c6 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1221,7 +1221,7 @@ static void gen9_guc2host_events_work(struct work_struct *work)
>   	}
>   	spin_unlock_irq(&dev_priv->irq_lock);
>
> -	/* TODO: Handle the events for which GuC interrupted host */
> +	i915_guc_capture_logs(&dev_priv->drm);
>   }
>
>   /**
> @@ -1707,7 +1707,8 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
>   					I915_READ(SOFT_SCRATCH(15)) & ~msg);
>
>   				/* Handle flush interrupt event in bottom half */
> -				queue_work(dev_priv->wq, &dev_priv->guc.events_work);
> +				queue_work(dev_priv->guc.log.wq,
> +						&dev_priv->guc.events_work);
>   			}
>   		}
>   		spin_unlock(&dev_priv->irq_lock);
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index 2663b41..d4f0fae 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -125,6 +125,8 @@ struct intel_guc_fw {
>   struct intel_guc_log {
>   	uint32_t flags;
>   	struct drm_i915_gem_object *obj;
> +	struct workqueue_struct *wq;
> +	void *buf_addr;
>   };
>
>   struct intel_guc {
> @@ -171,5 +173,6 @@ int i915_guc_wq_check_space(struct drm_i915_gem_request *rq);
>   int i915_guc_submit(struct drm_i915_gem_request *rq);
>   void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
>   void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
> +void i915_guc_capture_logs(struct drm_device *dev);
>
>   #endif
>

Regards,

Tvrtko

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 08/17] drm/i915: Forcefully flush GuC log buffer on reset
  2016-07-10 13:41 ` [PATCH 08/17] drm/i915: Forcefully flush GuC log buffer on reset akash.goel
@ 2016-07-19 11:12   ` Tvrtko Ursulin
  2016-07-19 11:21     ` Chris Wilson
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-19 11:12 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>
> If GuC logs are being captured, there should be a force log buffer flush
> action sent to GuC before proceeding with GPU reset and re-initializing
> GUC. Those logs would be useful to understand why the GPU reset was
> initiated.
>
> v2: Rebase.
>
> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_guc_submission.c | 32 ++++++++++++++++++++++++++++++
>   drivers/gpu/drm/i915/i915_irq.c            |  2 ++
>   drivers/gpu/drm/i915/intel_guc.h           |  1 +
>   3 files changed, 35 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index 9b436fa..8cc31c6 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -183,6 +183,16 @@ static int host2guc_logbuffer_flush_complete(struct intel_guc *guc)
>   	return host2guc_action(guc, data, 1);
>   }
>
> +static int host2guc_force_logbuffer_flush(struct intel_guc *guc)
> +{
> +	u32 data[2];
> +
> +	data[0] = HOST2GUC_ACTION_FORCE_LOG_BUFFER_FLUSH;
> +	data[1] = 0;
> +
> +	return host2guc_action(guc, data, 2);
> +}
> +
>   /*
>    * Initialise, update, or clear doorbell data shared with the GuC
>    *
> @@ -1404,6 +1414,28 @@ void i915_guc_capture_logs(struct drm_device *dev)
>   	intel_runtime_pm_put(dev_priv);
>   }
>
> +void i915_guc_capture_logs_on_reset(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +
> +	mutex_lock(&dev->struct_mutex);

Not sure what are the repercussion of taking the mutex on the 
i915_reset_and_wakeup and path (error capture, hangcheck, dont' know 
this area well). Check with Chris and Mika I suppose (cc-ed)?

> +
> +	if (!i915.enable_guc_submission || (i915.guc_log_level < 0))

It would be cool if guc_log_level could be guaranteed to be disabled 
when guc submission is not on. I think it would be more maintainable.

> +		goto end;
> +
> +	/* First disable the interrupts, will be renabled after reset */
> +	gen9_disable_guc_interrupts(dev_priv);
> +
> +	/* Ask GuC to update the log buffer state */
> +	host2guc_force_logbuffer_flush(&dev_priv->guc);
> +
> +	/* GuC would have updated the log buffer by now, so capture it */
> +	i915_guc_capture_logs(dev);
> +
> +end:
> +	mutex_unlock(&dev->struct_mutex);
> +}
> +
>   void i915_guc_unregister(struct drm_device *dev)
>   {
>   	if (!i915.enable_guc_submission)
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index f90d3c6..bdd7a67 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2640,6 +2640,8 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv)
>   		 */
>   		intel_runtime_pm_get(dev_priv);
>
> +		i915_guc_capture_logs_on_reset(&dev_priv->drm);
> +
>   		intel_prepare_reset(dev_priv);
>
>   		/*
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index a784cf8..ed773b5 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -175,6 +175,7 @@ int i915_guc_submit(struct drm_i915_gem_request *rq);
>   void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
>   void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
>   void i915_guc_capture_logs(struct drm_device *dev);
> +void i915_guc_capture_logs_on_reset(struct drm_device *dev);
>   void i915_guc_register(struct drm_device *dev);
>   void i915_guc_unregister(struct drm_device *dev);
>
>

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 08/17] drm/i915: Forcefully flush GuC log buffer on reset
  2016-07-19 11:12   ` Tvrtko Ursulin
@ 2016-07-19 11:21     ` Chris Wilson
  2016-07-20  4:21       ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Chris Wilson @ 2016-07-19 11:21 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: akash.goel, intel-gfx

On Tue, Jul 19, 2016 at 12:12:20PM +0100, Tvrtko Ursulin wrote:
> 
> On 10/07/16 14:41, akash.goel@intel.com wrote:
> >From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> >
> >If GuC logs are being captured, there should be a force log buffer flush
> >action sent to GuC before proceeding with GPU reset and re-initializing
> >GUC. Those logs would be useful to understand why the GPU reset was
> >initiated.
> >
> >v2: Rebase.
> >
> >Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> >Signed-off-by: Akash Goel <akash.goel@intel.com>
> >---
> >  drivers/gpu/drm/i915/i915_guc_submission.c | 32 ++++++++++++++++++++++++++++++
> >  drivers/gpu/drm/i915/i915_irq.c            |  2 ++
> >  drivers/gpu/drm/i915/intel_guc.h           |  1 +
> >  3 files changed, 35 insertions(+)
> >
> >diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> >index 9b436fa..8cc31c6 100644
> >--- a/drivers/gpu/drm/i915/i915_guc_submission.c
> >+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> >@@ -183,6 +183,16 @@ static int host2guc_logbuffer_flush_complete(struct intel_guc *guc)
> >  	return host2guc_action(guc, data, 1);
> >  }
> >
> >+static int host2guc_force_logbuffer_flush(struct intel_guc *guc)
> >+{
> >+	u32 data[2];
> >+
> >+	data[0] = HOST2GUC_ACTION_FORCE_LOG_BUFFER_FLUSH;
> >+	data[1] = 0;
> >+
> >+	return host2guc_action(guc, data, 2);
> >+}
> >+
> >  /*
> >   * Initialise, update, or clear doorbell data shared with the GuC
> >   *
> >@@ -1404,6 +1414,28 @@ void i915_guc_capture_logs(struct drm_device *dev)
> >  	intel_runtime_pm_put(dev_priv);
> >  }
> >
> >+void i915_guc_capture_logs_on_reset(struct drm_device *dev)
> >+{
> >+	struct drm_i915_private *dev_priv = dev->dev_private;
> >+
> >+	mutex_lock(&dev->struct_mutex);
> 
> Not sure what are the repercussion of taking the mutex on the
> i915_reset_and_wakeup and path (error capture, hangcheck, dont' know
> this area well). Check with Chris and Mika I suppose (cc-ed)?

Flat out invalid to take struct_mutex on the error capture path, or any
lock at all really (just in case of driver bugs). Consider it to be an
atomic context that may preempt the driver at any point.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-10 13:41 ` [PATCH 09/17] drm/i915: Debugfs support for GuC logging control akash.goel
  2016-07-10 17:59   ` kbuild test robot
@ 2016-07-19 11:24   ` Tvrtko Ursulin
  2016-07-20  4:42     ` Goel, Akash
  1 sibling, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-19 11:24 UTC (permalink / raw)
  To: akash.goel, intel-gfx


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>
> This patch provides debugfs interface i915_guc_output_control for
> on the fly enabling/disabling of logging in GuC firmware and controlling
> the verbosity level of logs.
> The value written to the file, should have bit 0 set to enable logging and
> bits 4-7 should contain the verbosity info.
>
> v2: Add a forceful flush, to collect left over logs, on disabling logging.
>      Useful for Validation.
>
> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_debugfs.c        | 32 ++++++++++++++++-
>   drivers/gpu/drm/i915/i915_guc_submission.c | 57 ++++++++++++++++++++++++++++++
>   drivers/gpu/drm/i915/intel_guc.h           |  1 +
>   3 files changed, 89 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 5e35565..3c9c7f7 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -2644,6 +2644,35 @@ static int i915_guc_log_dump(struct seq_file *m, void *data)
>   	return 0;
>   }
>
> +static int
> +i915_guc_log_control_set(void *data, u64 val)
> +{
> +	struct drm_device *dev = data;
> +	struct drm_i915_private *dev_priv = dev->dev_private;

to_i915 should be used.

> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&dev->struct_mutex);
> +	if (ret)
> +		return ret;
> +
> +	if (!i915.enable_guc_submission || !dev_priv->guc.log.obj) {

Wouldn't guc.log.obj be enough?

> +		ret = -EINVAL;
> +		goto end;
> +	}
> +
> +	intel_runtime_pm_get(dev_priv);
> +	ret = i915_guc_log_control(dev, val);
> +	intel_runtime_pm_put(dev_priv);
> +
> +end:
> +	mutex_unlock(&dev->struct_mutex);
> +	return ret;
> +}
> +
> +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
> +			NULL, i915_guc_log_control_set,
> +			"0x%08llx\n");

Does the readback still work with no get method?

> +
>   static int i915_edp_psr_status(struct seq_file *m, void *data)
>   {
>   	struct drm_info_node *node = m->private;
> @@ -5464,7 +5493,8 @@ static const struct i915_debugfs_files {
>   	{"i915_fbc_false_color", &i915_fbc_fc_fops},
>   	{"i915_dp_test_data", &i915_displayport_test_data_fops},
>   	{"i915_dp_test_type", &i915_displayport_test_type_fops},
> -	{"i915_dp_test_active", &i915_displayport_test_active_fops}
> +	{"i915_dp_test_active", &i915_displayport_test_active_fops},
> +	{"i915_guc_log_control", &i915_guc_log_control_fops}
>   };
>
>   void intel_display_crc_init(struct drm_device *dev)
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index 8cc31c6..2e3b723 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -193,6 +193,16 @@ static int host2guc_force_logbuffer_flush(struct intel_guc *guc)
>   	return host2guc_action(guc, data, 2);
>   }
>
> +static int host2guc_logging_control(struct intel_guc *guc, u32 control_val)
> +{
> +	u32 data[2];
> +
> +	data[0] = HOST2GUC_ACTION_UK_LOG_ENABLE_LOGGING;
> +	data[1] = control_val;
> +
> +	return host2guc_action(guc, data, 2);
> +}
> +
>   /*
>    * Initialise, update, or clear doorbell data shared with the GuC
>    *
> @@ -1455,3 +1465,50 @@ void i915_guc_register(struct drm_device *dev)
>   	guc_log_late_setup(dev);
>   	mutex_unlock(&dev->struct_mutex);
>   }
> +
> +int i915_guc_log_control(struct drm_device *dev, uint64_t control_val)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;

to_i915

Actually, function should take dev_priv if not even guc depending on the 
established convention in the file.

> +	union guc_log_control log_param;
> +	int ret;
> +
> +	log_param.logging_enabled = control_val & 0x1;
> +	log_param.verbosity = (control_val >> 4) & 0xF;
> +
> +	if (log_param.verbosity < GUC_LOG_VERBOSITY_MIN ||
> +	    log_param.verbosity > GUC_LOG_VERBOSITY_MAX)
> +		return -EINVAL;
> +
> +	/* This combination doesn't make sense & won't have any effect */
> +	if (!log_param.logging_enabled && (i915.guc_log_level < 0))
> +		return -EINVAL;

Hm, disabling while already disabled - why should that return an error? 
Might be annoying in scripts.

> +
> +	ret = host2guc_logging_control(&dev_priv->guc, log_param.value);
> +	if (ret < 0) {
> +		DRM_DEBUG_DRIVER("host2guc action failed\n");

Add ret to the log since it is easy?

> +		return ret;
> +	}
> +
> +	i915.guc_log_level = log_param.verbosity;
> +
> +	/* If log_level was set as -1 at boot time, then the relay channel file
> +	 * wouldn't have been created by now and interrupts also would not have
> +	 * been enabled.
> +	 */
> +	if (!dev_priv->guc.log.relay_chan) {
> +		ret = guc_log_late_setup(dev);
> +		if (!ret)
> +			gen9_enable_guc_interrupts(dev_priv);

Hm, look at the above and below, do we need to create the relay channel 
if logging_enabled == false ?

> +	} else if (!log_param.logging_enabled) {
> +		/* Once logging is disabled, GuC won't generate logs & send an
> +		 * interrupt. But there could be some data in the log buffer
> +		 * which is yet to be captured. So request GuC to update the log
> +		 * buffer state and send the flush interrupt so that Host can
> +		 * collect the left over logs also.
> +		 */
> +		flush_work(&dev_priv->guc.events_work);
> +		host2guc_force_logbuffer_flush(&dev_priv->guc);
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index ed773b5..d56bde6 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -178,5 +178,6 @@ void i915_guc_capture_logs(struct drm_device *dev);
>   void i915_guc_capture_logs_on_reset(struct drm_device *dev);
>   void i915_guc_register(struct drm_device *dev);
>   void i915_guc_unregister(struct drm_device *dev);
> +int i915_guc_log_control(struct drm_device *dev, uint64_t control_val);
>
>   #endif
>

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 07/17] drm/i915: Add a relay backed debugfs interface for capturing GuC logs
  2016-07-10 13:41 ` [PATCH 07/17] drm/i915: Add a relay backed debugfs interface for capturing GuC logs akash.goel
  2016-07-10 17:07   ` kbuild test robot
@ 2016-07-19 11:31   ` Tvrtko Ursulin
  2016-07-20  3:41     ` Goel, Akash
  1 sibling, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-19 11:31 UTC (permalink / raw)
  To: akash.goel, intel-gfx; +Cc: Sourab Gupta


On 10/07/16 14:41, akash.goel@intel.com wrote:
> From: Akash Goel <akash.goel@intel.com>
>
> Added a new debugfs interface '/sys/kernel/debug/dri/guc_log' for the
> User to capture GuC firmware logs. Availed relay framework to implement
> the interface, where Driver will have to just use a relay API to store
> snapshots of the GuC log buffer in the buffer managed by relay.
> The snapshot will be taken when GuC firmware sends a log buffer flush
> interrupt and up to four snaphots could be stored in the relay buffer.
> The relay buffer will be operated in a mode where it will overwrite the
> data not yet collected by User.
> Besides mmap method, through which User can directly access the relay
> buffer contents, relay also supports the 'poll' method. Through the 'poll'
> call on log file, User can come to know whenever a new snapshot of the
> log buffer is taken by Driver, so can run in tandem with the Driver and
> capture the logs in a sustained/streaming manner, without any loss of data.
>
> v2: Defer the creation of relay channel & associated debugfs file, as
>      debugfs setup is now done at the end of i915 Driver load. (Chris)
>
> v3:
> - Switch to no-overwrite mode for relay.
> - Fix the relay sub buffer switching sequence.
>
> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
> Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
> Signed-off-by: Akash Goel <akash.goel@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_drv.c            |   2 +
>   drivers/gpu/drm/i915/i915_guc_submission.c | 197 ++++++++++++++++++++++++++++-
>   drivers/gpu/drm/i915/intel_guc.h           |   3 +
>   3 files changed, 199 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 25c6b9b..43c9900 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -1177,6 +1177,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
>   	/* Reveal our presence to userspace */
>   	if (drm_dev_register(dev, 0) == 0) {
>   		i915_debugfs_register(dev_priv);
> +		i915_guc_register(dev);
>   		i915_setup_sysfs(dev);
>   	} else
>   		DRM_ERROR("Failed to register driver for userspace access!\n");
> @@ -1215,6 +1216,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
>   	intel_opregion_unregister(dev_priv);
>
>   	i915_teardown_sysfs(&dev_priv->drm);
> +	i915_guc_unregister(&dev_priv->drm);
>   	i915_debugfs_unregister(dev_priv);
>   	drm_dev_unregister(&dev_priv->drm);
>
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index d3dbb8e..9b436fa 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -23,6 +23,8 @@
>    */
>   #include <linux/firmware.h>
>   #include <linux/circ_buf.h>
> +#include <linux/debugfs.h>
> +#include <linux/relay.h>
>   #include "i915_drv.h"
>   #include "intel_guc.h"
>
> @@ -836,12 +838,33 @@ err:
>
>   static void guc_move_to_next_buf(struct intel_guc *guc)
>   {
> -	return;
> +	/* Make sure our updates are in the sub buffer are visible when
> +	 * Consumer sees a newly produced sub buffer.
> +	 */
> +	smp_wmb();
> +
> +	/* All data has been written, so now move the offset of sub buffer. */
> +	relay_reserve(guc->log.relay_chan, guc->log.obj->base.size);
> +
> +	/* Switch to the next sub buffer */
> +	relay_flush(guc->log.relay_chan);
>   }
>
>   static void* guc_get_write_buffer(struct intel_guc *guc)
>   {
> -	return NULL;
> +	/* FIXME: Cover the check under a lock ? */
> +	if (!guc->log.relay_chan)
> +		return NULL;
> +
> +	/* Just get the base address of a new sub buffer and copy data into it
> +	 * ourselves. NULL will be returned in no-overwrite mode, if all sub
> +	 * buffers are full. Could have used the relay_write() to indirectly
> +	 * copy the data, but that would have been bit convoluted, as we need to
> +	 * write to only certain locations inside a sub buffer which cannot be
> +	 * done without using relay_reserve() along with relay_write(). So its
> +	 * better to use relay_reserve() alone.
> +	 */
> +	return relay_reserve(guc->log.relay_chan, 0);
>   }
>
>   static void guc_read_update_log_buffer(struct drm_device *dev)
> @@ -906,6 +929,119 @@ static void guc_read_update_log_buffer(struct drm_device *dev)
>   		guc_move_to_next_buf(guc);
>   }
>
> +/*
> + * Sub buffer switch callback. Called whenever relay has to switch to a new
> + * sub buffer, relay stays on the same sub buffer if 0 is returned.
> + */
> +static int subbuf_start_callback(struct rchan_buf *buf,
> +				 void *subbuf,
> +				 void *prev_subbuf,
> +				 size_t prev_padding)
> +{
> +	/* Use no-overwrite mode by default, where relay will stop accepting
> +	 * new data if there are no empty sub buffers left.
> +	 * There is no strict synchronization enforced by relay between Consumer
> +	 * and Producer. In overwrite mode, there is a possibility of getting
> +	 * inconsistent/garbled data, the producer could be writing on to the
> +	 * same sub buffer from which Consumer is reading. This can't be avoided
> +	 * unless Consumer is fast enough and can always run in tandem with
> +	 * Producer.
> +	 */
> +	if (relay_buf_full(buf))
> +		return 0;
> +
> +	return 1;
> +}
> +
> +/*
> + * file_create() callback. Creates relay file in debugfs.
> + */
> +static struct dentry *create_buf_file_callback(const char *filename,
> +					       struct dentry *parent,
> +					       umode_t mode,
> +					       struct rchan_buf *buf,
> +					       int *is_global)
> +{
> +	/*
> +	 * Not using the channel filename passed as an argument, since for each
> +	 * channel relay appends the corresponding CPU number to the filename
> +	 * passed in relay_open(). This should be fine as relay just needs a
> +	 * dentry of the file associated with the channel buffer and that file's
> +	 * name need not be same as the filename passed as an argument.
> +	 */
> +	struct dentry *buf_file = debugfs_create_file("guc_log", mode,
> +			parent, buf, &relay_file_operations);
> +
> +	/* This to enable the use of a single buffer for the relay channel and
> +	 * correspondingly have a single file exposed to User, through which
> +	 * it can collect the logs inorder without any post-processing.
> +	 */
> +	*is_global = 1;
> +
> +	return buf_file;
> +}
> +
> +/*
> + * file_remove() default callback. Removes relay file in debugfs.
> + */
> +static int remove_buf_file_callback(struct dentry *dentry)
> +{
> +	debugfs_remove(dentry);
> +	return 0;
> +}
> +
> +/* relay channel callbacks */
> +static struct rchan_callbacks relay_callbacks = {
> +	.subbuf_start = subbuf_start_callback,
> +	.create_buf_file = create_buf_file_callback,
> +	.remove_buf_file = remove_buf_file_callback,
> +};
> +
> +static void guc_remove_log_relay_file(struct intel_guc *guc)
> +{
> +	if (guc->log.relay_chan)
> +		relay_close(guc->log.relay_chan);
> +}
> +
> +static int guc_create_log_relay_file(struct intel_guc *guc)
> +{
> +	struct drm_i915_private *dev_priv = guc_to_i915(guc);
> +	struct drm_device *dev = &dev_priv->drm;
> +	struct dentry *log_dir;
> +	struct rchan *guc_log_relay_chan;
> +	size_t n_subbufs, subbuf_size;
> +
> +	if (guc->log.relay_chan)
> +		return 0;
> +
> +	/* If /sys/kernel/debug/dri/0 location do not exist, then debugfs is
> +	 * not mounted and so can't create the relay file.
> +	 * The relay API seems to fit well with debugfs only.
> +	 */
> +	if (!dev->primary->debugfs_root)
> +		return -ENODEV;
> +
> +	/* For now create the log file in /sys/kernel/debug/dri/0 dir */
> +	log_dir = dev->primary->debugfs_root;
> +
> +	/* Keep the size of sub buffers same as shared log buffer */
> +	subbuf_size = guc->log.obj->base.size;
> +	/* TODO: Decide based on the User's input */
> +	n_subbufs = 4;
> +
> +	guc_log_relay_chan = relay_open("guc_log", log_dir,
> +			subbuf_size, n_subbufs, &relay_callbacks, dev);
> +
> +	if (!guc_log_relay_chan) {
> +		DRM_DEBUG_DRIVER("Couldn't create relay chan for guc logs\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* FIXME: Cover the update under a lock ? */
> +	guc->log.relay_chan = guc_log_relay_chan;
> +	return 0;
> +}
> +
>   static void guc_log_cleanup(struct drm_i915_private *dev_priv)
>   {
>   	struct intel_guc *guc = &dev_priv->guc;
> @@ -918,6 +1054,9 @@ static void guc_log_cleanup(struct drm_i915_private *dev_priv)
>   	/* First disable the flush interrupt */
>   	gen9_disable_guc_interrupts(dev_priv);
>
> +	guc_remove_log_relay_file(guc);
> +	guc->log.relay_chan = NULL;
> +
>   	if (guc->log.buf_addr)
>   		i915_gem_object_unpin_map(guc->log.obj);
>
> @@ -996,6 +1135,39 @@ static void guc_create_log(struct intel_guc *guc)
>   	guc->log.flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
>   }
>
> +static int guc_log_late_setup(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_guc *guc = &dev_priv->guc;
> +	int ret;
> +
> +	lockdep_assert_held(&dev->struct_mutex);
> +
> +	if (i915.guc_log_level < 0)
> +		return -EINVAL;
> +
> +	if (WARN_ON(guc->log.relay_chan))
> +		return -EINVAL;
> +
> +	/* If log_level was set as -1 at boot time, then vmalloc mapping would
> +	 * not have been created for the log buffer, so create one now.
> +	 */
> +	ret = guc_create_log_extras(guc);
> +	if (ret)
> +		goto err;
> +
> +	ret = guc_create_log_relay_file(guc);
> +	if (ret)
> +		goto err;
> +
> +	return 0;
> +err:
> +	guc_log_cleanup(dev_priv);
> +	/* logging will remain off */
> +	i915.guc_log_level = -1;
> +	return ret;
> +}
> +
>   static void init_guc_policies(struct guc_policies *policies)
>   {
>   	struct guc_policy *policy;
> @@ -1154,7 +1326,6 @@ void i915_guc_submission_fini(struct drm_i915_private *dev_priv)
>   	gem_release_guc_obj(dev_priv->guc.ads_obj);
>   	guc->ads_obj = NULL;
>
> -	guc_log_cleanup(dev_priv);
>   	gem_release_guc_obj(dev_priv->guc.log.obj);
>   	guc->log.obj = NULL;
>
> @@ -1232,3 +1403,23 @@ void i915_guc_capture_logs(struct drm_device *dev)
>   	host2guc_logbuffer_flush_complete(&dev_priv->guc);
>   	intel_runtime_pm_put(dev_priv);
>   }
> +
> +void i915_guc_unregister(struct drm_device *dev)
> +{
> +	if (!i915.enable_guc_submission)
> +		return;
> +
> +	mutex_lock(&dev->struct_mutex);
> +	guc_log_cleanup(dev->dev_private);
> +	mutex_unlock(&dev->struct_mutex);
> +}
> +
> +void i915_guc_register(struct drm_device *dev)
> +{
> +	if (!i915.enable_guc_submission)
> +		return;
> +
> +	mutex_lock(&dev->struct_mutex);
> +	guc_log_late_setup(dev);
> +	mutex_unlock(&dev->struct_mutex);
> +}
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index d4f0fae..a784cf8 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -127,6 +127,7 @@ struct intel_guc_log {
>   	struct drm_i915_gem_object *obj;
>   	struct workqueue_struct *wq;
>   	void *buf_addr;
> +	struct rchan *relay_chan;
>   };
>
>   struct intel_guc {
> @@ -174,5 +175,7 @@ int i915_guc_submit(struct drm_i915_gem_request *rq);
>   void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
>   void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
>   void i915_guc_capture_logs(struct drm_device *dev);
> +void i915_guc_register(struct drm_device *dev);
> +void i915_guc_unregister(struct drm_device *dev);
>
>   #endif
>

I am clueless about relayfs - do we have someone in house who could 
provide a better review of that?

In the mean time, you got TODO and FIXME's in the code so that needs to 
be resolved before a full review anyway. :)

Regards,

Tvrtko

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 06/17] drm/i915: Handle log buffer flush interrupt event from GuC
  2016-07-19 10:58   ` Tvrtko Ursulin
@ 2016-07-20  3:29     ` Goel, Akash
  0 siblings, 0 replies; 87+ messages in thread
From: Goel, Akash @ 2016-07-20  3:29 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/19/2016 4:28 PM, Tvrtko Ursulin wrote:
>
> On 10/07/16 14:41, akash.goel@intel.com wrote:
>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>
>> GuC ukernel sends an interrupt to Host to flush the log buffer
>> and expects Host to correspondingly update the read pointer
>> information in the state structure, once it has consumed the
>> log buffer contents by copying them to a file or buffer.
>> Even if Host couldn't copy the contents, it can still update the
>> read pointer so that logging state is not disturbed on GuC side.
>>
>> v2:
>> - Use a dedicated workqueue for handling flush interrupt. (Tvrtko)
>> - Reduce the overall log buffer copying time by skipping the copy of
>>    crash buffer area for regular cases and copying only the state
>>    structure data in first page.
>>
>> v3:
>>   - Create a vmalloc mapping of log buffer. (Chris)
>>   - Cover the flush acknowledgment under rpm get & put.(Chris)
>>   - Revert the change of skipping the copy of crash dump area, as
>>     not really needed, will be covered by subsequent patch.
>>
>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>> ---
>>   drivers/gpu/drm/i915/i915_drv.c            |  13 +++
>>   drivers/gpu/drm/i915/i915_guc_submission.c | 148
>> +++++++++++++++++++++++++++++
>>   drivers/gpu/drm/i915/i915_irq.c            |   5 +-
>>   drivers/gpu/drm/i915/intel_guc.h           |   3 +
>>   4 files changed, 167 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_drv.c
>> b/drivers/gpu/drm/i915/i915_drv.c
>> index b9a8117..25c6b9b 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.c
>> +++ b/drivers/gpu/drm/i915/i915_drv.c
>> @@ -791,8 +791,20 @@ static int i915_workqueues_init(struct
>> drm_i915_private *dev_priv)
>>       if (dev_priv->hotplug.dp_wq == NULL)
>>           goto out_free_wq;
>>
>> +    if (HAS_GUC_SCHED(dev_priv)) {
>> +        /* Need a dedicated wq to process log buffer flush interrupts
>> +         * from GuC without much delay so as to avoid any loss of logs.
>> +         */
>> +        dev_priv->guc.log.wq =
>> +            alloc_ordered_workqueue("i915-guc_log", 0);
>> +        if (dev_priv->guc.log.wq == NULL)
>> +            goto out_free_hotplug_dp_wq;
>> +    }
>> +
>>       return 0;
>>
>> +out_free_hotplug_dp_wq:
>> +    destroy_workqueue(dev_priv->hotplug.dp_wq);
>>   out_free_wq:
>>       destroy_workqueue(dev_priv->wq);
>>   out_err:
>> @@ -803,6 +815,7 @@ out_err:
>>
>>   static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv)
>>   {
>> +    destroy_workqueue(dev_priv->guc.log.wq);
>
> I am ignoring the wq parts of the patch since the next series may look
> different in this respect.
>
> However you may need to have wq destruction under the same HAS_GUC_SCHED
> condition as when you create it.

Thanks, will do.
Sorry, my bad.
>
>>       destroy_workqueue(dev_priv->hotplug.dp_wq);
>>       destroy_workqueue(dev_priv->wq);
>>   }
>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>> index 0bac172..d3dbb8e 100644
>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>> @@ -172,6 +172,15 @@ static int host2guc_sample_forcewake(struct
>> intel_guc *guc,
>>       return host2guc_action(guc, data, ARRAY_SIZE(data));
>>   }
>>
>> +static int host2guc_logbuffer_flush_complete(struct intel_guc *guc)
>> +{
>> +    u32 data[1];
>> +
>> +    data[0] = HOST2GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE;
>> +
>> +    return host2guc_action(guc, data, 1);
>> +}
>> +
>>   /*
>>    * Initialise, update, or clear doorbell data shared with the GuC
>>    *
>> @@ -825,6 +834,123 @@ err:
>>       return NULL;
>>   }
>>
>> +static void guc_move_to_next_buf(struct intel_guc *guc)
>> +{
>> +    return;
>> +}
>> +
>> +static void* guc_get_write_buffer(struct intel_guc *guc)
>> +{
>> +    return NULL;
>> +}
>> +
>> +static void guc_read_update_log_buffer(struct drm_device *dev)
>
> dev_priv should be passed in for driver internal functions.
>
>> +{
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>> +    struct intel_guc *guc = &dev_priv->guc;
>> +    struct guc_log_buffer_state *log_buffer_state,
>> *log_buffer_copy_state;
>> +    struct guc_log_buffer_state log_buffer_state_local;
>> +    void *src_data_ptr, *dst_data_ptr;
>> +    u32 i, buffer_size;
>> +
>> +    if (!guc->log.obj || !guc->log.buf_addr)
>> +        return;
>> +
>> +    log_buffer_state = src_data_ptr = guc->log.buf_addr;
>> +
>> +    /* Get the pointer to local buffer to store the logs */
>> +    dst_data_ptr = log_buffer_copy_state = guc_get_write_buffer(guc);
>
> This will return NULL so the loop below doesn't do anything much. I
> assume at this point in the patch series things are not wired up yet?
>
The below loop will still update the state structures, lying in the 
first page of GuC log buffer.
There is no local buffer yet to store the logs.

>> +
>> +    /* Actual logs are present from the 2nd page */
>> +    src_data_ptr += PAGE_SIZE;
>> +    dst_data_ptr += PAGE_SIZE;
>> +
>> +    for (i = 0; i < GUC_MAX_LOG_BUFFER; i++) {
>> +        log_buffer_state_local = *log_buffer_state;
>> +        buffer_size = log_buffer_state_local.size;
>> +
>> +        if (log_buffer_copy_state) {
>> +            /* First copy the state structure */
>> +            memcpy(log_buffer_copy_state, &log_buffer_state_local,
>> +                    sizeof(struct guc_log_buffer_state));
>
> For some reason I find it hard to grasp the meaning of the different
> variables with slightly different names:
>
> log_buffer_state
This is the pointer to GuC log buffer.

> log_buffer_copy_state,
This is the pointer to relay sub buffer, it may be NULL also if there 
are no empty sub buffers left to store the logs.

> log_buffer_state_local
This is the local copy of state structure on the stack.
	log_buffer_state_local = *log_buffer state;

This way we access the state structure fields in GuC log buffer
(uncached mapped) for read only once.
Actually there are multiple accesses required to state structures in GuC 
log buffer.
One access is required to copy the state structures from GuC log buffer 
to the relay sub buffer.
Then for some bookkeeping, we have to (re)access some of the individual 
fields inside the state structure (please refer the subsequent patch
drm/i915: Add stats for GuC log buffer flush interrupts).

>
> The _local one for example, it seems to be copied into from the GuC
> mapping and then copied again into log_buffer_copy_state.
>
> Why do you need two copies of it?
As mentioned above, log_buffer_copy_state could be NULL also.

> And why sometimes the code does a structure copy and sometimes explicit
> memcpy?
>
> I think even worse, when it does a structure copy:
>
> log_buffer_state_local = *log_buffer state;
>
> The log_buffer_state is a GEM object mapping. So in my mind it would be
> better the do the explicit memcpy there.
>
> And then this memcpy between the local copy and write buffer, that will
> be into the relay sub buffer?
>
Fine for consistency will use memcpy only to make a local copy of the 
state structures on stack.
	memcpy(&log_buffer_state_local, log_buffer_state,
			sizeof(struct guc_log_buffer_state));

> It seems to me there is no real need for log_buffer_state_local since
> the bottom of the loop still accesses it via the GEM obj mapping
> (log_buffer_state)
>
> So don't know, I find it all confusing.
Sorry for all the confusion, did it like this to make sure we access the 
state structures in GuC log buffer only once for reads.

>> +
>> +            /* The write pointer could have been updated by the GuC
>> +             * firmware, after sending the flush interrupt to Host,
>> +             * for consistency set the write pointer value to same
>> +             * value of sampled_write_ptr in the snapshot buffer.
>> +             */
>> +            log_buffer_copy_state->write_ptr =
>> +                log_buffer_copy_state->sampled_write_ptr;
>> +
>> +            log_buffer_copy_state++;
>> +
>> +            /* Now copy the actual logs */
>> +            memcpy(dst_data_ptr, src_data_ptr, buffer_size);
>
> Doesn't this copy (and overwrite) the same location
> log_buffer_copy_state points to? So the memcpy above and the write_ptr
> update (why?) are then overwritten by this memcpy because dst_data_ptr
> == log_buffer_copy_state at this point unless I am missing something.
>
log_buffer_copy_state initially points to the start of first page, 
whereas dst_data_ptr initially points to the start of 2nd page (where 
the actual logs are present).

I think you missed the following increment, right before the loop,
	/* Actual logs are present from the 2nd page */
	src_data_ptr += PAGE_SIZE;
	dst_data_ptr += PAGE_SIZE;

>> +
>> +            src_data_ptr += buffer_size;
>> +            dst_data_ptr += buffer_size;
>> +        }
>> +
>> +        /* FIXME: invalidate/flush for log buffer needed */
>> +
>> +        /* Update the read pointer in the shared log buffer */
>> +        log_buffer_state->read_ptr =
>> +            log_buffer_state_local.sampled_write_ptr;
>> +
>> +        /* Clear the 'flush to file' flag */
>> +        log_buffer_state->flush_to_file = 0;
>> +        log_buffer_state++;
>> +    }
>> +
>> +    if (log_buffer_copy_state)
>> +        guc_move_to_next_buf(guc);
>> +}
>> +
>> +static void guc_log_cleanup(struct drm_i915_private *dev_priv)
>> +{
>> +    struct intel_guc *guc = &dev_priv->guc;
>> +
>> +    lockdep_assert_held(&dev_priv->drm.struct_mutex);
>> +
>> +    if (i915.guc_log_level < 0)
>> +        return;
>> +
>> +    /* First disable the flush interrupt */
>> +    gen9_disable_guc_interrupts(dev_priv);
>> +
>> +    if (guc->log.buf_addr)
>> +        i915_gem_object_unpin_map(guc->log.obj);
>> +
>> +    guc->log.buf_addr = NULL;
>> +}
>> +
>> +static int guc_create_log_extras(struct intel_guc *guc)
>> +{
>> +    struct drm_i915_private *dev_priv = guc_to_i915(guc);
>> +    void *vaddr;
>> +    int ret;
>> +
>> +    lockdep_assert_held(&dev_priv->drm.struct_mutex);
>> +
>> +    /* Nothing to do */
>> +    if (i915.guc_log_level < 0)
>> +        return 0;
>> +
>> +    if (!guc->log.buf_addr) {
>> +        /* Create a vmalloc mapping of log buffer pages */
>> +        vaddr = i915_gem_object_pin_map(guc->log.obj);
>> +        if (IS_ERR(vaddr)) {
>> +            ret = PTR_ERR(vaddr);
>> +            DRM_ERROR("Couldn't map log buffer pages %d\n", ret);
>> +            return ret;
>> +        }
>> +
>> +        guc->log.buf_addr = vaddr;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>>   static void guc_create_log(struct intel_guc *guc)
>>   {
>>       struct drm_i915_private *dev_priv = guc_to_i915(guc);
>> @@ -851,6 +977,13 @@ static void guc_create_log(struct intel_guc *guc)
>>           }
>>
>>           guc->log.obj = obj;
>> +
>> +        if (guc_create_log_extras(guc)) {
>> +            gem_release_guc_obj(guc->log.obj);
>> +            guc->log.obj = NULL;
>> +            i915.guc_log_level = -1;
>> +            return;
>> +        }
>>       }
>>
>>       /* each allocated unit is a page */
>> @@ -1021,6 +1154,7 @@ void i915_guc_submission_fini(struct
>> drm_i915_private *dev_priv)
>>       gem_release_guc_obj(dev_priv->guc.ads_obj);
>>       guc->ads_obj = NULL;
>>
>> +    guc_log_cleanup(dev_priv);
>>       gem_release_guc_obj(dev_priv->guc.log.obj);
>>       guc->log.obj = NULL;
>>
>> @@ -1084,3 +1218,17 @@ int intel_guc_resume(struct drm_device *dev)
>>
>>       return host2guc_action(guc, data, ARRAY_SIZE(data));
>>   }
>> +
>> +void i915_guc_capture_logs(struct drm_device *dev)
>> +{
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>> +
>> +    guc_read_update_log_buffer(dev);
>> +
>> +    /* Generally device is expected to be active only at this
>> +     * time, so get/put should be really quick.
>> +     */
>> +    intel_runtime_pm_get(dev_priv);
>> +    host2guc_logbuffer_flush_complete(&dev_priv->guc);
>> +    intel_runtime_pm_put(dev_priv);
>> +}
>> diff --git a/drivers/gpu/drm/i915/i915_irq.c
>> b/drivers/gpu/drm/i915/i915_irq.c
>> index fd73c94..f90d3c6 100644
>> --- a/drivers/gpu/drm/i915/i915_irq.c
>> +++ b/drivers/gpu/drm/i915/i915_irq.c
>> @@ -1221,7 +1221,7 @@ static void gen9_guc2host_events_work(struct
>> work_struct *work)
>>       }
>>       spin_unlock_irq(&dev_priv->irq_lock);
>>
>> -    /* TODO: Handle the events for which GuC interrupted host */
>> +    i915_guc_capture_logs(&dev_priv->drm);
>>   }
>>
>>   /**
>> @@ -1707,7 +1707,8 @@ static void gen9_guc_irq_handler(struct
>> drm_i915_private *dev_priv, u32 gt_iir)
>>                       I915_READ(SOFT_SCRATCH(15)) & ~msg);
>>
>>                   /* Handle flush interrupt event in bottom half */
>> -                queue_work(dev_priv->wq, &dev_priv->guc.events_work);
>> +                queue_work(dev_priv->guc.log.wq,
>> +                        &dev_priv->guc.events_work);
>>               }
>>           }
>>           spin_unlock(&dev_priv->irq_lock);
>> diff --git a/drivers/gpu/drm/i915/intel_guc.h
>> b/drivers/gpu/drm/i915/intel_guc.h
>> index 2663b41..d4f0fae 100644
>> --- a/drivers/gpu/drm/i915/intel_guc.h
>> +++ b/drivers/gpu/drm/i915/intel_guc.h
>> @@ -125,6 +125,8 @@ struct intel_guc_fw {
>>   struct intel_guc_log {
>>       uint32_t flags;
>>       struct drm_i915_gem_object *obj;
>> +    struct workqueue_struct *wq;
>> +    void *buf_addr;
>>   };
>>
>>   struct intel_guc {
>> @@ -171,5 +173,6 @@ int i915_guc_wq_check_space(struct
>> drm_i915_gem_request *rq);
>>   int i915_guc_submit(struct drm_i915_gem_request *rq);
>>   void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
>>   void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
>> +void i915_guc_capture_logs(struct drm_device *dev);
>>
>>   #endif
>>
>
> Regards,
>
> Tvrtko
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 07/17] drm/i915: Add a relay backed debugfs interface for capturing GuC logs
  2016-07-19 11:31   ` Tvrtko Ursulin
@ 2016-07-20  3:41     ` Goel, Akash
  0 siblings, 0 replies; 87+ messages in thread
From: Goel, Akash @ 2016-07-20  3:41 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: Sourab Gupta, akash.goel



On 7/19/2016 5:01 PM, Tvrtko Ursulin wrote:
>
> On 10/07/16 14:41, akash.goel@intel.com wrote:
>> From: Akash Goel <akash.goel@intel.com>
>>
>> Added a new debugfs interface '/sys/kernel/debug/dri/guc_log' for the
>> User to capture GuC firmware logs. Availed relay framework to implement
>> the interface, where Driver will have to just use a relay API to store
>> snapshots of the GuC log buffer in the buffer managed by relay.
>> The snapshot will be taken when GuC firmware sends a log buffer flush
>> interrupt and up to four snaphots could be stored in the relay buffer.
>> The relay buffer will be operated in a mode where it will overwrite the
>> data not yet collected by User.
>> Besides mmap method, through which User can directly access the relay
>> buffer contents, relay also supports the 'poll' method. Through the
>> 'poll'
>> call on log file, User can come to know whenever a new snapshot of the
>> log buffer is taken by Driver, so can run in tandem with the Driver and
>> capture the logs in a sustained/streaming manner, without any loss of
>> data.
>>
>> v2: Defer the creation of relay channel & associated debugfs file, as
>>      debugfs setup is now done at the end of i915 Driver load. (Chris)
>>
>> v3:
>> - Switch to no-overwrite mode for relay.
>> - Fix the relay sub buffer switching sequence.
>>
>> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
>> Signed-off-by: Sourab Gupta <sourab.gupta@intel.com>
>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>> ---
>>   drivers/gpu/drm/i915/i915_drv.c            |   2 +
>>   drivers/gpu/drm/i915/i915_guc_submission.c | 197
>> ++++++++++++++++++++++++++++-
>>   drivers/gpu/drm/i915/intel_guc.h           |   3 +
>>   3 files changed, 199 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_drv.c
>> b/drivers/gpu/drm/i915/i915_drv.c
>> index 25c6b9b..43c9900 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.c
>> +++ b/drivers/gpu/drm/i915/i915_drv.c
>> @@ -1177,6 +1177,7 @@ static void i915_driver_register(struct
>> drm_i915_private *dev_priv)
>>       /* Reveal our presence to userspace */
>>       if (drm_dev_register(dev, 0) == 0) {
>>           i915_debugfs_register(dev_priv);
>> +        i915_guc_register(dev);
>>           i915_setup_sysfs(dev);
>>       } else
>>           DRM_ERROR("Failed to register driver for userspace access!\n");
>> @@ -1215,6 +1216,7 @@ static void i915_driver_unregister(struct
>> drm_i915_private *dev_priv)
>>       intel_opregion_unregister(dev_priv);
>>
>>       i915_teardown_sysfs(&dev_priv->drm);
>> +    i915_guc_unregister(&dev_priv->drm);
>>       i915_debugfs_unregister(dev_priv);
>>       drm_dev_unregister(&dev_priv->drm);
>>
>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>> index d3dbb8e..9b436fa 100644
>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>> @@ -23,6 +23,8 @@
>>    */
>>   #include <linux/firmware.h>
>>   #include <linux/circ_buf.h>
>> +#include <linux/debugfs.h>
>> +#include <linux/relay.h>
>>   #include "i915_drv.h"
>>   #include "intel_guc.h"
>>
>> @@ -836,12 +838,33 @@ err:
>>
>>   static void guc_move_to_next_buf(struct intel_guc *guc)
>>   {
>> -    return;
>> +    /* Make sure our updates are in the sub buffer are visible when
>> +     * Consumer sees a newly produced sub buffer.
>> +     */
>> +    smp_wmb();
>> +
>> +    /* All data has been written, so now move the offset of sub
>> buffer. */
>> +    relay_reserve(guc->log.relay_chan, guc->log.obj->base.size);
>> +
>> +    /* Switch to the next sub buffer */
>> +    relay_flush(guc->log.relay_chan);
>>   }
>>
>>   static void* guc_get_write_buffer(struct intel_guc *guc)
>>   {
>> -    return NULL;
>> +    /* FIXME: Cover the check under a lock ? */
>> +    if (!guc->log.relay_chan)
>> +        return NULL;
>> +
>> +    /* Just get the base address of a new sub buffer and copy data
>> into it
>> +     * ourselves. NULL will be returned in no-overwrite mode, if all sub
>> +     * buffers are full. Could have used the relay_write() to indirectly
>> +     * copy the data, but that would have been bit convoluted, as we
>> need to
>> +     * write to only certain locations inside a sub buffer which
>> cannot be
>> +     * done without using relay_reserve() along with relay_write().
>> So its
>> +     * better to use relay_reserve() alone.
>> +     */
>> +    return relay_reserve(guc->log.relay_chan, 0);
>>   }
>>
>>   static void guc_read_update_log_buffer(struct drm_device *dev)
>> @@ -906,6 +929,119 @@ static void guc_read_update_log_buffer(struct
>> drm_device *dev)
>>           guc_move_to_next_buf(guc);
>>   }
>>
>> +/*
>> + * Sub buffer switch callback. Called whenever relay has to switch to
>> a new
>> + * sub buffer, relay stays on the same sub buffer if 0 is returned.
>> + */
>> +static int subbuf_start_callback(struct rchan_buf *buf,
>> +                 void *subbuf,
>> +                 void *prev_subbuf,
>> +                 size_t prev_padding)
>> +{
>> +    /* Use no-overwrite mode by default, where relay will stop accepting
>> +     * new data if there are no empty sub buffers left.
>> +     * There is no strict synchronization enforced by relay between
>> Consumer
>> +     * and Producer. In overwrite mode, there is a possibility of
>> getting
>> +     * inconsistent/garbled data, the producer could be writing on to
>> the
>> +     * same sub buffer from which Consumer is reading. This can't be
>> avoided
>> +     * unless Consumer is fast enough and can always run in tandem with
>> +     * Producer.
>> +     */
>> +    if (relay_buf_full(buf))
>> +        return 0;
>> +
>> +    return 1;
>> +}
>> +
>> +/*
>> + * file_create() callback. Creates relay file in debugfs.
>> + */
>> +static struct dentry *create_buf_file_callback(const char *filename,
>> +                           struct dentry *parent,
>> +                           umode_t mode,
>> +                           struct rchan_buf *buf,
>> +                           int *is_global)
>> +{
>> +    /*
>> +     * Not using the channel filename passed as an argument, since
>> for each
>> +     * channel relay appends the corresponding CPU number to the
>> filename
>> +     * passed in relay_open(). This should be fine as relay just needs a
>> +     * dentry of the file associated with the channel buffer and that
>> file's
>> +     * name need not be same as the filename passed as an argument.
>> +     */
>> +    struct dentry *buf_file = debugfs_create_file("guc_log", mode,
>> +            parent, buf, &relay_file_operations);
>> +
>> +    /* This to enable the use of a single buffer for the relay
>> channel and
>> +     * correspondingly have a single file exposed to User, through which
>> +     * it can collect the logs inorder without any post-processing.
>> +     */
>> +    *is_global = 1;
>> +
>> +    return buf_file;
>> +}
>> +
>> +/*
>> + * file_remove() default callback. Removes relay file in debugfs.
>> + */
>> +static int remove_buf_file_callback(struct dentry *dentry)
>> +{
>> +    debugfs_remove(dentry);
>> +    return 0;
>> +}
>> +
>> +/* relay channel callbacks */
>> +static struct rchan_callbacks relay_callbacks = {
>> +    .subbuf_start = subbuf_start_callback,
>> +    .create_buf_file = create_buf_file_callback,
>> +    .remove_buf_file = remove_buf_file_callback,
>> +};
>> +
>> +static void guc_remove_log_relay_file(struct intel_guc *guc)
>> +{
>> +    if (guc->log.relay_chan)
>> +        relay_close(guc->log.relay_chan);
>> +}
>> +
>> +static int guc_create_log_relay_file(struct intel_guc *guc)
>> +{
>> +    struct drm_i915_private *dev_priv = guc_to_i915(guc);
>> +    struct drm_device *dev = &dev_priv->drm;
>> +    struct dentry *log_dir;
>> +    struct rchan *guc_log_relay_chan;
>> +    size_t n_subbufs, subbuf_size;
>> +
>> +    if (guc->log.relay_chan)
>> +        return 0;
>> +
>> +    /* If /sys/kernel/debug/dri/0 location do not exist, then debugfs is
>> +     * not mounted and so can't create the relay file.
>> +     * The relay API seems to fit well with debugfs only.
>> +     */
>> +    if (!dev->primary->debugfs_root)
>> +        return -ENODEV;
>> +
>> +    /* For now create the log file in /sys/kernel/debug/dri/0 dir */
>> +    log_dir = dev->primary->debugfs_root;
>> +
>> +    /* Keep the size of sub buffers same as shared log buffer */
>> +    subbuf_size = guc->log.obj->base.size;
>> +    /* TODO: Decide based on the User's input */
>> +    n_subbufs = 4;
>> +
>> +    guc_log_relay_chan = relay_open("guc_log", log_dir,
>> +            subbuf_size, n_subbufs, &relay_callbacks, dev);
>> +
>> +    if (!guc_log_relay_chan) {
>> +        DRM_DEBUG_DRIVER("Couldn't create relay chan for guc logs\n");
>> +        return -ENOMEM;
>> +    }
>> +
>> +    /* FIXME: Cover the update under a lock ? */
>> +    guc->log.relay_chan = guc_log_relay_chan;
>> +    return 0;
>> +}
>> +
>>   static void guc_log_cleanup(struct drm_i915_private *dev_priv)
>>   {
>>       struct intel_guc *guc = &dev_priv->guc;
>> @@ -918,6 +1054,9 @@ static void guc_log_cleanup(struct
>> drm_i915_private *dev_priv)
>>       /* First disable the flush interrupt */
>>       gen9_disable_guc_interrupts(dev_priv);
>>
>> +    guc_remove_log_relay_file(guc);
>> +    guc->log.relay_chan = NULL;
>> +
>>       if (guc->log.buf_addr)
>>           i915_gem_object_unpin_map(guc->log.obj);
>>
>> @@ -996,6 +1135,39 @@ static void guc_create_log(struct intel_guc *guc)
>>       guc->log.flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
>>   }
>>
>> +static int guc_log_late_setup(struct drm_device *dev)
>> +{
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>> +    struct intel_guc *guc = &dev_priv->guc;
>> +    int ret;
>> +
>> +    lockdep_assert_held(&dev->struct_mutex);
>> +
>> +    if (i915.guc_log_level < 0)
>> +        return -EINVAL;
>> +
>> +    if (WARN_ON(guc->log.relay_chan))
>> +        return -EINVAL;
>> +
>> +    /* If log_level was set as -1 at boot time, then vmalloc mapping
>> would
>> +     * not have been created for the log buffer, so create one now.
>> +     */
>> +    ret = guc_create_log_extras(guc);
>> +    if (ret)
>> +        goto err;
>> +
>> +    ret = guc_create_log_relay_file(guc);
>> +    if (ret)
>> +        goto err;
>> +
>> +    return 0;
>> +err:
>> +    guc_log_cleanup(dev_priv);
>> +    /* logging will remain off */
>> +    i915.guc_log_level = -1;
>> +    return ret;
>> +}
>> +
>>   static void init_guc_policies(struct guc_policies *policies)
>>   {
>>       struct guc_policy *policy;
>> @@ -1154,7 +1326,6 @@ void i915_guc_submission_fini(struct
>> drm_i915_private *dev_priv)
>>       gem_release_guc_obj(dev_priv->guc.ads_obj);
>>       guc->ads_obj = NULL;
>>
>> -    guc_log_cleanup(dev_priv);
>>       gem_release_guc_obj(dev_priv->guc.log.obj);
>>       guc->log.obj = NULL;
>>
>> @@ -1232,3 +1403,23 @@ void i915_guc_capture_logs(struct drm_device *dev)
>>       host2guc_logbuffer_flush_complete(&dev_priv->guc);
>>       intel_runtime_pm_put(dev_priv);
>>   }
>> +
>> +void i915_guc_unregister(struct drm_device *dev)
>> +{
>> +    if (!i915.enable_guc_submission)
>> +        return;
>> +
>> +    mutex_lock(&dev->struct_mutex);
>> +    guc_log_cleanup(dev->dev_private);
>> +    mutex_unlock(&dev->struct_mutex);
>> +}
>> +
>> +void i915_guc_register(struct drm_device *dev)
>> +{
>> +    if (!i915.enable_guc_submission)
>> +        return;
>> +
>> +    mutex_lock(&dev->struct_mutex);
>> +    guc_log_late_setup(dev);
>> +    mutex_unlock(&dev->struct_mutex);
>> +}
>> diff --git a/drivers/gpu/drm/i915/intel_guc.h
>> b/drivers/gpu/drm/i915/intel_guc.h
>> index d4f0fae..a784cf8 100644
>> --- a/drivers/gpu/drm/i915/intel_guc.h
>> +++ b/drivers/gpu/drm/i915/intel_guc.h
>> @@ -127,6 +127,7 @@ struct intel_guc_log {
>>       struct drm_i915_gem_object *obj;
>>       struct workqueue_struct *wq;
>>       void *buf_addr;
>> +    struct rchan *relay_chan;
>>   };
>>
>>   struct intel_guc {
>> @@ -174,5 +175,7 @@ int i915_guc_submit(struct drm_i915_gem_request *rq);
>>   void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
>>   void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
>>   void i915_guc_capture_logs(struct drm_device *dev);
>> +void i915_guc_register(struct drm_device *dev);
>> +void i915_guc_unregister(struct drm_device *dev);
>>
>>   #endif
>>
>
> I am clueless about relayfs - do we have someone in house who could
> provide a better review of that?
>
Probably a skim through 
https://www.kernel.org/doc/Documentation/filesystems/relay.txt & a bit 
of code walk-through would help, that's what I also had to do.

> In the mean time, you got TODO and FIXME's in the code so that needs to
> be resolved before a full review anyway. :)
>
TODO is already taken care in a subsequent patch.
About FIXME, I am not really sure and need suggestion/inputs on it.

Best regards
Akash

> Regards,
>
> Tvrtko
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 08/17] drm/i915: Forcefully flush GuC log buffer on reset
  2016-07-19 11:21     ` Chris Wilson
@ 2016-07-20  4:21       ` Goel, Akash
  2016-07-20  9:12         ` Chris Wilson
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-20  4:21 UTC (permalink / raw)
  To: Chris Wilson, Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/19/2016 4:51 PM, Chris Wilson wrote:
> On Tue, Jul 19, 2016 at 12:12:20PM +0100, Tvrtko Ursulin wrote:
>>
>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>
>>> If GuC logs are being captured, there should be a force log buffer flush
>>> action sent to GuC before proceeding with GPU reset and re-initializing
>>> GUC. Those logs would be useful to understand why the GPU reset was
>>> initiated.
>>>
>>> v2: Rebase.
>>>
>>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>> ---
>>>  drivers/gpu/drm/i915/i915_guc_submission.c | 32 ++++++++++++++++++++++++++++++
>>>  drivers/gpu/drm/i915/i915_irq.c            |  2 ++
>>>  drivers/gpu/drm/i915/intel_guc.h           |  1 +
>>>  3 files changed, 35 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> index 9b436fa..8cc31c6 100644
>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> @@ -183,6 +183,16 @@ static int host2guc_logbuffer_flush_complete(struct intel_guc *guc)
>>>  	return host2guc_action(guc, data, 1);
>>>  }
>>>
>>> +static int host2guc_force_logbuffer_flush(struct intel_guc *guc)
>>> +{
>>> +	u32 data[2];
>>> +
>>> +	data[0] = HOST2GUC_ACTION_FORCE_LOG_BUFFER_FLUSH;
>>> +	data[1] = 0;
>>> +
>>> +	return host2guc_action(guc, data, 2);
>>> +}
>>> +
>>>  /*
>>>   * Initialise, update, or clear doorbell data shared with the GuC
>>>   *
>>> @@ -1404,6 +1414,28 @@ void i915_guc_capture_logs(struct drm_device *dev)
>>>  	intel_runtime_pm_put(dev_priv);
>>>  }
>>>
>>> +void i915_guc_capture_logs_on_reset(struct drm_device *dev)
>>> +{
>>> +	struct drm_i915_private *dev_priv = dev->dev_private;
>>> +
>>> +	mutex_lock(&dev->struct_mutex);
>>
>> Not sure what are the repercussion of taking the mutex on the
>> i915_reset_and_wakeup and path (error capture, hangcheck, dont' know
>> this area well). Check with Chris and Mika I suppose (cc-ed)?
>

Took the struct_mutex, just to avoid a very remote possibility where
i915_guc_capture_logs_on_reset & debugfs function i915_guc_log_control 
executes concurrently.

> Flat out invalid to take struct_mutex on the error capture path, or any
> lock at all really (just in case of driver bugs). Consider it to be an
> atomic context that may preempt the driver at any point.

Actually I see that i915_reset() too takes the struct_mutex right at the 
beginning and I have plugged the call to 
i915_guc_capture_logs_on_reset() just before that.

Also it is being called after i915_error_wake_up(), so any client 
waiting on a request would have backed off and any new attempt by 
clients to lock the struct_mutex should see i915_reset_in_progress as
true.

Best regards
Akash
> -Chris
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-19 11:24   ` Tvrtko Ursulin
@ 2016-07-20  4:42     ` Goel, Akash
  2016-07-20  9:08       ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-20  4:42 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/19/2016 4:54 PM, Tvrtko Ursulin wrote:
>
> On 10/07/16 14:41, akash.goel@intel.com wrote:
>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>
>> This patch provides debugfs interface i915_guc_output_control for
>> on the fly enabling/disabling of logging in GuC firmware and controlling
>> the verbosity level of logs.
>> The value written to the file, should have bit 0 set to enable logging
>> and
>> bits 4-7 should contain the verbosity info.
>>
>> v2: Add a forceful flush, to collect left over logs, on disabling
>> logging.
>>      Useful for Validation.
>>
>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>> ---
>>   drivers/gpu/drm/i915/i915_debugfs.c        | 32 ++++++++++++++++-
>>   drivers/gpu/drm/i915/i915_guc_submission.c | 57
>> ++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/i915/intel_guc.h           |  1 +
>>   3 files changed, 89 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>> b/drivers/gpu/drm/i915/i915_debugfs.c
>> index 5e35565..3c9c7f7 100644
>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>> @@ -2644,6 +2644,35 @@ static int i915_guc_log_dump(struct seq_file
>> *m, void *data)
>>       return 0;
>>   }
>>
>> +static int
>> +i915_guc_log_control_set(void *data, u64 val)
>> +{
>> +    struct drm_device *dev = data;
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>
> to_i915 should be used.
Sorry for missing this, need to use this at other places also.

>
>> +    int ret;
>> +
>> +    ret = mutex_lock_interruptible(&dev->struct_mutex);
>> +    if (ret)
>> +        return ret;
>> +
>> +    if (!i915.enable_guc_submission || !dev_priv->guc.log.obj) {
>
> Wouldn't guc.log.obj be enough?

Actually failure in allocation of log buffer, at boot time, is not 
considered fatal and submission through GuC is still done.
So i915.enable_guc_submission could be 1 with guc.log.obj as NULL.

>
>> +        ret = -EINVAL;
>> +        goto end;
>> +    }
>> +
>> +    intel_runtime_pm_get(dev_priv);
>> +    ret = i915_guc_log_control(dev, val);
>> +    intel_runtime_pm_put(dev_priv);
>> +
>> +end:
>> +    mutex_unlock(&dev->struct_mutex);
>> +    return ret;
>> +}
>> +
>> +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
>> +            NULL, i915_guc_log_control_set,
>> +            "0x%08llx\n");
>
> Does the readback still work with no get method?

readback will give a 'Permission denied' error

>
>> +
>>   static int i915_edp_psr_status(struct seq_file *m, void *data)
>>   {
>>       struct drm_info_node *node = m->private;
>> @@ -5464,7 +5493,8 @@ static const struct i915_debugfs_files {
>>       {"i915_fbc_false_color", &i915_fbc_fc_fops},
>>       {"i915_dp_test_data", &i915_displayport_test_data_fops},
>>       {"i915_dp_test_type", &i915_displayport_test_type_fops},
>> -    {"i915_dp_test_active", &i915_displayport_test_active_fops}
>> +    {"i915_dp_test_active", &i915_displayport_test_active_fops},
>> +    {"i915_guc_log_control", &i915_guc_log_control_fops}
>>   };
>>
>>   void intel_display_crc_init(struct drm_device *dev)
>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>> index 8cc31c6..2e3b723 100644
>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>> @@ -193,6 +193,16 @@ static int host2guc_force_logbuffer_flush(struct
>> intel_guc *guc)
>>       return host2guc_action(guc, data, 2);
>>   }
>>
>> +static int host2guc_logging_control(struct intel_guc *guc, u32
>> control_val)
>> +{
>> +    u32 data[2];
>> +
>> +    data[0] = HOST2GUC_ACTION_UK_LOG_ENABLE_LOGGING;
>> +    data[1] = control_val;
>> +
>> +    return host2guc_action(guc, data, 2);
>> +}
>> +
>>   /*
>>    * Initialise, update, or clear doorbell data shared with the GuC
>>    *
>> @@ -1455,3 +1465,50 @@ void i915_guc_register(struct drm_device *dev)
>>       guc_log_late_setup(dev);
>>       mutex_unlock(&dev->struct_mutex);
>>   }
>> +
>> +int i915_guc_log_control(struct drm_device *dev, uint64_t control_val)
>> +{
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>
> to_i915
>
> Actually, function should take dev_priv if not even guc depending on the
> established convention in the file.
>
Ok for all the new logging related exported functions, will use dev_priv.

>> +    union guc_log_control log_param;
>> +    int ret;
>> +
>> +    log_param.logging_enabled = control_val & 0x1;
>> +    log_param.verbosity = (control_val >> 4) & 0xF;
>> +
>> +    if (log_param.verbosity < GUC_LOG_VERBOSITY_MIN ||
>> +        log_param.verbosity > GUC_LOG_VERBOSITY_MAX)
>> +        return -EINVAL;
>> +
>> +    /* This combination doesn't make sense & won't have any effect */
>> +    if (!log_param.logging_enabled && (i915.guc_log_level < 0))
>> +        return -EINVAL;
>
> Hm, disabling while already disabled - why should that return an error?
> Might be annoying in scripts.

Just to make the User aware. Ok will suppress this and return 0.
>
>> +
>> +    ret = host2guc_logging_control(&dev_priv->guc, log_param.value);
>> +    if (ret < 0) {
>> +        DRM_DEBUG_DRIVER("host2guc action failed\n");
>
> Add ret to the log since it is easy?
>
fine will do that.
>> +        return ret;
>> +    }
>> +
>> +    i915.guc_log_level = log_param.verbosity;
>> +
>> +    /* If log_level was set as -1 at boot time, then the relay
>> channel file
>> +     * wouldn't have been created by now and interrupts also would
>> not have
>> +     * been enabled.
>> +     */
>> +    if (!dev_priv->guc.log.relay_chan) {
>> +        ret = guc_log_late_setup(dev);
>> +        if (!ret)
>> +            gen9_enable_guc_interrupts(dev_priv);
>
> Hm, look at the above and below, do we need to create the relay channel
> if logging_enabled == false ?

Can come here only if logging is enabled, by the virtue of above check,
        /* This combination doesn't make sense & won't have any effect */
        if (!log_param.logging_enabled && (i915.guc_log_level < 0))
	   return -EINVAL;

When guc_log_level < 0, first write on this file by User should be to 
enable logging.

Best regards
Akash

>
>> +    } else if (!log_param.logging_enabled) {
>> +        /* Once logging is disabled, GuC won't generate logs & send an
>> +         * interrupt. But there could be some data in the log buffer
>> +         * which is yet to be captured. So request GuC to update the log
>> +         * buffer state and send the flush interrupt so that Host can
>> +         * collect the left over logs also.
>> +         */
>> +        flush_work(&dev_priv->guc.events_work);
>> +        host2guc_force_logbuffer_flush(&dev_priv->guc);
>> +    }
>> +
>> +    return ret;
>> +}
>> diff --git a/drivers/gpu/drm/i915/intel_guc.h
>> b/drivers/gpu/drm/i915/intel_guc.h
>> index ed773b5..d56bde6 100644
>> --- a/drivers/gpu/drm/i915/intel_guc.h
>> +++ b/drivers/gpu/drm/i915/intel_guc.h
>> @@ -178,5 +178,6 @@ void i915_guc_capture_logs(struct drm_device *dev);
>>   void i915_guc_capture_logs_on_reset(struct drm_device *dev);
>>   void i915_guc_register(struct drm_device *dev);
>>   void i915_guc_unregister(struct drm_device *dev);
>> +int i915_guc_log_control(struct drm_device *dev, uint64_t control_val);
>>
>>   #endif
>>
>
> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-20  4:42     ` Goel, Akash
@ 2016-07-20  9:08       ` Tvrtko Ursulin
  2016-07-20  9:32         ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-20  9:08 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 20/07/16 05:42, Goel, Akash wrote:
> On 7/19/2016 4:54 PM, Tvrtko Ursulin wrote:
>>
>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>
>>> This patch provides debugfs interface i915_guc_output_control for
>>> on the fly enabling/disabling of logging in GuC firmware and controlling
>>> the verbosity level of logs.
>>> The value written to the file, should have bit 0 set to enable logging
>>> and
>>> bits 4-7 should contain the verbosity info.
>>>
>>> v2: Add a forceful flush, to collect left over logs, on disabling
>>> logging.
>>>      Useful for Validation.
>>>
>>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>> ---
>>>   drivers/gpu/drm/i915/i915_debugfs.c        | 32 ++++++++++++++++-
>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 57
>>> ++++++++++++++++++++++++++++++
>>>   drivers/gpu/drm/i915/intel_guc.h           |  1 +
>>>   3 files changed, 89 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>>> b/drivers/gpu/drm/i915/i915_debugfs.c
>>> index 5e35565..3c9c7f7 100644
>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>> @@ -2644,6 +2644,35 @@ static int i915_guc_log_dump(struct seq_file
>>> *m, void *data)
>>>       return 0;
>>>   }
>>>
>>> +static int
>>> +i915_guc_log_control_set(void *data, u64 val)
>>> +{
>>> +    struct drm_device *dev = data;
>>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>>
>> to_i915 should be used.
> Sorry for missing this, need to use this at other places also.
>
>>
>>> +    int ret;
>>> +
>>> +    ret = mutex_lock_interruptible(&dev->struct_mutex);
>>> +    if (ret)
>>> +        return ret;
>>> +
>>> +    if (!i915.enable_guc_submission || !dev_priv->guc.log.obj) {
>>
>> Wouldn't guc.log.obj be enough?
>
> Actually failure in allocation of log buffer, at boot time, is not
> considered fatal and submission through GuC is still done.
> So i915.enable_guc_submission could be 1 with guc.log.obj as NULL.

If guc.log.obj is NULL it will return -EINVAL without trying to create 
it here. If you intended for this function to try and create the log 
object if not already present, via i915_guc_log_control, in that case 
the condition above should only be if (!i915.enable_guc_submisison), no?

>>
>>> +        ret = -EINVAL;
>>> +        goto end;
>>> +    }
>>> +
>>> +    intel_runtime_pm_get(dev_priv);
>>> +    ret = i915_guc_log_control(dev, val);
>>> +    intel_runtime_pm_put(dev_priv);
>>> +
>>> +end:
>>> +    mutex_unlock(&dev->struct_mutex);
>>> +    return ret;
>>> +}
>>> +
>>> +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
>>> +            NULL, i915_guc_log_control_set,
>>> +            "0x%08llx\n");
>>
>> Does the readback still work with no get method?
>
> readback will give a 'Permission denied' error

Is that what we want? I think it would be nice to allow read-back unless 
there is a specific reason why it shouldn't be allowed.

>>
>>> +
>>>   static int i915_edp_psr_status(struct seq_file *m, void *data)
>>>   {
>>>       struct drm_info_node *node = m->private;
>>> @@ -5464,7 +5493,8 @@ static const struct i915_debugfs_files {
>>>       {"i915_fbc_false_color", &i915_fbc_fc_fops},
>>>       {"i915_dp_test_data", &i915_displayport_test_data_fops},
>>>       {"i915_dp_test_type", &i915_displayport_test_type_fops},
>>> -    {"i915_dp_test_active", &i915_displayport_test_active_fops}
>>> +    {"i915_dp_test_active", &i915_displayport_test_active_fops},
>>> +    {"i915_guc_log_control", &i915_guc_log_control_fops}
>>>   };
>>>
>>>   void intel_display_crc_init(struct drm_device *dev)
>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> index 8cc31c6..2e3b723 100644
>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>> @@ -193,6 +193,16 @@ static int host2guc_force_logbuffer_flush(struct
>>> intel_guc *guc)
>>>       return host2guc_action(guc, data, 2);
>>>   }
>>>
>>> +static int host2guc_logging_control(struct intel_guc *guc, u32
>>> control_val)
>>> +{
>>> +    u32 data[2];
>>> +
>>> +    data[0] = HOST2GUC_ACTION_UK_LOG_ENABLE_LOGGING;
>>> +    data[1] = control_val;
>>> +
>>> +    return host2guc_action(guc, data, 2);
>>> +}
>>> +
>>>   /*
>>>    * Initialise, update, or clear doorbell data shared with the GuC
>>>    *
>>> @@ -1455,3 +1465,50 @@ void i915_guc_register(struct drm_device *dev)
>>>       guc_log_late_setup(dev);
>>>       mutex_unlock(&dev->struct_mutex);
>>>   }
>>> +
>>> +int i915_guc_log_control(struct drm_device *dev, uint64_t control_val)
>>> +{
>>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>>
>> to_i915
>>
>> Actually, function should take dev_priv if not even guc depending on the
>> established convention in the file.
>>
> Ok for all the new logging related exported functions, will use dev_priv.

Or intel_guc where applicable, please look in guc code to see what is 
mostly used. There is also guc_to_i915 helper or something.

>
>>> +    union guc_log_control log_param;
>>> +    int ret;
>>> +
>>> +    log_param.logging_enabled = control_val & 0x1;
>>> +    log_param.verbosity = (control_val >> 4) & 0xF;
>>> +
>>> +    if (log_param.verbosity < GUC_LOG_VERBOSITY_MIN ||
>>> +        log_param.verbosity > GUC_LOG_VERBOSITY_MAX)
>>> +        return -EINVAL;
>>> +
>>> +    /* This combination doesn't make sense & won't have any effect */
>>> +    if (!log_param.logging_enabled && (i915.guc_log_level < 0))
>>> +        return -EINVAL;
>>
>> Hm, disabling while already disabled - why should that return an error?
>> Might be annoying in scripts.
>
> Just to make the User aware. Ok will suppress this and return 0.

Good, because it would be really annoying since you don't implement 
readback as well. For example:

echo 0x0 > guc_logging_control

= -EINVAL

"What's wrong? What's the current status?"

cat guc_logging_control

= -EACESS (or whatever)

"What?!?"

:)

>>
>>> +
>>> +    ret = host2guc_logging_control(&dev_priv->guc, log_param.value);
>>> +    if (ret < 0) {
>>> +        DRM_DEBUG_DRIVER("host2guc action failed\n");
>>
>> Add ret to the log since it is easy?
>>
> fine will do that.
>>> +        return ret;
>>> +    }
>>> +
>>> +    i915.guc_log_level = log_param.verbosity;
>>> +
>>> +    /* If log_level was set as -1 at boot time, then the relay
>>> channel file
>>> +     * wouldn't have been created by now and interrupts also would
>>> not have
>>> +     * been enabled.
>>> +     */
>>> +    if (!dev_priv->guc.log.relay_chan) {
>>> +        ret = guc_log_late_setup(dev);
>>> +        if (!ret)
>>> +            gen9_enable_guc_interrupts(dev_priv);
>>
>> Hm, look at the above and below, do we need to create the relay channel
>> if logging_enabled == false ?
>
> Can come here only if logging is enabled, by the virtue of above check,
>         /* This combination doesn't make sense & won't have any effect */
>         if (!log_param.logging_enabled && (i915.guc_log_level < 0))
>         return -EINVAL;
>
> When guc_log_level < 0, first write on this file by User should be to
> enable logging.

Okay just make sure that the relay channel is not created on repeated 
disabling.

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 08/17] drm/i915: Forcefully flush GuC log buffer on reset
  2016-07-20  4:21       ` Goel, Akash
@ 2016-07-20  9:12         ` Chris Wilson
  2016-07-20  9:48           ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Chris Wilson @ 2016-07-20  9:12 UTC (permalink / raw)
  To: Goel, Akash; +Cc: intel-gfx

On Wed, Jul 20, 2016 at 09:51:45AM +0530, Goel, Akash wrote:
> 
> 
> On 7/19/2016 4:51 PM, Chris Wilson wrote:
> >On Tue, Jul 19, 2016 at 12:12:20PM +0100, Tvrtko Ursulin wrote:
> >>
> >>On 10/07/16 14:41, akash.goel@intel.com wrote:
> >>>From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> >>>
> >>>If GuC logs are being captured, there should be a force log buffer flush
> >>>action sent to GuC before proceeding with GPU reset and re-initializing
> >>>GUC. Those logs would be useful to understand why the GPU reset was
> >>>initiated.
> >>>
> >>>v2: Rebase.
> >>>
> >>>Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
> >>>Signed-off-by: Akash Goel <akash.goel@intel.com>
> >>>---
> >>> drivers/gpu/drm/i915/i915_guc_submission.c | 32 ++++++++++++++++++++++++++++++
> >>> drivers/gpu/drm/i915/i915_irq.c            |  2 ++
> >>> drivers/gpu/drm/i915/intel_guc.h           |  1 +
> >>> 3 files changed, 35 insertions(+)
> >>>
> >>>diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> >>>index 9b436fa..8cc31c6 100644
> >>>--- a/drivers/gpu/drm/i915/i915_guc_submission.c
> >>>+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> >>>@@ -183,6 +183,16 @@ static int host2guc_logbuffer_flush_complete(struct intel_guc *guc)
> >>> 	return host2guc_action(guc, data, 1);
> >>> }
> >>>
> >>>+static int host2guc_force_logbuffer_flush(struct intel_guc *guc)
> >>>+{
> >>>+	u32 data[2];
> >>>+
> >>>+	data[0] = HOST2GUC_ACTION_FORCE_LOG_BUFFER_FLUSH;
> >>>+	data[1] = 0;
> >>>+
> >>>+	return host2guc_action(guc, data, 2);
> >>>+}
> >>>+
> >>> /*
> >>>  * Initialise, update, or clear doorbell data shared with the GuC
> >>>  *
> >>>@@ -1404,6 +1414,28 @@ void i915_guc_capture_logs(struct drm_device *dev)
> >>> 	intel_runtime_pm_put(dev_priv);
> >>> }
> >>>
> >>>+void i915_guc_capture_logs_on_reset(struct drm_device *dev)
> >>>+{
> >>>+	struct drm_i915_private *dev_priv = dev->dev_private;
> >>>+
> >>>+	mutex_lock(&dev->struct_mutex);
> >>
> >>Not sure what are the repercussion of taking the mutex on the
> >>i915_reset_and_wakeup and path (error capture, hangcheck, dont' know
> >>this area well). Check with Chris and Mika I suppose (cc-ed)?
> >
> 
> Took the struct_mutex, just to avoid a very remote possibility where
> i915_guc_capture_logs_on_reset & debugfs function
> i915_guc_log_control executes concurrently.
> 
> >Flat out invalid to take struct_mutex on the error capture path, or any
> >lock at all really (just in case of driver bugs). Consider it to be an
> >atomic context that may preempt the driver at any point.
> 
> Actually I see that i915_reset() too takes the struct_mutex right at
> the beginning and I have plugged the call to
> i915_guc_capture_logs_on_reset() just before that.

Postmortem state is captured from i915_capture_error_state(), and as I
recall one of the raison d'etre for this facility was to include the guc
log in the error state.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-20  9:08       ` Tvrtko Ursulin
@ 2016-07-20  9:32         ` Goel, Akash
  2016-07-20  9:47           ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-20  9:32 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/20/2016 2:38 PM, Tvrtko Ursulin wrote:
>
> On 20/07/16 05:42, Goel, Akash wrote:
>> On 7/19/2016 4:54 PM, Tvrtko Ursulin wrote:
>>>
>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>>
>>>> This patch provides debugfs interface i915_guc_output_control for
>>>> on the fly enabling/disabling of logging in GuC firmware and
>>>> controlling
>>>> the verbosity level of logs.
>>>> The value written to the file, should have bit 0 set to enable logging
>>>> and
>>>> bits 4-7 should contain the verbosity info.
>>>>
>>>> v2: Add a forceful flush, to collect left over logs, on disabling
>>>> logging.
>>>>      Useful for Validation.
>>>>
>>>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>> ---
>>>>   drivers/gpu/drm/i915/i915_debugfs.c        | 32 ++++++++++++++++-
>>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 57
>>>> ++++++++++++++++++++++++++++++
>>>>   drivers/gpu/drm/i915/intel_guc.h           |  1 +
>>>>   3 files changed, 89 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>>>> b/drivers/gpu/drm/i915/i915_debugfs.c
>>>> index 5e35565..3c9c7f7 100644
>>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>>> @@ -2644,6 +2644,35 @@ static int i915_guc_log_dump(struct seq_file
>>>> *m, void *data)
>>>>       return 0;
>>>>   }
>>>>
>>>> +static int
>>>> +i915_guc_log_control_set(void *data, u64 val)
>>>> +{
>>>> +    struct drm_device *dev = data;
>>>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>>>
>>> to_i915 should be used.
>> Sorry for missing this, need to use this at other places also.
>>
>>>
>>>> +    int ret;
>>>> +
>>>> +    ret = mutex_lock_interruptible(&dev->struct_mutex);
>>>> +    if (ret)
>>>> +        return ret;
>>>> +
>>>> +    if (!i915.enable_guc_submission || !dev_priv->guc.log.obj) {
>>>
>>> Wouldn't guc.log.obj be enough?
>>
>> Actually failure in allocation of log buffer, at boot time, is not
>> considered fatal and submission through GuC is still done.
>> So i915.enable_guc_submission could be 1 with guc.log.obj as NULL.
>
> If guc.log.obj is NULL it will return -EINVAL without trying to create
> it here. If you intended for this function to try and create the log
> object if not already present, via i915_guc_log_control, in that case
> the condition above should only be if (!i915.enable_guc_submisison), no?
>
If guc.log.obj is found to be NULL, we consider logging can't be enabled 
at run time. Allocation of log buffer is supposed to done
at boot time only, otherwise GuC would have to be reset & firmware to be 
reloaded to pass the log buffer address at run time, which is probably 
not desirable. That's why in the first patch decoupled the allocation of 
log buffer from log_level value.

>>>
>>>> +        ret = -EINVAL;
>>>> +        goto end;
>>>> +    }
>>>> +
>>>> +    intel_runtime_pm_get(dev_priv);
>>>> +    ret = i915_guc_log_control(dev, val);
>>>> +    intel_runtime_pm_put(dev_priv);
>>>> +
>>>> +end:
>>>> +    mutex_unlock(&dev->struct_mutex);
>>>> +    return ret;
>>>> +}
>>>> +
>>>> +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
>>>> +            NULL, i915_guc_log_control_set,
>>>> +            "0x%08llx\n");
>>>
>>> Does the readback still work with no get method?
>>
>> readback will give a 'Permission denied' error
>
> Is that what we want? I think it would be nice to allow read-back unless
> there is a specific reason why it shouldn't be allowed.
>

Ok can implement a dummy read back function but what should be 
shown/returned on read.

Should I show/return the guc_log_level value (which is also available 
from /sys/module/i915/parameters/) ?


>>>
>>>> +
>>>>   static int i915_edp_psr_status(struct seq_file *m, void *data)
>>>>   {
>>>>       struct drm_info_node *node = m->private;
>>>> @@ -5464,7 +5493,8 @@ static const struct i915_debugfs_files {
>>>>       {"i915_fbc_false_color", &i915_fbc_fc_fops},
>>>>       {"i915_dp_test_data", &i915_displayport_test_data_fops},
>>>>       {"i915_dp_test_type", &i915_displayport_test_type_fops},
>>>> -    {"i915_dp_test_active", &i915_displayport_test_active_fops}
>>>> +    {"i915_dp_test_active", &i915_displayport_test_active_fops},
>>>> +    {"i915_guc_log_control", &i915_guc_log_control_fops}
>>>>   };
>>>>
>>>>   void intel_display_crc_init(struct drm_device *dev)
>>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> index 8cc31c6..2e3b723 100644
>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>> @@ -193,6 +193,16 @@ static int host2guc_force_logbuffer_flush(struct
>>>> intel_guc *guc)
>>>>       return host2guc_action(guc, data, 2);
>>>>   }
>>>>
>>>> +static int host2guc_logging_control(struct intel_guc *guc, u32
>>>> control_val)
>>>> +{
>>>> +    u32 data[2];
>>>> +
>>>> +    data[0] = HOST2GUC_ACTION_UK_LOG_ENABLE_LOGGING;
>>>> +    data[1] = control_val;
>>>> +
>>>> +    return host2guc_action(guc, data, 2);
>>>> +}
>>>> +
>>>>   /*
>>>>    * Initialise, update, or clear doorbell data shared with the GuC
>>>>    *
>>>> @@ -1455,3 +1465,50 @@ void i915_guc_register(struct drm_device *dev)
>>>>       guc_log_late_setup(dev);
>>>>       mutex_unlock(&dev->struct_mutex);
>>>>   }
>>>> +
>>>> +int i915_guc_log_control(struct drm_device *dev, uint64_t control_val)
>>>> +{
>>>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>>>
>>> to_i915
>>>
>>> Actually, function should take dev_priv if not even guc depending on the
>>> established convention in the file.
>>>
>> Ok for all the new logging related exported functions, will use dev_priv.
>
> Or intel_guc where applicable, please look in guc code to see what is
> mostly used. There is also guc_to_i915 helper or something.
>
for functions exported from i915_guc_submission.c file, dev_priv has 
been used.

>>
>>>> +    union guc_log_control log_param;
>>>> +    int ret;
>>>> +
>>>> +    log_param.logging_enabled = control_val & 0x1;
>>>> +    log_param.verbosity = (control_val >> 4) & 0xF;
>>>> +
>>>> +    if (log_param.verbosity < GUC_LOG_VERBOSITY_MIN ||
>>>> +        log_param.verbosity > GUC_LOG_VERBOSITY_MAX)
>>>> +        return -EINVAL;
>>>> +
>>>> +    /* This combination doesn't make sense & won't have any effect */
>>>> +    if (!log_param.logging_enabled && (i915.guc_log_level < 0))
>>>> +        return -EINVAL;
>>>
>>> Hm, disabling while already disabled - why should that return an error?
>>> Might be annoying in scripts.
>>
>> Just to make the User aware. Ok will suppress this and return 0.
>
> Good, because it would be really annoying since you don't implement
> readback as well. For example:
>
> echo 0x0 > guc_logging_control
>
> = -EINVAL
>
> "What's wrong? What's the current status?"
>
> cat guc_logging_control
>
> = -EACESS (or whatever)
>
> "What?!?"
>
> :)
>
>>>
>>>> +
>>>> +    ret = host2guc_logging_control(&dev_priv->guc, log_param.value);
>>>> +    if (ret < 0) {
>>>> +        DRM_DEBUG_DRIVER("host2guc action failed\n");
>>>
>>> Add ret to the log since it is easy?
>>>
>> fine will do that.
>>>> +        return ret;
>>>> +    }
>>>> +
>>>> +    i915.guc_log_level = log_param.verbosity;
>>>> +
>>>> +    /* If log_level was set as -1 at boot time, then the relay
>>>> channel file
>>>> +     * wouldn't have been created by now and interrupts also would
>>>> not have
>>>> +     * been enabled.
>>>> +     */
>>>> +    if (!dev_priv->guc.log.relay_chan) {
>>>> +        ret = guc_log_late_setup(dev);
>>>> +        if (!ret)
>>>> +            gen9_enable_guc_interrupts(dev_priv);
>>>
>>> Hm, look at the above and below, do we need to create the relay channel
>>> if logging_enabled == false ?
>>
>> Can come here only if logging is enabled, by the virtue of above check,
>>         /* This combination doesn't make sense & won't have any effect */
>>         if (!log_param.logging_enabled && (i915.guc_log_level < 0))
>>         return -EINVAL;
>>
>> When guc_log_level < 0, first write on this file by User should be to
>> enable logging.
>
> Okay just make sure that the relay channel is not created on repeated
> disabling.
>
Yes channel will be created only once, when logging is enabled for first 
time.

Best regards
Akash
> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-20  9:32         ` Goel, Akash
@ 2016-07-20  9:47           ` Tvrtko Ursulin
  2016-07-20 10:12             ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-20  9:47 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 20/07/16 10:32, Goel, Akash wrote:
>
>
> On 7/20/2016 2:38 PM, Tvrtko Ursulin wrote:
>>
>> On 20/07/16 05:42, Goel, Akash wrote:
>>> On 7/19/2016 4:54 PM, Tvrtko Ursulin wrote:
>>>>
>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>>>
>>>>> This patch provides debugfs interface i915_guc_output_control for
>>>>> on the fly enabling/disabling of logging in GuC firmware and
>>>>> controlling
>>>>> the verbosity level of logs.
>>>>> The value written to the file, should have bit 0 set to enable logging
>>>>> and
>>>>> bits 4-7 should contain the verbosity info.
>>>>>
>>>>> v2: Add a forceful flush, to collect left over logs, on disabling
>>>>> logging.
>>>>>      Useful for Validation.
>>>>>
>>>>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>> ---
>>>>>   drivers/gpu/drm/i915/i915_debugfs.c        | 32 ++++++++++++++++-
>>>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 57
>>>>> ++++++++++++++++++++++++++++++
>>>>>   drivers/gpu/drm/i915/intel_guc.h           |  1 +
>>>>>   3 files changed, 89 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>>>>> b/drivers/gpu/drm/i915/i915_debugfs.c
>>>>> index 5e35565..3c9c7f7 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>>>> @@ -2644,6 +2644,35 @@ static int i915_guc_log_dump(struct seq_file
>>>>> *m, void *data)
>>>>>       return 0;
>>>>>   }
>>>>>
>>>>> +static int
>>>>> +i915_guc_log_control_set(void *data, u64 val)
>>>>> +{
>>>>> +    struct drm_device *dev = data;
>>>>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>>>>
>>>> to_i915 should be used.
>>> Sorry for missing this, need to use this at other places also.
>>>
>>>>
>>>>> +    int ret;
>>>>> +
>>>>> +    ret = mutex_lock_interruptible(&dev->struct_mutex);
>>>>> +    if (ret)
>>>>> +        return ret;
>>>>> +
>>>>> +    if (!i915.enable_guc_submission || !dev_priv->guc.log.obj) {
>>>>
>>>> Wouldn't guc.log.obj be enough?
>>>
>>> Actually failure in allocation of log buffer, at boot time, is not
>>> considered fatal and submission through GuC is still done.
>>> So i915.enable_guc_submission could be 1 with guc.log.obj as NULL.
>>
>> If guc.log.obj is NULL it will return -EINVAL without trying to create
>> it here. If you intended for this function to try and create the log
>> object if not already present, via i915_guc_log_control, in that case
>> the condition above should only be if (!i915.enable_guc_submisison), no?
>>
> If guc.log.obj is found to be NULL, we consider logging can't be enabled
> at run time. Allocation of log buffer is supposed to done
> at boot time only, otherwise GuC would have to be reset & firmware to be
> reloaded to pass the log buffer address at run time, which is probably
> not desirable. That's why in the first patch decoupled the allocation of
> log buffer from log_level value.

Okay so why then the check above shouldn't just be;

	if (!dev_priv->guc.log.obj)

as I originally suggested?

>
>>>>
>>>>> +        ret = -EINVAL;
>>>>> +        goto end;
>>>>> +    }
>>>>> +
>>>>> +    intel_runtime_pm_get(dev_priv);
>>>>> +    ret = i915_guc_log_control(dev, val);
>>>>> +    intel_runtime_pm_put(dev_priv);
>>>>> +
>>>>> +end:
>>>>> +    mutex_unlock(&dev->struct_mutex);
>>>>> +    return ret;
>>>>> +}
>>>>> +
>>>>> +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
>>>>> +            NULL, i915_guc_log_control_set,
>>>>> +            "0x%08llx\n");
>>>>
>>>> Does the readback still work with no get method?
>>>
>>> readback will give a 'Permission denied' error
>>
>> Is that what we want? I think it would be nice to allow read-back unless
>> there is a specific reason why it shouldn't be allowed.
>>
>
> Ok can implement a dummy read back function but what should be
> shown/returned on read.
>
> Should I show/return the guc_log_level value (which is also available
> from /sys/module/i915/parameters/) ?

I would return the same value that was written in. Is the problem that 
it is not stored anywhere? Maybe reconstruct it from
i915.guc_log_level ?

Although it is not ideal that we got two formats for the same thing. 
Thinking about that, why not use the same format in debugfs as for the 
module param?

And I forgot, i915.guc_log_level == 0 is logging enabled with minimum 
verbosity?

Is it too late to change that? :)

Regards,

Tvrtko

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 08/17] drm/i915: Forcefully flush GuC log buffer on reset
  2016-07-20  9:12         ` Chris Wilson
@ 2016-07-20  9:48           ` Goel, Akash
  0 siblings, 0 replies; 87+ messages in thread
From: Goel, Akash @ 2016-07-20  9:48 UTC (permalink / raw)
  To: Chris Wilson, Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/20/2016 2:42 PM, Chris Wilson wrote:
> On Wed, Jul 20, 2016 at 09:51:45AM +0530, Goel, Akash wrote:
>>
>>
>> On 7/19/2016 4:51 PM, Chris Wilson wrote:
>>> On Tue, Jul 19, 2016 at 12:12:20PM +0100, Tvrtko Ursulin wrote:
>>>>
>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>>>
>>>>> If GuC logs are being captured, there should be a force log buffer flush
>>>>> action sent to GuC before proceeding with GPU reset and re-initializing
>>>>> GUC. Those logs would be useful to understand why the GPU reset was
>>>>> initiated.
>>>>>
>>>>> v2: Rebase.
>>>>>
>>>>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>> ---
>>>>> drivers/gpu/drm/i915/i915_guc_submission.c | 32 ++++++++++++++++++++++++++++++
>>>>> drivers/gpu/drm/i915/i915_irq.c            |  2 ++
>>>>> drivers/gpu/drm/i915/intel_guc.h           |  1 +
>>>>> 3 files changed, 35 insertions(+)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> index 9b436fa..8cc31c6 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
>>>>> @@ -183,6 +183,16 @@ static int host2guc_logbuffer_flush_complete(struct intel_guc *guc)
>>>>> 	return host2guc_action(guc, data, 1);
>>>>> }
>>>>>
>>>>> +static int host2guc_force_logbuffer_flush(struct intel_guc *guc)
>>>>> +{
>>>>> +	u32 data[2];
>>>>> +
>>>>> +	data[0] = HOST2GUC_ACTION_FORCE_LOG_BUFFER_FLUSH;
>>>>> +	data[1] = 0;
>>>>> +
>>>>> +	return host2guc_action(guc, data, 2);
>>>>> +}
>>>>> +
>>>>> /*
>>>>>  * Initialise, update, or clear doorbell data shared with the GuC
>>>>>  *
>>>>> @@ -1404,6 +1414,28 @@ void i915_guc_capture_logs(struct drm_device *dev)
>>>>> 	intel_runtime_pm_put(dev_priv);
>>>>> }
>>>>>
>>>>> +void i915_guc_capture_logs_on_reset(struct drm_device *dev)
>>>>> +{
>>>>> +	struct drm_i915_private *dev_priv = dev->dev_private;
>>>>> +
>>>>> +	mutex_lock(&dev->struct_mutex);
>>>>
>>>> Not sure what are the repercussion of taking the mutex on the
>>>> i915_reset_and_wakeup and path (error capture, hangcheck, dont' know
>>>> this area well). Check with Chris and Mika I suppose (cc-ed)?
>>>
>>
>> Took the struct_mutex, just to avoid a very remote possibility where
>> i915_guc_capture_logs_on_reset & debugfs function
>> i915_guc_log_control executes concurrently.
>>
>>> Flat out invalid to take struct_mutex on the error capture path, or any
>>> lock at all really (just in case of driver bugs). Consider it to be an
>>> atomic context that may preempt the driver at any point.
>>
>> Actually I see that i915_reset() too takes the struct_mutex right at
>> the beginning and I have plugged the call to
>> i915_guc_capture_logs_on_reset() just before that.
>
> Postmortem state is captured from i915_capture_error_state(), and as I
> recall one of the raison d'etre for this facility was to include the guc
> log in the error state.

Sorry I missed augmenting the error state with guc firmware logs.
For that also a prior flush will be needed, will do the flush without 
acquiring the struct_mutex.

Best regards
Akash

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-20  9:47           ` Tvrtko Ursulin
@ 2016-07-20 10:12             ` Goel, Akash
  2016-07-20 10:40               ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-20 10:12 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/20/2016 3:17 PM, Tvrtko Ursulin wrote:
>
> On 20/07/16 10:32, Goel, Akash wrote:
>>
>>
>> On 7/20/2016 2:38 PM, Tvrtko Ursulin wrote:
>>>
>>> On 20/07/16 05:42, Goel, Akash wrote:
>>>> On 7/19/2016 4:54 PM, Tvrtko Ursulin wrote:
>>>>>
>>>>> On 10/07/16 14:41, akash.goel@intel.com wrote:
>>>>>> From: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>>>>
>>>>>> This patch provides debugfs interface i915_guc_output_control for
>>>>>> on the fly enabling/disabling of logging in GuC firmware and
>>>>>> controlling
>>>>>> the verbosity level of logs.
>>>>>> The value written to the file, should have bit 0 set to enable
>>>>>> logging
>>>>>> and
>>>>>> bits 4-7 should contain the verbosity info.
>>>>>>
>>>>>> v2: Add a forceful flush, to collect left over logs, on disabling
>>>>>> logging.
>>>>>>      Useful for Validation.
>>>>>>
>>>>>> Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com>
>>>>>> Signed-off-by: Akash Goel <akash.goel@intel.com>
>>>>>> ---
>>>>>>   drivers/gpu/drm/i915/i915_debugfs.c        | 32 ++++++++++++++++-
>>>>>>   drivers/gpu/drm/i915/i915_guc_submission.c | 57
>>>>>> ++++++++++++++++++++++++++++++
>>>>>>   drivers/gpu/drm/i915/intel_guc.h           |  1 +
>>>>>>   3 files changed, 89 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> b/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> index 5e35565..3c9c7f7 100644
>>>>>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>>>>> @@ -2644,6 +2644,35 @@ static int i915_guc_log_dump(struct seq_file
>>>>>> *m, void *data)
>>>>>>       return 0;
>>>>>>   }
>>>>>>
>>>>>> +static int
>>>>>> +i915_guc_log_control_set(void *data, u64 val)
>>>>>> +{
>>>>>> +    struct drm_device *dev = data;
>>>>>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>>>>>
>>>>> to_i915 should be used.
>>>> Sorry for missing this, need to use this at other places also.
>>>>
>>>>>
>>>>>> +    int ret;
>>>>>> +
>>>>>> +    ret = mutex_lock_interruptible(&dev->struct_mutex);
>>>>>> +    if (ret)
>>>>>> +        return ret;
>>>>>> +
>>>>>> +    if (!i915.enable_guc_submission || !dev_priv->guc.log.obj) {
>>>>>
>>>>> Wouldn't guc.log.obj be enough?
>>>>
>>>> Actually failure in allocation of log buffer, at boot time, is not
>>>> considered fatal and submission through GuC is still done.
>>>> So i915.enable_guc_submission could be 1 with guc.log.obj as NULL.
>>>
>>> If guc.log.obj is NULL it will return -EINVAL without trying to create
>>> it here. If you intended for this function to try and create the log
>>> object if not already present, via i915_guc_log_control, in that case
>>> the condition above should only be if (!i915.enable_guc_submisison), no?
>>>
>> If guc.log.obj is found to be NULL, we consider logging can't be enabled
>> at run time. Allocation of log buffer is supposed to done
>> at boot time only, otherwise GuC would have to be reset & firmware to be
>> reloaded to pass the log buffer address at run time, which is probably
>> not desirable. That's why in the first patch decoupled the allocation of
>> log buffer from log_level value.
>
> Okay so why then the check above shouldn't just be;
>
>     if (!dev_priv->guc.log.obj)
>
> as I originally suggested?

Right, so sorry got confused, I misread & interpreted that you are 
suggesting to have !i915.enable_guc_submission check instead.

(!dev_priv->guc.log.obj) check should suffice.

>
>>
>>>>>
>>>>>> +        ret = -EINVAL;
>>>>>> +        goto end;
>>>>>> +    }
>>>>>> +
>>>>>> +    intel_runtime_pm_get(dev_priv);
>>>>>> +    ret = i915_guc_log_control(dev, val);
>>>>>> +    intel_runtime_pm_put(dev_priv);
>>>>>> +
>>>>>> +end:
>>>>>> +    mutex_unlock(&dev->struct_mutex);
>>>>>> +    return ret;
>>>>>> +}
>>>>>> +
>>>>>> +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
>>>>>> +            NULL, i915_guc_log_control_set,
>>>>>> +            "0x%08llx\n");
>>>>>
>>>>> Does the readback still work with no get method?
>>>>
>>>> readback will give a 'Permission denied' error
>>>
>>> Is that what we want? I think it would be nice to allow read-back unless
>>> there is a specific reason why it shouldn't be allowed.
>>>
>>
>> Ok can implement a dummy read back function but what should be
>> shown/returned on read.
>>
>> Should I show/return the guc_log_level value (which is also available
>> from /sys/module/i915/parameters/) ?
>
> I would return the same value that was written in. Is the problem that
> it is not stored anywhere? Maybe reconstruct it from
> i915.guc_log_level ?
>

The verbosity value will be same as guc_log_level. But whether logging 
on GuC side is currently enabled or disabled can't be inferred (it could 
have been disabled at run time).
So will have to store the exact value written by User.

> Although it is not ideal that we got two formats for the same thing.
> Thinking about that, why not use the same format in debugfs as for the
> module param?
>
> And I forgot, i915.guc_log_level == 0 is logging enabled with minimum
> verbosity?
>
i915.guc_log_level == 0 just indicates the minimum verbosity. But 
logging could still be disabled on GuC side.

For example, Driver boots with 'i915.guc_log_level = 0' so logging is 
enabled, later User disables the logging by echoing 0x0 on the 
guc_log_control debugfs file.

Best regards
Akash

> Is it too late to change that? :)
>
> Regards,
>
> Tvrtko
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-20 10:12             ` Goel, Akash
@ 2016-07-20 10:40               ` Tvrtko Ursulin
  2016-07-20 11:29                 ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-20 10:40 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 20/07/16 11:12, Goel, Akash wrote:
> On 7/20/2016 3:17 PM, Tvrtko Ursulin wrote:
>>>>>>> +        ret = -EINVAL;
>>>>>>> +        goto end;
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    intel_runtime_pm_get(dev_priv);
>>>>>>> +    ret = i915_guc_log_control(dev, val);
>>>>>>> +    intel_runtime_pm_put(dev_priv);
>>>>>>> +
>>>>>>> +end:
>>>>>>> +    mutex_unlock(&dev->struct_mutex);
>>>>>>> +    return ret;
>>>>>>> +}
>>>>>>> +
>>>>>>> +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
>>>>>>> +            NULL, i915_guc_log_control_set,
>>>>>>> +            "0x%08llx\n");
>>>>>>
>>>>>> Does the readback still work with no get method?
>>>>>
>>>>> readback will give a 'Permission denied' error
>>>>
>>>> Is that what we want? I think it would be nice to allow read-back
>>>> unless
>>>> there is a specific reason why it shouldn't be allowed.
>>>>
>>>
>>> Ok can implement a dummy read back function but what should be
>>> shown/returned on read.
>>>
>>> Should I show/return the guc_log_level value (which is also available
>>> from /sys/module/i915/parameters/) ?
>>
>> I would return the same value that was written in. Is the problem that
>> it is not stored anywhere? Maybe reconstruct it from
>> i915.guc_log_level ?
>>
>
> The verbosity value will be same as guc_log_level. But whether logging
> on GuC side is currently enabled or disabled can't be inferred (it could
> have been disabled at run time).
> So will have to store the exact value written by User.

That's what I meant. Code currently seem to decompose the value written 
via debugfs and store it in i915.guc_log_level:

0x00 = -1
0x10 = -1
...
0x01 = 0
0x11 = 1
0x21 = 2
0x31 = 3
...

So for readback you could translate back from i915.guc_log_level to the 
debugfs format.

Although I have suggested below even more...

>> Although it is not ideal that we got two formats for the same thing.
>> Thinking about that, why not use the same format in debugfs as for the
>> module param?

... that why do we have to have two formats? Isn't that a bit confusing?

Why couldn't we use the same integer values from i915.guc_log_level for 
debugfs control ?

>>
>> And I forgot, i915.guc_log_level == 0 is logging enabled with minimum
>> verbosity?
>>
> i915.guc_log_level == 0 just indicates the minimum verbosity. But
> logging could still be disabled on GuC side.

Yes, I can't remember any precedent where zero means enabled so it is 
just weird. But it is too late to change it now. :(

> For example, Driver boots with 'i915.guc_log_level = 0' so logging is
> enabled, later User disables the logging by echoing 0x0 on the
> guc_log_control debugfs file.

That's fine

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-20 10:40               ` Tvrtko Ursulin
@ 2016-07-20 11:29                 ` Goel, Akash
  2016-07-20 11:50                   ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-20 11:29 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/20/2016 4:10 PM, Tvrtko Ursulin wrote:
>
> On 20/07/16 11:12, Goel, Akash wrote:
>> On 7/20/2016 3:17 PM, Tvrtko Ursulin wrote:
>>>>>>>> +        ret = -EINVAL;
>>>>>>>> +        goto end;
>>>>>>>> +    }
>>>>>>>> +
>>>>>>>> +    intel_runtime_pm_get(dev_priv);
>>>>>>>> +    ret = i915_guc_log_control(dev, val);
>>>>>>>> +    intel_runtime_pm_put(dev_priv);
>>>>>>>> +
>>>>>>>> +end:
>>>>>>>> +    mutex_unlock(&dev->struct_mutex);
>>>>>>>> +    return ret;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
>>>>>>>> +            NULL, i915_guc_log_control_set,
>>>>>>>> +            "0x%08llx\n");
>>>>>>>
>>>>>>> Does the readback still work with no get method?
>>>>>>
>>>>>> readback will give a 'Permission denied' error
>>>>>
>>>>> Is that what we want? I think it would be nice to allow read-back
>>>>> unless
>>>>> there is a specific reason why it shouldn't be allowed.
>>>>>
>>>>
>>>> Ok can implement a dummy read back function but what should be
>>>> shown/returned on read.
>>>>
>>>> Should I show/return the guc_log_level value (which is also available
>>>> from /sys/module/i915/parameters/) ?
>>>
>>> I would return the same value that was written in. Is the problem that
>>> it is not stored anywhere? Maybe reconstruct it from
>>> i915.guc_log_level ?
>>>
>>
>> The verbosity value will be same as guc_log_level. But whether logging
>> on GuC side is currently enabled or disabled can't be inferred (it could
>> have been disabled at run time).
>> So will have to store the exact value written by User.
>
> That's what I meant. Code currently seem to decompose the value written
> via debugfs and store it in i915.guc_log_level:
>
> 0x00 = -1
> 0x10 = -1
> ...
> 0x01 = 0
> 0x11 = 1
> 0x21 = 2
> 0x31 = 3
> ...
>
> So for readback you could translate back from i915.guc_log_level to the
> debugfs format.
>
Sorry for all the mess.

Should I add a new field 'debugfs_ctrl_val' in guc structure, to store 
the value previously written to debugfs file, considering guc_log_level 
only gives an indication of the verbosity level ?

Actually in future there may be other additions also to the value 
written to guc_log_control debugfs, have right now exposed only logging 
& verbosity level controls to User, as they are deemed most useful right 
now.
But there are some other controls also which can be passed to GuC 
firmware through UK_LOG_ENABLE_LOGGING host2guc action.

Best regards
Akash

> Although I have suggested below even more...
>
>>> Although it is not ideal that we got two formats for the same thing.
>>> Thinking about that, why not use the same format in debugfs as for the
>>> module param?
>
> ... that why do we have to have two formats? Isn't that a bit confusing?
>
> Why couldn't we use the same integer values from i915.guc_log_level for
> debugfs control ?
>

>>>
>>> And I forgot, i915.guc_log_level == 0 is logging enabled with minimum
>>> verbosity?
>>>
>> i915.guc_log_level == 0 just indicates the minimum verbosity. But
>> logging could still be disabled on GuC side.
>
> Yes, I can't remember any precedent where zero means enabled so it is
> just weird. But it is too late to change it now. :(
>
>> For example, Driver boots with 'i915.guc_log_level = 0' so logging is
>> enabled, later User disables the logging by echoing 0x0 on the
>> guc_log_control debugfs file.
>
> That's fine
>
> Regards,
>
> Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-20 11:29                 ` Goel, Akash
@ 2016-07-20 11:50                   ` Tvrtko Ursulin
  2016-07-20 12:16                     ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-20 11:50 UTC (permalink / raw)
  To: Goel, Akash, intel-gfx


On 20/07/16 12:29, Goel, Akash wrote:
> On 7/20/2016 4:10 PM, Tvrtko Ursulin wrote:
>> On 20/07/16 11:12, Goel, Akash wrote:
>>> On 7/20/2016 3:17 PM, Tvrtko Ursulin wrote:
>>>>>>>>> +        ret = -EINVAL;
>>>>>>>>> +        goto end;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    intel_runtime_pm_get(dev_priv);
>>>>>>>>> +    ret = i915_guc_log_control(dev, val);
>>>>>>>>> +    intel_runtime_pm_put(dev_priv);
>>>>>>>>> +
>>>>>>>>> +end:
>>>>>>>>> +    mutex_unlock(&dev->struct_mutex);
>>>>>>>>> +    return ret;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
>>>>>>>>> +            NULL, i915_guc_log_control_set,
>>>>>>>>> +            "0x%08llx\n");
>>>>>>>>
>>>>>>>> Does the readback still work with no get method?
>>>>>>>
>>>>>>> readback will give a 'Permission denied' error
>>>>>>
>>>>>> Is that what we want? I think it would be nice to allow read-back
>>>>>> unless
>>>>>> there is a specific reason why it shouldn't be allowed.
>>>>>>
>>>>>
>>>>> Ok can implement a dummy read back function but what should be
>>>>> shown/returned on read.
>>>>>
>>>>> Should I show/return the guc_log_level value (which is also available
>>>>> from /sys/module/i915/parameters/) ?
>>>>
>>>> I would return the same value that was written in. Is the problem that
>>>> it is not stored anywhere? Maybe reconstruct it from
>>>> i915.guc_log_level ?
>>>>
>>>
>>> The verbosity value will be same as guc_log_level. But whether logging
>>> on GuC side is currently enabled or disabled can't be inferred (it could
>>> have been disabled at run time).
>>> So will have to store the exact value written by User.
>>
>> That's what I meant. Code currently seem to decompose the value written
>> via debugfs and store it in i915.guc_log_level:
>>
>> 0x00 = -1
>> 0x10 = -1
>> ...
>> 0x01 = 0
>> 0x11 = 1
>> 0x21 = 2
>> 0x31 = 3
>> ...
>>
>> So for readback you could translate back from i915.guc_log_level to the
>> debugfs format.
>>
> Sorry for all the mess.
>
> Should I add a new field 'debugfs_ctrl_val' in guc structure, to store
> the value previously written to debugfs file, considering guc_log_level
> only gives an indication of the verbosity level ?
>
> Actually in future there may be other additions also to the value
> written to guc_log_control debugfs, have right now exposed only logging
> & verbosity level controls to User, as they are deemed most useful right
> now.
> But there are some other controls also which can be passed to GuC
> firmware through UK_LOG_ENABLE_LOGGING host2guc action.

I see.

Would it work, for time being at least, to set i915.guc_log_level to -1 
when logging is disabled via debugfs?

It think that also has the advantage of making the current guc logging 
state consistent when observed from the outside. Otherwise the debugfs 
value and module parameter may disagree on it, as you said before. Which 
is not that great I think.

Apart from making the reported stated consistent, that way you could, at 
least for the time being, get away without storing a copy of 
guc_log_control but reconstruct it from the module parameter on read-back.

Regards,

Tvrtko



You could avoid storing a copy of guc_log_control like that.



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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/17] drm/i915: Debugfs support for GuC logging control
  2016-07-20 11:50                   ` Tvrtko Ursulin
@ 2016-07-20 12:16                     ` Goel, Akash
  0 siblings, 0 replies; 87+ messages in thread
From: Goel, Akash @ 2016-07-20 12:16 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx; +Cc: akash.goel



On 7/20/2016 5:20 PM, Tvrtko Ursulin wrote:
>
> On 20/07/16 12:29, Goel, Akash wrote:
>> On 7/20/2016 4:10 PM, Tvrtko Ursulin wrote:
>>> On 20/07/16 11:12, Goel, Akash wrote:
>>>> On 7/20/2016 3:17 PM, Tvrtko Ursulin wrote:

>>>>>>>>>> +DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
>>>>>>>>>> +            NULL, i915_guc_log_control_set,
>>>>>>>>>> +            "0x%08llx\n");
>>>>>>>>>
>>>>>>>>> Does the readback still work with no get method?
>>>>>>>>
>>>>>>>> readback will give a 'Permission denied' error
>>>>>>>
>>>>>>> Is that what we want? I think it would be nice to allow read-back
>>>>>>> unless
>>>>>>> there is a specific reason why it shouldn't be allowed.
>>>>>>>
>>>>>>
>>>>>> Ok can implement a dummy read back function but what should be
>>>>>> shown/returned on read.
>>>>>>
>>>>>> Should I show/return the guc_log_level value (which is also available
>>>>>> from /sys/module/i915/parameters/) ?
>>>>>
>>>>> I would return the same value that was written in. Is the problem that
>>>>> it is not stored anywhere? Maybe reconstruct it from
>>>>> i915.guc_log_level ?
>>>>>
>>>>
>>>> The verbosity value will be same as guc_log_level. But whether logging
>>>> on GuC side is currently enabled or disabled can't be inferred (it
>>>> could
>>>> have been disabled at run time).
>>>> So will have to store the exact value written by User.
>>>
>>> That's what I meant. Code currently seem to decompose the value written
>>> via debugfs and store it in i915.guc_log_level:
>>>
>>> 0x00 = -1
>>> 0x10 = -1
>>> ...
>>> 0x01 = 0
>>> 0x11 = 1
>>> 0x21 = 2
>>> 0x31 = 3
>>> ...
>>>
>>> So for readback you could translate back from i915.guc_log_level to the
>>> debugfs format.
>>>
>> Sorry for all the mess.
>>
>> Should I add a new field 'debugfs_ctrl_val' in guc structure, to store
>> the value previously written to debugfs file, considering guc_log_level
>> only gives an indication of the verbosity level ?
>>
>> Actually in future there may be other additions also to the value
>> written to guc_log_control debugfs, have right now exposed only logging
>> & verbosity level controls to User, as they are deemed most useful right
>> now.
>> But there are some other controls also which can be passed to GuC
>> firmware through UK_LOG_ENABLE_LOGGING host2guc action.
>
> I see.
>
> Would it work, for time being at least, to set i915.guc_log_level to -1
> when logging is disabled via debugfs?
>
Actually had thought about this, but didn't pursue since on doing so 
will have to adjust some of the guc_log_level related asserts/ conditions.
Will do it now as currently this looks to be the best alternative.
Thanks much for the inputs.

Best regards
Akash

> It think that also has the advantage of making the current guc logging
> state consistent when observed from the outside. Otherwise the debugfs
> value and module parameter may disagree on it, as you said before. Which
> is not that great I think.
>
> Apart from making the reported stated consistent, that way you could, at
> least for the time being, get away without storing a copy of
> guc_log_control but reconstruct it from the module parameter on read-back.
>
> Regards,
>
> Tvrtko
>
>
>
> You could avoid storing a copy of guc_log_control like that.
>
>
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 17/17] drm/i915: Use rt priority kthread to do GuC log buffer sampling
  2016-07-10 13:41 ` [PATCH 17/17] drm/i915: Use rt priority kthread to do GuC log buffer sampling akash.goel
@ 2016-07-20 19:34   ` Chris Wilson
  2016-07-21  3:41     ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Chris Wilson @ 2016-07-20 19:34 UTC (permalink / raw)
  To: akash.goel; +Cc: intel-gfx

On Sun, Jul 10, 2016 at 07:11:24PM +0530, akash.goel@intel.com wrote:
> @@ -1707,8 +1692,8 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
>  					I915_READ(SOFT_SCRATCH(15)) & ~msg);
>  
>  				/* Handle flush interrupt event in bottom half */
> -				queue_work(dev_priv->guc.log.wq,
> -						&dev_priv->guc.events_work);
> +				smp_store_mb(dev_priv->guc.log.flush_signal, 1);
> +				wake_up_process(dev_priv->guc.log.flush_task);
>  			}

> +void guc_cancel_log_flush_work_sync(struct drm_i915_private *dev_priv)
> +{
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	dev_priv->guc.log.flush_signal = false;
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +
> +	if (dev_priv->guc.log.flush_task)
> +		wait_for_completion(&dev_priv->guc.log.flush_completion);
> +}
> +
> +static int guc_log_flush_worker(void *arg)
> +{
> +	struct drm_i915_private *dev_priv = arg;
> +	struct intel_guc *guc = &dev_priv->guc;
> +
> +	/* Install ourselves with high priority to reduce signalling latency */
> +	struct sched_param param = { .sched_priority = 1 };
> +	sched_setscheduler_nocheck(current, SCHED_FIFO, &param);
> +
> +	do {
> +		set_current_state(TASK_INTERRUPTIBLE);
> +
> +		spin_lock_irq(&dev_priv->irq_lock);
> +		if (guc->log.flush_signal) {
> +			guc->log.flush_signal = false;
> +			reinit_completion(&guc->log.flush_completion);
> +			spin_unlock_irq(&dev_priv->irq_lock);
> +			i915_guc_capture_logs(&dev_priv->drm);
> +			complete_all(&guc->log.flush_completion);
> +		} else {
> +			spin_unlock_irq(&dev_priv->irq_lock);
> +			if (kthread_should_stop())
> +				break;
> +
> +			schedule();
> +		}
> +	} while (1);
> +	__set_current_state(TASK_RUNNING);
> +
> +	return 0;

This looks decidely fishy.

irq handler:
	smp_store_mb(log.signal, 1);
	wake_up_process(log.tsk);

worker:
do {
	set_current_state(TASK_INT);

	while (cmpxchg(&log.signal, 1, 0)) {
		reinit_completion(log.complete);
		i915_guc_capture_logs();
	}

	complete_all(log.complete);
	if (kthread_should_stop())
		break;
	
	schedule();
} while(1);
__set_current_state(TASK_RUNNING);

flush:
	smp_store_mb(log.signal, 0);
	wait_for_completion(log.complete);


In the end, just the silly locking and placement of complete_all() is
dangerous. reinit_completion() lacks the barrier to be used like this
really, at any rate, racy with the irq handler, so use sparingly or when
you control the irq handler. (Also not sure if log.signal = 0 is sane,
or the current callsites really require the flush.)
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 17/17] drm/i915: Use rt priority kthread to do GuC log buffer sampling
  2016-07-20 19:34   ` Chris Wilson
@ 2016-07-21  3:41     ` Goel, Akash
  2016-07-21  5:43       ` Chris Wilson
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-21  3:41 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx; +Cc: akash.goel



On 7/21/2016 1:04 AM, Chris Wilson wrote:
> On Sun, Jul 10, 2016 at 07:11:24PM +0530, akash.goel@intel.com wrote:
>> @@ -1707,8 +1692,8 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
>>  					I915_READ(SOFT_SCRATCH(15)) & ~msg);
>>
>>  				/* Handle flush interrupt event in bottom half */
>> -				queue_work(dev_priv->guc.log.wq,
>> -						&dev_priv->guc.events_work);
>> +				smp_store_mb(dev_priv->guc.log.flush_signal, 1);
>> +				wake_up_process(dev_priv->guc.log.flush_task);
>>  			}
>
>> +void guc_cancel_log_flush_work_sync(struct drm_i915_private *dev_priv)
>> +{
>> +	spin_lock_irq(&dev_priv->irq_lock);
>> +	dev_priv->guc.log.flush_signal = false;
>> +	spin_unlock_irq(&dev_priv->irq_lock);
>> +
>> +	if (dev_priv->guc.log.flush_task)
>> +		wait_for_completion(&dev_priv->guc.log.flush_completion);
>> +}
>> +
>> +static int guc_log_flush_worker(void *arg)
>> +{
>> +	struct drm_i915_private *dev_priv = arg;
>> +	struct intel_guc *guc = &dev_priv->guc;
>> +
>> +	/* Install ourselves with high priority to reduce signalling latency */
>> +	struct sched_param param = { .sched_priority = 1 };
>> +	sched_setscheduler_nocheck(current, SCHED_FIFO, &param);
>> +
>> +	do {
>> +		set_current_state(TASK_INTERRUPTIBLE);
>> +
>> +		spin_lock_irq(&dev_priv->irq_lock);
>> +		if (guc->log.flush_signal) {
>> +			guc->log.flush_signal = false;
>> +			reinit_completion(&guc->log.flush_completion);
>> +			spin_unlock_irq(&dev_priv->irq_lock);
>> +			i915_guc_capture_logs(&dev_priv->drm);
>> +			complete_all(&guc->log.flush_completion);
>> +		} else {
>> +			spin_unlock_irq(&dev_priv->irq_lock);
>> +			if (kthread_should_stop())
>> +				break;
>> +
>> +			schedule();
>> +		}
>> +	} while (1);
>> +	__set_current_state(TASK_RUNNING);
>> +
>> +	return 0;
>
> This looks decidely fishy.
>
Sorry for that.

> irq handler:
> 	smp_store_mb(log.signal, 1);
> 	wake_up_process(log.tsk);
>
> worker:
> do {
> 	set_current_state(TASK_INT);
>
> 	while (cmpxchg(&log.signal, 1, 0)) {
> 		reinit_completion(log.complete);
> 		i915_guc_capture_logs();
> 	}
>
> 	complete_all(log.complete);
> 	if (kthread_should_stop())
> 		break;
> 	
> 	schedule();
> } while(1);
> __set_current_state(TASK_RUNNING);
>
> flush:
> 	smp_store_mb(log.signal, 0);
> 	wait_for_completion(log.complete);
>
>
> In the end, just the silly locking and placement of complete_all() is
> dangerous. reinit_completion() lacks the barrier to be used like this
> really, at any rate, racy with the irq handler, so use sparingly or when
> you control the irq handler.
Sorry I forgot to add a comment that guc_cancel_log_flush_work_sync() 
should be invoked only after ensuring that there will be no more flush 
interrupts, which will happen either by explicitly disabling the 
interrupt or disabling the logging and that's what is done at the 2 call 
sites.

Since had covered reinit_completion() under the irq_lock, thought an 
explicit barrier is not needed.

	spin_lock_irq(&dev_priv->irq_lock);
	if (guc->log.flush_signal) {
		guc->log.flush_signal = false;
		reinit_completion(&guc->log.flush_completion);
		spin_unlock_irq(&dev_priv->irq_lock);
		i915_guc_capture_logs(&dev_priv->drm);
	 	complete_all(&guc->log.flush_completion);

The placement of complete_all isn't right for the case, where
a guc_cancel_log_flush_work_sync() is called but there was no prior 
flush interrupt received.

> (Also not sure if log.signal = 0 is sane,
Did log.signal = 0 for fast cancellation. Will remove that.

A smp_wmb() after reinit_completion(&flush_completion) would be fine ?

> or the current callsites really require the flush.)

Sync against a ongoing/pending flush is being done for the 2 forceful 
flush cases, which will be effective only if the pending flush is 
completed, so forceful flush should be serialized with a pending flush.

Best regards
Akash

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 17/17] drm/i915: Use rt priority kthread to do GuC log buffer sampling
  2016-07-21  3:41     ` Goel, Akash
@ 2016-07-21  5:43       ` Chris Wilson
  2016-07-21  6:18         ` Goel, Akash
  0 siblings, 1 reply; 87+ messages in thread
From: Chris Wilson @ 2016-07-21  5:43 UTC (permalink / raw)
  To: Goel, Akash; +Cc: intel-gfx

On Thu, Jul 21, 2016 at 09:11:42AM +0530, Goel, Akash wrote:
> 
> 
> On 7/21/2016 1:04 AM, Chris Wilson wrote:
> >In the end, just the silly locking and placement of complete_all() is
> >dangerous. reinit_completion() lacks the barrier to be used like this
> >really, at any rate, racy with the irq handler, so use sparingly or when
> >you control the irq handler.
> Sorry I forgot to add a comment that
> guc_cancel_log_flush_work_sync() should be invoked only after
> ensuring that there will be no more flush interrupts, which will
> happen either by explicitly disabling the interrupt or disabling the
> logging and that's what is done at the 2 call sites.
> 
> Since had covered reinit_completion() under the irq_lock, thought an
> explicit barrier is not needed.

You hadn't controlled everything via the irq_lock, and nor should you.

> 
> 	spin_lock_irq(&dev_priv->irq_lock);
> 	if (guc->log.flush_signal) {
> 		guc->log.flush_signal = false;
> 		reinit_completion(&guc->log.flush_completion);
> 		spin_unlock_irq(&dev_priv->irq_lock);
> 		i915_guc_capture_logs(&dev_priv->drm);
> 	 	complete_all(&guc->log.flush_completion);
> 
> The placement of complete_all isn't right for the case, where
> a guc_cancel_log_flush_work_sync() is called but there was no prior
> flush interrupt received.

Exactly.
 
> >(Also not sure if log.signal = 0 is sane,
> Did log.signal = 0 for fast cancellation. Will remove that.
> 
> A smp_wmb() after reinit_completion(&flush_completion) would be fine ?

Don't worry, the race can only be controlled by controlling the irq. In
the end, I think something more like

	while (signal) ...

	complete_all();
	schedule();
	reinit_completion();

is the simplest.

> >or the current callsites really require the flush.)
> 
> Sync against a ongoing/pending flush is being done for the 2
> forceful flush cases, which will be effective only if the pending
> flush is completed, so forceful flush should be serialized with a
> pending flush.

Or you just signal=true, wakeup task, wait_timeout. Otherwise you
haven't really serialized anything without disabling the interrupt.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 17/17] drm/i915: Use rt priority kthread to do GuC log buffer sampling
  2016-07-21  5:43       ` Chris Wilson
@ 2016-07-21  6:18         ` Goel, Akash
  2016-07-21  9:44           ` Tvrtko Ursulin
  0 siblings, 1 reply; 87+ messages in thread
From: Goel, Akash @ 2016-07-21  6:18 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx; +Cc: akash.goel



On 7/21/2016 11:13 AM, Chris Wilson wrote:
> On Thu, Jul 21, 2016 at 09:11:42AM +0530, Goel, Akash wrote:
>>
>>
>> On 7/21/2016 1:04 AM, Chris Wilson wrote:
>>> In the end, just the silly locking and placement of complete_all() is
>>> dangerous. reinit_completion() lacks the barrier to be used like this
>>> really, at any rate, racy with the irq handler, so use sparingly or when
>>> you control the irq handler.
>> Sorry I forgot to add a comment that
>> guc_cancel_log_flush_work_sync() should be invoked only after
>> ensuring that there will be no more flush interrupts, which will
>> happen either by explicitly disabling the interrupt or disabling the
>> logging and that's what is done at the 2 call sites.
>>
>> Since had covered reinit_completion() under the irq_lock, thought an
>> explicit barrier is not needed.
>
> You hadn't controlled everything via the irq_lock, and nor should you.
>
>>
>> 	spin_lock_irq(&dev_priv->irq_lock);
>> 	if (guc->log.flush_signal) {
>> 		guc->log.flush_signal = false;
>> 		reinit_completion(&guc->log.flush_completion);
>> 		spin_unlock_irq(&dev_priv->irq_lock);
>> 		i915_guc_capture_logs(&dev_priv->drm);
>> 	 	complete_all(&guc->log.flush_completion);
>>
>> The placement of complete_all isn't right for the case, where
>> a guc_cancel_log_flush_work_sync() is called but there was no prior
>> flush interrupt received.
>
> Exactly.
>
>>> (Also not sure if log.signal = 0 is sane,
>> Did log.signal = 0 for fast cancellation. Will remove that.
>>
>> A smp_wmb() after reinit_completion(&flush_completion) would be fine ?
>
> Don't worry, the race can only be controlled by controlling the irq.


> In the end, I think something more like
>
> 	while (signal) ...
>
> 	complete_all();
> 	schedule();
> 	reinit_completion();
>
> is the simplest.
Thanks much, so will have the task body like this.
do {
	set_current_state(TASK_INT);
	while (cmpxchg(&log.signal, 1, 0)) {
		i915_guc_capture_logs();
	};
	complete_all(log.complete);
	if (kthread_should_stop())
		break;
	schedule();
	reinit_completion();
} while(1);

>
>>> or the current callsites really require the flush.)
>>
>> Sync against a ongoing/pending flush is being done for the 2
>> forceful flush cases, which will be effective only if the pending
>> flush is completed, so forceful flush should be serialized with a
>> pending flush.
>
> Or you just signal=true, wakeup task, wait_timeout. Otherwise you
> haven't really serialized anything without disabling the interrupt.
Agree without disabling the interrupt, serialization cannot be provided,

For the sync can use,
{
	WARN_ON(guc->interrupts_enabled);
	wait_for_completion_interruptible_timeout(
			guc->log.complete, 5 /* in jiffies*/);
}


Best regards
Akash
> -Chris
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 17/17] drm/i915: Use rt priority kthread to do GuC log buffer sampling
  2016-07-21  6:18         ` Goel, Akash
@ 2016-07-21  9:44           ` Tvrtko Ursulin
  0 siblings, 0 replies; 87+ messages in thread
From: Tvrtko Ursulin @ 2016-07-21  9:44 UTC (permalink / raw)
  To: Goel, Akash, Chris Wilson, intel-gfx


On 21/07/16 07:18, Goel, Akash wrote:
> On 7/21/2016 11:13 AM, Chris Wilson wrote:
>> On Thu, Jul 21, 2016 at 09:11:42AM +0530, Goel, Akash wrote:
>>>
>>>
>>> On 7/21/2016 1:04 AM, Chris Wilson wrote:
>>>> In the end, just the silly locking and placement of complete_all() is
>>>> dangerous. reinit_completion() lacks the barrier to be used like this
>>>> really, at any rate, racy with the irq handler, so use sparingly or
>>>> when
>>>> you control the irq handler.
>>> Sorry I forgot to add a comment that
>>> guc_cancel_log_flush_work_sync() should be invoked only after
>>> ensuring that there will be no more flush interrupts, which will
>>> happen either by explicitly disabling the interrupt or disabling the
>>> logging and that's what is done at the 2 call sites.
>>>
>>> Since had covered reinit_completion() under the irq_lock, thought an
>>> explicit barrier is not needed.
>>
>> You hadn't controlled everything via the irq_lock, and nor should you.
>>
>>>
>>>     spin_lock_irq(&dev_priv->irq_lock);
>>>     if (guc->log.flush_signal) {
>>>         guc->log.flush_signal = false;
>>>         reinit_completion(&guc->log.flush_completion);
>>>         spin_unlock_irq(&dev_priv->irq_lock);
>>>         i915_guc_capture_logs(&dev_priv->drm);
>>>          complete_all(&guc->log.flush_completion);
>>>
>>> The placement of complete_all isn't right for the case, where
>>> a guc_cancel_log_flush_work_sync() is called but there was no prior
>>> flush interrupt received.
>>
>> Exactly.
>>
>>>> (Also not sure if log.signal = 0 is sane,
>>> Did log.signal = 0 for fast cancellation. Will remove that.
>>>
>>> A smp_wmb() after reinit_completion(&flush_completion) would be fine ?
>>
>> Don't worry, the race can only be controlled by controlling the irq.
>
>
>> In the end, I think something more like
>>
>>     while (signal) ...
>>
>>     complete_all();
>>     schedule();
>>     reinit_completion();
>>
>> is the simplest.
> Thanks much, so will have the task body like this.
> do {
>      set_current_state(TASK_INT);
>      while (cmpxchg(&log.signal, 1, 0)) {
>          i915_guc_capture_logs();
>      };
>      complete_all(log.complete);
>      if (kthread_should_stop())
>          break;
>      schedule();
>      reinit_completion();
> } while(1);
>
>>
>>>> or the current callsites really require the flush.)
>>>
>>> Sync against a ongoing/pending flush is being done for the 2
>>> forceful flush cases, which will be effective only if the pending
>>> flush is completed, so forceful flush should be serialized with a
>>> pending flush.
>>
>> Or you just signal=true, wakeup task, wait_timeout. Otherwise you
>> haven't really serialized anything without disabling the interrupt.
> Agree without disabling the interrupt, serialization cannot be provided,
>
> For the sync can use,
> {
>      WARN_ON(guc->interrupts_enabled);
>      wait_for_completion_interruptible_timeout(
>              guc->log.complete, 5 /* in jiffies*/);
> }

We don't even know for sure if the thread (especially rt priority) is 
absolutely required. Worker solution would be so much simpler if good 
enough.

Because in the meantime it was discovered that relayfs has a silly 
polling behaviour where it delays waking up readers by a jiffy and that 
copies can be done much faster with SSE instructions. And that we are 
increasing the GuC buffer anyway to improve space utilization.

So I say again, I think you need to evaluate all that and determine if a 
complicated thread solution is really needed.

In parallel question is also if relayfs needs to be improved wrt this 
latency issue, or if it can't, maybe it is the wrong facility for this 
use case.

Regards,

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

^ permalink raw reply	[flat|nested] 87+ messages in thread

end of thread, other threads:[~2016-07-21  9:44 UTC | newest]

Thread overview: 87+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-10 13:41 [PATCH v4 00/17] Support for sustained capturing of GuC firmware logs akash.goel
2016-07-10 13:41 ` [PATCH 01/17] drm/i915: Decouple GuC log setup from verbosity parameter akash.goel
2016-07-11  9:37   ` Tvrtko Ursulin
2016-07-11 11:41     ` Goel, Akash
2016-07-11 11:50       ` Tvrtko Ursulin
2016-07-11 12:11         ` Goel, Akash
2016-07-11 13:07           ` Tvrtko Ursulin
2016-07-10 13:41 ` [PATCH 02/17] drm/i915: Add GuC ukernel logging related fields to fw interface file akash.goel
2016-07-10 13:41 ` [PATCH 03/17] drm/i915: New structure to contain GuC logging related fields akash.goel
2016-07-10 13:41 ` [PATCH 04/17] drm/i915: Add low level set of routines for programming PM IER/IIR/IMR register set akash.goel
2016-07-11 10:04   ` Tvrtko Ursulin
2016-07-10 13:41 ` [PATCH 05/17] drm/i915: Support for GuC interrupts akash.goel
2016-07-11 10:30   ` Tvrtko Ursulin
2016-07-11 13:15     ` Goel, Akash
2016-07-11 13:23       ` Tvrtko Ursulin
2016-07-11 13:38         ` Goel, Akash
2016-07-11 13:43           ` Tvrtko Ursulin
2016-07-11 14:20             ` Goel, Akash
2016-07-10 13:41 ` [PATCH 06/17] drm/i915: Handle log buffer flush interrupt event from GuC akash.goel
2016-07-19 10:58   ` Tvrtko Ursulin
2016-07-20  3:29     ` Goel, Akash
2016-07-10 13:41 ` [PATCH 07/17] drm/i915: Add a relay backed debugfs interface for capturing GuC logs akash.goel
2016-07-10 17:07   ` kbuild test robot
2016-07-19 11:31   ` Tvrtko Ursulin
2016-07-20  3:41     ` Goel, Akash
2016-07-10 13:41 ` [PATCH 08/17] drm/i915: Forcefully flush GuC log buffer on reset akash.goel
2016-07-19 11:12   ` Tvrtko Ursulin
2016-07-19 11:21     ` Chris Wilson
2016-07-20  4:21       ` Goel, Akash
2016-07-20  9:12         ` Chris Wilson
2016-07-20  9:48           ` Goel, Akash
2016-07-10 13:41 ` [PATCH 09/17] drm/i915: Debugfs support for GuC logging control akash.goel
2016-07-10 17:59   ` kbuild test robot
2016-07-19 11:24   ` Tvrtko Ursulin
2016-07-20  4:42     ` Goel, Akash
2016-07-20  9:08       ` Tvrtko Ursulin
2016-07-20  9:32         ` Goel, Akash
2016-07-20  9:47           ` Tvrtko Ursulin
2016-07-20 10:12             ` Goel, Akash
2016-07-20 10:40               ` Tvrtko Ursulin
2016-07-20 11:29                 ` Goel, Akash
2016-07-20 11:50                   ` Tvrtko Ursulin
2016-07-20 12:16                     ` Goel, Akash
2016-07-10 13:41 ` [PATCH 10/17] drm/i915: New module param to control the size of buffer used for storing GuC firmware logs akash.goel
2016-07-15 11:15   ` Tvrtko Ursulin
2016-07-15 15:36     ` Goel, Akash
2016-07-18 10:06       ` Tvrtko Ursulin
2016-07-18 12:19         ` Goel, Akash
2016-07-18 13:06           ` Tvrtko Ursulin
2016-07-18 13:40             ` Goel, Akash
2016-07-10 13:41 ` [PATCH 11/17] drm/i915: Support to create write combined type vmaps akash.goel
2016-07-15 11:31   ` Tvrtko Ursulin
2016-07-15 11:45     ` Chris Wilson
2016-07-15 16:30     ` Goel, Akash
2016-07-18 10:18       ` Tvrtko Ursulin
2016-07-10 13:41 ` [PATCH 12/17] drm/i915: Use uncached(WC) mapping for acessing the GuC log buffer akash.goel
2016-07-10 13:41 ` [PATCH 13/17] drm/i915: New lock to serialize the Host2GuC actions akash.goel
2016-07-15 11:40   ` Tvrtko Ursulin
2016-07-15 15:51     ` Goel, Akash
2016-07-18 10:12       ` Tvrtko Ursulin
2016-07-18 10:46         ` Goel, Akash
2016-07-18 11:18           ` Tvrtko Ursulin
2016-07-18 11:31             ` Goel, Akash
2016-07-18 11:36               ` Tvrtko Ursulin
2016-07-10 13:41 ` [PATCH 14/17] drm/i915: Add stats for GuC log buffer flush interrupts akash.goel
2016-07-15 11:51   ` Tvrtko Ursulin
2016-07-15 15:58     ` Goel, Akash
2016-07-18 10:16       ` Tvrtko Ursulin
2016-07-18 10:59         ` Goel, Akash
2016-07-18 11:33           ` Tvrtko Ursulin
2016-07-18 11:47             ` Goel, Akash
2016-07-10 13:41 ` [PATCH 15/17] drm/i915: Increase GuC log buffer size to reduce " akash.goel
2016-07-15 11:57   ` Tvrtko Ursulin
2016-07-15 14:42     ` Goel, Akash
2016-07-15 15:07       ` Tvrtko Ursulin
2016-07-15 16:20         ` Goel, Akash
2016-07-18  9:54           ` Tvrtko Ursulin
2016-07-18 12:35             ` Goel, Akash
2016-07-18 13:08               ` Tvrtko Ursulin
2016-07-10 13:41 ` [PATCH 16/17] drm/i915: Optimization to reduce the sampling time of GuC log buffer akash.goel
2016-07-10 13:41 ` [PATCH 17/17] drm/i915: Use rt priority kthread to do GuC log buffer sampling akash.goel
2016-07-20 19:34   ` Chris Wilson
2016-07-21  3:41     ` Goel, Akash
2016-07-21  5:43       ` Chris Wilson
2016-07-21  6:18         ` Goel, Akash
2016-07-21  9:44           ` Tvrtko Ursulin
2016-07-10 14:12 ` ✗ Ro.CI.BAT: failure for Support for sustained capturing of GuC firmware logs (rev5) Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.