All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/18] Command submission via GuC for SKL
@ 2015-03-26 19:41 yu.dai
  2015-03-26 19:41 ` [PATCH 01/18] drm/i915: Add guc firmware interface headers yu.dai
                   ` (18 more replies)
  0 siblings, 19 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

This series of patch is to enable ExecList submission via GuC. Here are some
key points related to this series, not in particular order.

*** i915_guc_client ***
We use the term client to avoid confusion with contexts. A i915_guc_client is
equivalent to GuC object guc_context_desc. This context descriptor is allocated
from a pool of 1024 entries. Kernel driver will allocate doorbell and workqueue
for it. Also the process descriptor (guc_process_desc), which is mapped to
client space. So the client can write Work Item then ring the doorbell.

To simplify the implementation, we allocate one gem object that contains all
pages for doorbell, process descriptor and workqueue.

*** intel_guc ***
Top level structure of guc. It handles firmware loading and manages client pool
and doorbells. intel_guc owns a i915_guc_client to do the legacy submission.

** The Scratch registers ***
There are 16 MMIO-based registers start from 0xC180. The kernel driver writes a
value to the action register (SOFT_SCRATCH_0) along with any data. It then
triggers an interrupt on the GuC via another register write (0xC4C8). Firmware
writes a success/fail code back to the action register after processes the
request. The kernel driver polls waiting for this update and then proceeds.

Details in intel_guc_action()

*** Work Items ***
There are several types of work items that the host may place into a workqueue,
each with its own requirements and limitations. Currently only WQ_TYPE_INORDER
is used to support legacy submission via GuC, which represents in-order queue.
The kernel driver packs ring tail pointer and an ELSP context descriptor dword
into Work Item.

Details in add_workqueue_item()

*** Doorbells ***
Doorbells are interrupts to uKernel. A doorbell is a single cache line (QW)
mapped into process space.

Details in ring_doorbell()

*** Firmware versioning ***
The firmware build process will generate a version header file with major and
minor version defined. The versions are built into CSS header of firmware too.
i915 kernel driver set the minimal firmware version required by each platform.
The firmware installation package will install (symbolic link) proper version
of firmware.

*** Firmware log ***
Firmware log is enabled by setting i915.guc_log_level to non-negative level.
Log data is printed out via reading debugfs i915_guc_log_dump. Reading from
i915_guc_load_status will print out firmware loading status and scratch
registers value.

TODO: the buffer works like a ring. To not missing any data, driver should
handle a GuC2Host interrupt (triggered when log buffer is half full) from GuC.

*** Ring buffer size ***
It is up to 16K (4 pages) per LRC. Not HW limitation but firmware is setup in
this way.

*** GuC address space ***
GuC is not expecting any gfx GGTT address that falls into range [0, WOPCM_TOP),
which is reserved for Boot ROM, SRAM and WOPCM. Currently this top address is
512K in order to fit in big HuC firmware.

In order to exclude 0-512K address space from GGTT, all gfx objects used by GuC
is pinned with PIN_OFFSET_BIAS along with size of WOPCM.

Alex Dai (13):
  drm/i915: Add guc firmware interface headers
  drm/i915: GuC firmware loader
  drm/i915: Add firmware version check
  drm/i915: Make several execlist helper functions external
  drm/i915: Add functions to allocate / release gem obj for GuC
  drm/i915: Functions to support command submission via GuC
  drm/i915: Integration of GuC client
  drm/i915: Interrupt routing for GuC scheduler
  drm/i915: Enable commands submission via GuC
  drm/i915: debugfs of GuC status
  drm/i915: Enable GuC firmware log
  drm/i915: Ring Context allocating for GuC
  drm/i915: Notify GuC when RC6 state is changed

Dave Gordon (2):
  drm/i915: Unified firmware loading mechanism
  drm/i915: Defer default hardware context initialisation until first
    open

Michael H. Nguyen (2):
  drm/i915: Add i915_gem_object_write() to i915_gem.c
  drm/i915: Move execlists defines from .c to .h

Sagar Kamble (1):
  drm/i915: Taking forcewake during GuC load.

 drivers/gpu/drm/i915/Makefile              |   8 +-
 drivers/gpu/drm/i915/i915_debugfs.c        | 102 +++++
 drivers/gpu/drm/i915/i915_dma.c            |   6 +
 drivers/gpu/drm/i915/i915_drv.h            |  17 +
 drivers/gpu/drm/i915/i915_gem.c            |  39 +-
 drivers/gpu/drm/i915/i915_gem_context.c    |  35 +-
 drivers/gpu/drm/i915/i915_gem_stolen.c     |  10 +
 drivers/gpu/drm/i915/i915_params.c         |   9 +
 drivers/gpu/drm/i915/i915_reg.h            |  83 +++-
 drivers/gpu/drm/i915/intel_guc.h           | 186 +++++++++
 drivers/gpu/drm/i915/intel_guc_api.h       | 218 +++++++++++
 drivers/gpu/drm/i915/intel_guc_client.c    | 607 +++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_loader.c    | 466 ++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_scheduler.c | 167 ++++++++
 drivers/gpu/drm/i915/intel_lrc.c           | 112 ++----
 drivers/gpu/drm/i915/intel_lrc.h           |   3 +
 drivers/gpu/drm/i915/intel_pm.c            |   4 +
 drivers/gpu/drm/i915/intel_ringbuffer.c    |   2 +-
 drivers/gpu/drm/i915/intel_uc_loader.c     | 220 +++++++++++
 drivers/gpu/drm/i915/intel_uc_loader.h     |  82 ++++
 20 files changed, 2279 insertions(+), 97 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/intel_guc.h
 create mode 100644 drivers/gpu/drm/i915/intel_guc_api.h
 create mode 100644 drivers/gpu/drm/i915/intel_guc_client.c
 create mode 100644 drivers/gpu/drm/i915/intel_guc_loader.c
 create mode 100644 drivers/gpu/drm/i915/intel_guc_scheduler.c
 create mode 100644 drivers/gpu/drm/i915/intel_uc_loader.c
 create mode 100644 drivers/gpu/drm/i915/intel_uc_loader.h

-- 
1.9.1

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

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

* [PATCH 01/18] drm/i915: Add guc firmware interface headers
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 02/18] drm/i915: Add i915_gem_object_write() to i915_gem.c yu.dai
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

These are the subset of GuC interface that we are going to use to
enable command submission through GuC. The definition of these
struct and bit setting need to match those in firmware.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/intel_guc_api.h | 217 +++++++++++++++++++++++++++++++++++
 1 file changed, 217 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/intel_guc_api.h

diff --git a/drivers/gpu/drm/i915/intel_guc_api.h b/drivers/gpu/drm/i915/intel_guc_api.h
new file mode 100644
index 0000000..3d4f74a
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_api.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef _INTEL_GUC_API_H
+#define _INTEL_GUC_API_H
+
+#define GFXCORE_FAMILY_GEN8		11
+#define GFXCORE_FAMILY_GEN9		12
+#define GFXCORE_FAMILY_FORCE_ULONG	0x7fffffff
+
+#define GUC_CTX_PRIORITY_CRITICAL	0
+#define GUC_CTX_PRIORITY_HIGH		1
+#define GUC_CTX_PRIORITY_NORMAL		2
+#define GUC_CTX_PRIORITY_LOW		3
+
+#define MAX_GUC_GPU_CONTEXTS		1024
+
+/* Work queue item header definitions */
+#define WQ_STATUS_ACTIVE		1
+#define WQ_STATUS_SUSPENDED		2
+#define WQ_STATUS_CMD_ERROR		3
+#define WQ_STATUS_ENGINE_ID_NOT_USED	4
+#define WQ_STATUS_SUSPENDED_FROM_RESET	5
+#define WQ_TYPE_SHIFT			0
+#define   WQ_TYPE_BATCH_BUF		(0x1 << WQ_TYPE_SHIFT)
+#define   WQ_TYPE_PSEUDO		(0x2 << WQ_TYPE_SHIFT)
+#define   WQ_TYPE_INORDER		(0x3 << WQ_TYPE_SHIFT)
+#define WQ_TARGET_SHIFT			10
+#define WQ_LEN_SHIFT			16
+#define WQ_NO_WCFLUSH_WAIT		(1 << 27)
+#define WQ_PRESENT_WORKLOAD		(1 << 28)
+
+#define WQ_RING_TAIL_SHIFT		20
+#define WQ_RING_TAIL_MASK		(0x7FF << WQ_RING_TAIL_SHIFT)
+
+#define GUC_DOORBELL_ENABLED		1
+#define GUC_DOORBELL_DISABLED		0
+
+#define GUC_CTX_DESC_ATTR_ACTIVE	(1 << 0)
+#define GUC_CTX_DESC_ATTR_PENDING_DB	(1 << 1)
+#define GUC_CTX_DESC_ATTR_KERNEL	(1 << 2)
+#define GUC_CTX_DESC_ATTR_PREEMPT	(1 << 3)
+#define GUC_CTX_DESC_ATTR_RESET		(1 << 4)
+#define GUC_CTX_DESC_ATTR_WQLOCKED	(1 << 5)
+#define GUC_CTX_DESC_ATTR_PCH		(1 << 6)
+
+/* The guc control data is 10 DWORDs */
+#define GUC_CTL_CTXINFO			0
+#define   GUC_CTL_CTXNUM_IN16_SHIFT	0
+#define   GUC_CTL_BASE_ADDR_SHIFT	12
+#define GUC_CTL_ARAT_HIGH		1
+#define GUC_CTL_ARAT_LOW		2
+#define GUC_CTL_DEVICE_INFO		3
+#define   GUC_CTL_GTTYPE_SHIFT		0
+#define   GUC_CTL_COREFAMILY_SHIFT	7
+#define GUC_CTL_LOG_PARAMS		4
+#define   GUC_LOG_VALID			(1 << 0)
+#define   GUC_LOG_NOTIFY_ON_HALF_FULL	(1 << 1)
+#define   GUC_LOG_ALLOC_IN_MEGABYTE	(1 << 3)
+#define   GUC_LOG_CRASH_SHIFT		4
+#define   GUC_LOG_DPC_SHIFT		6
+#define   GUC_LOG_ISR_SHIFT		9
+#define   GUC_LOG_BUF_ADDR_SHIFT	12
+#define GUC_CTL_PAGE_FAULT_CONTROL	5
+#define GUC_CTL_WA			6
+#define   GUC_CTL_WA_UK_BY_DRIVER	(1 << 3)
+#define GUC_CTL_FEATURE			7
+#define   GUC_CTL_VCS2_ENABLED		(1 << 0)
+#define   GUC_CTL_KERNEL_SUBMISSIONS	(1 << 1)
+#define   GUC_CTL_FEATURE2		(1 << 2)
+#define   GUC_CTL_POWER_GATING		(1 << 3)
+#define   GUC_CTL_DISABLE_SCHEDULER	(1 << 4)
+#define   GUC_CTL_PREEMPTION_LOG	(1 << 5)
+#define GUC_CTL_DEBUG			8
+#define   GUC_LOG_VERBOSITY_SHIFT	0
+#define   GUC_LOG_VERBOSITY_LOW		(0 << GUC_LOG_VERBOSITY_SHIFT)
+#define   GUC_LOG_VERBOSITY_MED		(1 << GUC_LOG_VERBOSITY_SHIFT)
+#define   GUC_LOG_VERBOSITY_HIGH	(2 << GUC_LOG_VERBOSITY_SHIFT)
+#define   GUC_LOG_VERBOSITY_ULTRA	(3 << GUC_LOG_VERBOSITY_SHIFT)
+/* offset from base of LCRA, in pages */
+#define GUC_CTL_OFFSET			9
+#define   GUC_CTL_SHARED_DATA_SHIFT	0
+#define   GUC_CTL_RING_BUFFER_SHIFT	16
+
+#define GUC_CTL_MAX_DWORDS		(GUC_CTL_OFFSET + 1)
+
+struct guc_doorbell_info {
+	u32 db_status;
+	u32 cookie;
+	u32 reserved[14];
+} __packed;
+
+union guc_doorbell_qw {
+	struct {
+		u32 db_status;
+		u32 cookie;
+	};
+	u64 value_qw;
+} __packed;
+
+struct guc_process_desc {
+	u32 context_id;
+	u64 db_base_addr;
+	u32 head;
+	u32 tail;
+	u32 error_offset;
+	u64 wq_base_addr;
+	u32 wq_size_bytes;
+	u32 wq_status;
+	u32 engine_presence;
+	u32 priority;
+	u32 reserved[30];
+} __packed;
+
+/* Work item for submitting workloads into work queue of GuC. */
+struct guc_wq_item {
+	u32 header;
+	u32 context_desc;
+	u32 ring_tail;
+	u32 fence_id;
+} __packed;
+
+/* The execlist context including software and HW information */
+struct guc_execlist_context {
+	u32 context_desc;
+	u32 context_id;
+	u32 ring_status;
+	u32 ring_lcra;
+	u32 ring_begin;
+	u32 ring_end;
+	u32 ring_next_free_location;
+	u32 ring_current_tail_pointer_value;
+	u8 engine_state_submit_value;
+	u8 engine_state_wait_value;
+	u16 pagefault_count;
+	u16 engine_submit_queue_count;
+} __packed;
+
+/*Context descriptor for communicating between uKernel and Driver*/
+struct guc_context_desc {
+	u32 sched_common_area;
+	u32 context_id;
+	u32 pas_id;
+	u8 engines_used;
+	u64 db_trigger_cpu;
+	u32 db_trigger_uk;
+	u64 db_trigger_phy;
+	u16 db_id;
+
+	struct guc_execlist_context lrc[I915_NUM_RINGS];
+
+	u8 attribute;
+
+	u32 priority;
+
+	u32 wq_sampled_tail_offset;
+	u32 wq_total_submit_enqueues;
+
+	u32 process_desc;
+	u32 wq_addr;
+	u32 wq_size;
+
+	u32 engine_presence;
+
+	u32 reserved0[1];
+	u64 reserved1[1];
+
+	u64 desc_private;
+} __packed;
+
+/* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */
+enum host2guc_action {
+	HOST2GUC_ACTION_DEFAULT = 0x0,
+	HOST2GUC_ACTION_ALLOCATE_DOORBELL = 0x10,
+	HOST2GUC_ACTION_DEALLOCATE_DOORBELL = 0x20,
+	HOST2GUC_ACTION_LIMIT
+};
+
+/*
+ * The GuC sends its response to a command by overwriting the
+ * command in SS0. The response is distinguishable from a command
+ * by the fact that all the MASK bits are set. The remaining bits
+ * give more detail.
+ */
+#define	GUC2HOST_RESPONSE_MASK	0xF0000000
+#define	GUC2HOST_IS_RESPONSE(x) \
+	(((x) & GUC2HOST_RESPONSE_MASK) == GUC2HOST_RESPONSE_MASK)
+#define	GUC2HOST_STATUS(x)	(GUC2HOST_RESPONSE_MASK | (x))
+
+/* GUC will return status back to SOFT_SCRATCH_O_REG */
+enum guc2host_status {
+	GUC2HOST_STATUS_SUCCESS = GUC2HOST_STATUS(0x0),
+	GUC2HOST_STATUS_ALLOCATE_DOORBELL_FAIL = GUC2HOST_STATUS(0x10),
+	GUC2HOST_STATUS_DEALLOCATE_DOORBELL_FAIL = GUC2HOST_STATUS(0x20),
+	GUC2HOST_STATUS_GENERIC_FAIL = GUC2HOST_STATUS(0x0000F000)
+};
+
+#endif
-- 
1.9.1

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

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

* [PATCH 02/18] drm/i915: Add i915_gem_object_write() to i915_gem.c
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
  2015-03-26 19:41 ` [PATCH 01/18] drm/i915: Add guc firmware interface headers yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 03/18] drm/i915: Unified firmware loading mechanism yu.dai
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Michael H. Nguyen

From: "Michael H. Nguyen" <michael.h.nguyen@intel.com>

i915_gem_object_write() is a generic function to copy data from
user memory to gem object.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h |  3 +++
 drivers/gpu/drm/i915/i915_gem.c | 30 ++++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 256369f..e4215a0 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2612,6 +2612,9 @@ void i915_init_vm(struct drm_i915_private *dev_priv,
 void i915_gem_free_object(struct drm_gem_object *obj);
 void i915_gem_vma_destroy(struct i915_vma *vma);
 
+int i915_gem_object_write(struct drm_i915_gem_object *obj,
+			const void *data, const size_t size);
+
 #define PIN_MAPPABLE 0x1
 #define PIN_NONBLOCK 0x2
 #define PIN_GLOBAL 0x4
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 3300963..38e49d9 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -5197,3 +5197,33 @@ bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj)
 	return false;
 }
 
+/* Fill the @obj with the @size amount of @data */
+int i915_gem_object_write(struct drm_i915_gem_object *obj,
+			const void *data, const size_t size)
+{
+	struct sg_table *sg;
+	size_t bytes;
+	int ret;
+
+	ret = i915_gem_object_get_pages(obj);
+	if (ret)
+		return ret;
+
+	i915_gem_object_pin_pages(obj);
+
+	sg = obj->pages;
+
+	bytes = sg_copy_from_buffer(sg->sgl, sg->nents,
+				    (void *)data, (size_t)size);
+
+	i915_gem_object_unpin_pages(obj);
+
+	if (WARN(bytes != size,
+		 "Failed to upload all data (completed %zu bytes out of %zu total",
+		 bytes, size)) {
+		i915_gem_object_put_pages(obj);
+		return -EIO;
+	}
+
+	return 0;
+}
-- 
1.9.1

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

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

* [PATCH 03/18] drm/i915: Unified firmware loading mechanism
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
  2015-03-26 19:41 ` [PATCH 01/18] drm/i915: Add guc firmware interface headers yu.dai
  2015-03-26 19:41 ` [PATCH 02/18] drm/i915: Add i915_gem_object_write() to i915_gem.c yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 04/18] drm/i915: GuC firmware loader yu.dai
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Dave Gordon <david.s.gordon@intel.com>

Factor out the common code of loading firmware into a new file,
leaving only the uC-specific parts in the GuC loaders.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
---
 drivers/gpu/drm/i915/Makefile          |   3 +
 drivers/gpu/drm/i915/intel_uc_loader.c | 208 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_uc_loader.h |  78 +++++++++++++
 3 files changed, 289 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/intel_uc_loader.c
 create mode 100644 drivers/gpu/drm/i915/intel_uc_loader.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index a69002e..1b027c7 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -39,6 +39,9 @@ i915-y += i915_cmd_parser.o \
 	  intel_ringbuffer.o \
 	  intel_uncore.o
 
+# ancilliary microcontroller support
+i915-y += intel_uc_loader.o
+
 # autogenerated null render state
 i915-y += intel_renderstate_gen6.o \
 	  intel_renderstate_gen7.o \
diff --git a/drivers/gpu/drm/i915/intel_uc_loader.c b/drivers/gpu/drm/i915/intel_uc_loader.c
new file mode 100644
index 0000000..249e56e
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_uc_loader.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#include <linux/firmware.h>
+#include "i915_drv.h"
+#include "intel_uc_loader.h"
+
+/*
+ * Called once per uC, late in driver initialisation. GEM is now ready, and so
+ * we can now create a GEM object to hold the uC firmware. But first, we must
+ * synchronise with the firmware-fetching thread that was initiated during
+ * early driver load, in intel_uc_fw_init(), and see whether it successfully
+ * fetched the firmware blob.
+ */
+static void uc_fw_finish(struct drm_device *dev, struct intel_uc_fw *uc_fw)
+{
+	struct drm_i915_gem_object *obj = NULL;
+	const struct firmware *fw;
+
+	DRM_DEBUG_DRIVER("before waiting: %s fw fetch status %d, fw %p\n",
+		uc_fw->uc_name, uc_fw->uc_fw_fetch_status, uc_fw->uc_fw_blob);
+
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+	WARN_ON(uc_fw->uc_fw_fetch_status != INTEL_UC_FIRMWARE_PENDING);
+
+	wait_for_completion(&uc_fw->uc_fw_fetched);
+
+	DRM_DEBUG_DRIVER("after waiting: %s fw fetch status %d, fw %p\n",
+		uc_fw->uc_name, uc_fw->uc_fw_fetch_status, uc_fw->uc_fw_blob);
+
+	fw = uc_fw->uc_fw_blob;
+	uc_fw->uc_fw_blob = NULL;
+	if (!fw)
+		goto fail;
+
+	obj = i915_gem_alloc_object(dev, round_up(fw->size, PAGE_SIZE));
+	if (!obj)
+		goto fail;
+
+	if (i915_gem_object_write(obj, fw->data, fw->size))
+		goto fail;
+
+	DRM_DEBUG_DRIVER("%s fw fetch status SUCCESS\n", uc_fw->uc_name);
+	uc_fw->uc_fw_obj = obj;
+	uc_fw->uc_fw_size = fw->size;
+	uc_fw->uc_fw_fetch_status = INTEL_UC_FIRMWARE_SUCCESS;
+	release_firmware(fw);
+	return;
+
+fail:
+	DRM_DEBUG_DRIVER("%s fw fetch status FAIL; fw %p, obj %p\n",
+		uc_fw->uc_name, fw, obj);
+	DRM_ERROR("Failed to fetch %s firmware from <%s>\n",
+		  uc_fw->uc_name, uc_fw->uc_fw_path);
+
+	if (obj)
+		drm_gem_object_unreference(&obj->base);
+
+	uc_fw->uc_fw_fetch_status = INTEL_UC_FIRMWARE_FAIL;
+	release_firmware(fw);		/* OK even if fw is NULL */
+}
+
+/*
+ * Check the status of the firmware fetching process. If it's still
+ * PENDING, wait for completion first, then check the outcome.
+ */
+int intel_uc_fw_check(struct drm_device *dev, struct intel_uc_fw *uc_fw)
+{
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+	if (uc_fw->uc_fw_fetch_status == INTEL_UC_FIRMWARE_PENDING) {
+		/* We only come here once */
+		uc_fw_finish(dev, uc_fw);
+		/* state must now be FAIL or SUCCESS */
+	}
+
+	DRM_DEBUG_DRIVER("%s fw fetch status %d\n",
+		uc_fw->uc_name, uc_fw->uc_fw_fetch_status);
+
+	switch (uc_fw->uc_fw_fetch_status) {
+	case INTEL_UC_FIRMWARE_FAIL:
+		/* something went wrong :( */
+		return -EIO;
+
+	case INTEL_UC_FIRMWARE_NONE:
+		/* no firmware, nothing to do (not an error) */
+		return 0;
+
+	case INTEL_UC_FIRMWARE_PENDING:
+	default:
+		/* "can't happen" */
+		WARN_ONCE(1, "%s fw <%s> invalid uc_fw_fetch_status %d!\n",
+			uc_fw->uc_name, uc_fw->uc_fw_path,
+			uc_fw->uc_fw_fetch_status);
+		return -ENXIO;
+
+	case INTEL_UC_FIRMWARE_SUCCESS:
+		return 0;
+	}
+}
+
+/*
+ * Callback from the kernel's asynchronous firmware-fetching subsystem.
+ * All we have to do is stash the blob and signal completion.
+ * Error checking (e.g. no firmware) is left to mainline code.
+ * We don't have (and don't want or need to acquire) the struct_mutex here.
+ */
+static void uc_fw_fetch_callback(const struct firmware *fw, void *context)
+{
+	struct intel_uc_fw *uc_fw = context;
+
+	WARN_ON(uc_fw->uc_fw_fetch_status != INTEL_UC_FIRMWARE_PENDING);
+	DRM_DEBUG_DRIVER("%s firmware fetch from <%s> status %d, fw %p\n",
+			uc_fw->uc_name, uc_fw->uc_fw_path,
+			uc_fw->uc_fw_fetch_status, fw);
+
+	uc_fw->uc_fw_blob = fw;
+	complete(&uc_fw->uc_fw_fetched);
+}
+
+/*
+ * This is called just once per uC, during driver loading. It is therefore
+ * automatically single-threaded and does not need to acquire any mutexes
+ * or spinlocks. OTOH, GEM is not yet fully initialised, so we can't do
+ * very much here.
+ *
+ * The main task here is to initiate the fetching of the uC firmware into
+ * memory, using the standard kernel firmware fetching support.  The actual
+ * fetching will then proceed asynchronously and in parallel with the rest
+ * of driver initialisation; later in the loading process we will synchronise
+ * with the firmware-fetching thread before transferring the firmware image
+ * firstly into a GEM object and then into the uC's memory.
+ */
+void intel_uc_fw_init(struct drm_device *dev, struct intel_uc_fw *uc_fw,
+	const char *name, const char *fw_path, bool has_ucode)
+{
+	uc_fw->uc_name = name;
+	uc_fw->uc_fw_path = fw_path;
+	uc_fw->uc_fw_fetch_status = INTEL_UC_FIRMWARE_NONE;
+	init_completion(&uc_fw->uc_fw_fetched);
+
+	if (!has_ucode)
+		return;
+	if (fw_path == NULL) {
+		DRM_ERROR("No known %s firmware on this platform\n", name);
+		uc_fw->uc_fw_fetch_status = INTEL_UC_FIRMWARE_FAIL;
+		return;
+	}
+
+	uc_fw->uc_fw_fetch_status = INTEL_UC_FIRMWARE_PENDING;
+
+	if (request_firmware_nowait(THIS_MODULE, true, fw_path,
+				    &dev->pdev->dev,
+				    GFP_KERNEL, uc_fw,
+				    uc_fw_fetch_callback)) {
+		DRM_ERROR("Failed to request %s firmware from <%s>\n",
+			  name, fw_path);
+		uc_fw->uc_fw_fetch_status = INTEL_UC_FIRMWARE_FAIL;
+		return;
+	}
+
+	/* firmware fetch initiated, callback will signal completion */
+	DRM_DEBUG_DRIVER("initiated fetching %s firmware from <%s>\n",
+		name, fw_path);
+}
+
+/*
+ * Clean up all uC firmware-related data
+ */
+void intel_uc_fw_fini(struct drm_device *dev, struct intel_uc_fw *uc_fw)
+{
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+	/*
+	 * Generally, the blob should have been released earlier, but
+	 * if the driver load were aborted after the fetch had been
+	 * initiated but not completed it might still be around
+	 */
+	if (uc_fw->uc_fw_fetch_status == INTEL_UC_FIRMWARE_PENDING)
+		wait_for_completion(&uc_fw->uc_fw_fetched);
+	if (uc_fw->uc_fw_blob)
+		release_firmware(uc_fw->uc_fw_blob);
+	uc_fw->uc_fw_blob = NULL;
+
+	if (uc_fw->uc_fw_obj)
+		drm_gem_object_unreference(&uc_fw->uc_fw_obj->base);
+	uc_fw->uc_fw_obj = NULL;
+}
diff --git a/drivers/gpu/drm/i915/intel_uc_loader.h b/drivers/gpu/drm/i915/intel_uc_loader.h
new file mode 100644
index 0000000..661d46a
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_uc_loader.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#ifndef _INTEL_UC_LOADER_H
+#define _INTEL_UC_LOADER_H
+
+/*
+ * Microcontroller (uC) firmware loading support
+ */
+
+/*
+ * These values are used to track the stages of getting the required firmware
+ * into an onboard microcontroller. The common code tracks the phases of
+ * fetching the firmware (aka "binary blob") from an external file into a GEM
+ * object in the 'uc_fw_fetch_status' field below; the uC-specific DMA code
+ * uses the 'uc_fw_load_status' field to track the transfer from GEM object
+ * to uC memory.
+ *
+ * For the first (fetch) stage, the interpretation of the values is:
+ * NONE - no firmware is being fetched e.g. because there is no uC
+ * PENDING - firmware fetch initiated; callback will complete 'uc_fw_fetched'
+ * SUCCESS - uC firmware fetched into a GEM object and ready for use
+ * FAIL - something went wrong; uC firmware is not available
+ *
+ * The second (load) stage is simpler as there is no asynchronous handoff:
+ * NONE - no firmware is being loaded e.g. because there is no uC
+ * PENDING - firmware DMA load in progress
+ * SUCCESS - uC firmware loaded into uC memory and ready for use
+ * FAIL - something went wrong; uC firmware is not available
+ */
+enum intel_uc_fw_status {
+	INTEL_UC_FIRMWARE_FAIL = -1,
+	INTEL_UC_FIRMWARE_NONE = 0,
+	INTEL_UC_FIRMWARE_PENDING,
+	INTEL_UC_FIRMWARE_SUCCESS
+};
+
+/*
+ * This structure encapsulates all the data needed during the process of
+ * fetching, caching, and loading the firmware image into the uC.
+ */
+struct intel_uc_fw {
+	const char *			uc_name;
+	const char *			uc_fw_path;
+	const struct firmware *		uc_fw_blob;
+	struct completion		uc_fw_fetched;
+	size_t				uc_fw_size;
+	struct drm_i915_gem_object *	uc_fw_obj;
+	enum intel_uc_fw_status		uc_fw_fetch_status;
+	enum intel_uc_fw_status		uc_fw_load_status;
+};
+
+void intel_uc_fw_init(struct drm_device *dev, struct intel_uc_fw *uc_fw,
+	const char *uc_name, const char *fw_path, bool has_ucode);
+int intel_uc_fw_check(struct drm_device *dev, struct intel_uc_fw *uc_fw);
+void intel_uc_fw_fini(struct drm_device *dev, struct intel_uc_fw *uc_fw);
+
+#endif
-- 
1.9.1

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

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

* [PATCH 04/18] drm/i915: GuC firmware loader
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (2 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 03/18] drm/i915: Unified firmware loading mechanism yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 05/18] drm/i915: Add firmware version check yu.dai
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

Add GuC firmware loader. It uses the unified firmware loader to
fetch firmware blob first, then load to hw in driver main thread.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/Makefile           |   3 +-
 drivers/gpu/drm/i915/i915_dma.c         |   6 +
 drivers/gpu/drm/i915/i915_drv.h         |   6 +
 drivers/gpu/drm/i915/i915_gem_stolen.c  |  10 ++
 drivers/gpu/drm/i915/i915_reg.h         |   4 +-
 drivers/gpu/drm/i915/intel_guc.h        |  95 +++++++++++
 drivers/gpu/drm/i915/intel_guc_loader.c | 271 ++++++++++++++++++++++++++++++++
 7 files changed, 393 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/intel_guc.h
 create mode 100644 drivers/gpu/drm/i915/intel_guc_loader.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 1b027c7..6188302 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -40,7 +40,8 @@ i915-y += i915_cmd_parser.o \
 	  intel_uncore.o
 
 # ancilliary microcontroller support
-i915-y += intel_uc_loader.o
+i915-y += intel_uc_loader.o \
+	  intel_guc_loader.o
 
 # autogenerated null render state
 i915-y += intel_renderstate_gen6.o \
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index d49ed68..a4e6ffb 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -465,6 +465,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
 cleanup_gem:
 	mutex_lock(&dev->struct_mutex);
+	intel_guc_ucode_fini(dev);
 	i915_gem_cleanup_ringbuffer(dev);
 	i915_gem_context_fini(dev);
 	mutex_unlock(&dev->struct_mutex);
@@ -828,6 +829,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
 	intel_uncore_init(dev);
 
+	intel_wopcm_init(dev);
+
+	intel_guc_ucode_init(dev);
+
 	ret = i915_gem_gtt_init(dev);
 	if (ret)
 		goto out_regs;
@@ -1071,6 +1076,7 @@ int i915_driver_unload(struct drm_device *dev)
 	flush_workqueue(dev_priv->wq);
 
 	mutex_lock(&dev->struct_mutex);
+	intel_guc_ucode_fini(dev);
 	i915_gem_cleanup_ringbuffer(dev);
 	i915_gem_batch_pool_fini(&dev_priv->mm.batch_pool);
 	i915_gem_context_fini(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index e4215a0..1a60f86 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -50,6 +50,7 @@
 #include <linux/intel-iommu.h>
 #include <linux/kref.h>
 #include <linux/pm_qos.h>
+#include "intel_guc.h"
 
 /* General customization:
  */
@@ -1576,6 +1577,7 @@ struct drm_i915_private {
 
 	struct intel_gmbus gmbus[GMBUS_NUM_PORTS];
 
+	struct intel_guc guc;
 
 	/** gmbus_mutex protects against concurrent usage of the single hw gmbus
 	 * controller on different i2c buses. */
@@ -2405,6 +2407,9 @@ struct drm_i915_cmd_table {
 #define HAS_RC6(dev)		(INTEL_INFO(dev)->gen >= 6)
 #define HAS_RC6p(dev)		(INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev))
 
+#define HAS_GUC_UCODE(dev)	(IS_GEN9(dev) || IS_GEN8(dev))
+#define HAS_GUC_SCHED(dev)	(IS_GEN9(dev) || IS_BROADWELL(dev))
+
 #define INTEL_PCH_DEVICE_ID_MASK		0xff00
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE		0x3b00
 #define INTEL_PCH_CPT_DEVICE_ID_TYPE		0x1c00
@@ -2958,6 +2963,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
 					       u32 stolen_offset,
 					       u32 gtt_offset,
 					       u32 size);
+void intel_wopcm_init(struct drm_device *dev);
 
 /* i915_gem_shrinker.c */
 unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index f8da716..1377076 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -551,3 +551,13 @@ err_out:
 	drm_gem_object_unreference(&obj->base);
 	return NULL;
 }
+
+void intel_wopcm_init(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (HAS_GUC_UCODE(dev)) {
+		I915_WRITE(GUC_WOPCM_SIZE, GUC_WOPCM_SIZE_VALUE);
+		I915_WRITE(DMA_GUC_WOPCM_OFFSET, GUC_WOPCM_OFFSET);
+	}
+}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index b522eb6..dfd1eb4 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -6289,7 +6289,9 @@ enum skl_disp_power_wells {
 #define   GEN9_PGCTL_SSB_EU311_ACK	(1 << 14)
 
 #define GEN7_MISCCPCTL			(0x9424)
-#define   GEN7_DOP_CLOCK_GATE_ENABLE	(1<<0)
+#define   GEN7_DOP_CLOCK_GATE_ENABLE		(1<<0)
+#define   GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE	(1<<2)
+#define   GEN8_DOP_CLOCK_GATE_GUC_ENABLE	(1<<4)
 
 /* IVYBRIDGE DPF */
 #define GEN7_L3CDERRST1			0xB008 /* L3CD Error Status 1 */
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
new file mode 100644
index 0000000..d8e7c00
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#ifndef _INTEL_GUC_H_
+#define _INTEL_GUC_H_
+
+#include "intel_guc_api.h"
+#include "intel_uc_loader.h"
+
+struct intel_guc {
+	struct intel_uc_fw guc_fw;
+};
+
+#define GUC_STATUS		0xc000
+#define   GS_BOOTROM_SHIFT	1
+#define   GS_BOOTROM_MASK	(0x7F << GS_BOOTROM_SHIFT)
+#define   GS_BOOTROM_RSA_FAILED	(0x50 << GS_BOOTROM_SHIFT)
+#define   GS_UKERNEL_SHIFT	8
+#define   GS_UKERNEL_MASK	(0xFF << GS_UKERNEL_SHIFT)
+#define   GS_UKERNEL_LAPIC_DONE	(0x30 << GS_UKERNEL_SHIFT)
+#define   GS_UKERNEL_DPC_ERROR	(0x60 << GS_UKERNEL_SHIFT)
+#define   GS_UKERNEL_READY	(0xF0 << GS_UKERNEL_SHIFT)
+#define   GS_MIA_SHIFT		16
+#define   GS_MIA_MASK		(0x7 << GS_MIA_SHIFT)
+
+#define GUC_WOPCM_SIZE		0xc050
+#define   GUC_WOPCM_SIZE_VALUE  (0x80 << 12)	/* 512KB */
+#define   GUC_WOPCM_OFFSET	0x80000		/* 512KB */
+#define SOFT_SCRATCH(n)		(0xc180 + ((n) * 4))
+
+#define UOS_RSA_SCRATCH_0	0xc200
+#define   UOS_RSA_SIG_SIZE	0x100
+#define DMA_ADDR_0_LOW		0xc300
+#define DMA_ADDR_0_HIGH		0xc304
+#define DMA_ADDR_1_LOW		0xc308
+#define DMA_ADDR_1_HIGH		0xc30c
+#define   DMA_ADDRESS_SPACE_WOPCM	(7 << 16)
+#define   DMA_ADDRESS_SPACE_GTT		(8 << 16)
+#define DMA_COPY_SIZE		0xc310
+#define DMA_CTRL		0xc314
+#define   UOS_MOVE		(1<<4)
+#define   START_DMA		(1<<0)
+#define DMA_GUC_WOPCM_OFFSET	0xc340
+
+#define GEN8_GT_PM_CONFIG		0x138140
+#define GEN9_GT_PM_CONFIG		0x13816c
+#define   GEN8_GT_DOORBELL_ENABLE	(1<<0)
+
+#define GEN8_GTCR 0x4274
+#define   GEN8_GTCR_INVALIDATE (1<<0)
+
+#define GUC_ARAT_C6DIS		0xA178
+
+#define GUC_SHIM_CONTROL	(0xc064)
+#define   GUC_DISABLE_SRAM_INIT_TO_ZEROES	(1<<0)
+#define   GUC_ENABLE_READ_CACHE_LOGIC		(1<<1)
+#define   GUC_ENABLE_MIA_CACHING		(1<<2)
+#define   GUC_GEN10_MSGCH_ENABLE		(1<<4)
+#define   GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA	(1<<9)
+#define   GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA	(1<<10)
+#define   GUC_ENABLE_MIA_CLOCK_GATING		(1<<15)
+#define   GUC_GEN10_SHIM_WC_ENABLE		(1<<21)
+
+#define GUC_SHIM_CONTROL_VALUE	(GUC_DISABLE_SRAM_INIT_TO_ZEROES | \
+				 GUC_ENABLE_READ_CACHE_LOGIC | \
+				 GUC_ENABLE_MIA_CACHING | \
+				 GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA | \
+				 GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA)
+
+/* intel_guc_loader.c */
+extern int intel_guc_load_ucode(struct drm_device *dev);
+extern void intel_guc_ucode_fini(struct drm_device *dev);
+extern void intel_guc_ucode_init(struct drm_device *dev);
+
+#endif
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
new file mode 100644
index 0000000..91af710
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#include <linux/firmware.h>
+#include "i915_drv.h"
+#include "intel_guc.h"
+
+#define I915_GUC_UCODE_GEN8 "i915/guc_gen8.bin"
+#define I915_GUC_UCODE_GEN9 "i915/guc_gen9.bin"
+MODULE_FIRMWARE(I915_GUC_UCODE_GEN8);
+MODULE_FIRMWARE(I915_GUC_UCODE_GEN9);
+
+static int copy_rsa(struct drm_i915_private *dev_priv)
+{
+	struct sg_table *st = dev_priv->guc.guc_fw.uc_fw_obj->pages;
+	uint32_t rsa[UOS_RSA_SIG_SIZE / sizeof(uint32_t)];
+	size_t bytes;
+	int i;
+
+	bytes = sg_copy_to_buffer(st->sgl, st->nents, rsa, UOS_RSA_SIG_SIZE);
+	if (bytes != UOS_RSA_SIG_SIZE)
+		return -ENXIO;
+
+	for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(uint32_t); i++)
+		I915_WRITE(UOS_RSA_SCRATCH_0 + i * sizeof(uint32_t), rsa[i]);
+
+	return 0;
+}
+
+/* Read GuC status register (GUC_STATUS)
+ * Return true if get a success code from normal boot or RC6 boot
+ */
+static inline bool i915_guc_get_status(struct drm_i915_private *dev_priv,
+					u32 *status)
+{
+	*status = I915_READ(GUC_STATUS);
+	return (((*status) & GS_UKERNEL_MASK) == GS_UKERNEL_READY ||
+		((*status) & GS_UKERNEL_MASK) == GS_UKERNEL_LAPIC_DONE);
+}
+
+/* Transfers the firmware image to RAM for execution by the microcontroller.
+ *
+ * Architecturally, the DMA engine is bidirectional, and in can potentially
+ * even transfer between GTT locations. This functionality is left out of the
+ * API for now as there is no need for it.
+ */
+static int ucode_dma_xfer_sync(struct drm_i915_private *dev_priv)
+{
+	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
+	struct drm_i915_gem_object *fw_obj = guc_fw->uc_fw_obj;
+	const unsigned long offset = i915_gem_obj_ggtt_offset(fw_obj);
+	u32 status;
+	int ret = 0;
+
+	/* Set the source address for the uCode */
+	I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset) + UOS_RSA_SIG_SIZE);
+	I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
+
+	/* Set the destination. Current uCode expects an 8k stack starting from
+	 * offset 0. */
+	I915_WRITE(DMA_ADDR_1_LOW, 0x2000);
+
+	/* XXX: The image is automatically transfered to SRAM after the RSA
+	 * verification. This is why the address space is chosen as such. */
+	I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);
+
+	I915_WRITE(DMA_COPY_SIZE, guc_fw->uc_fw_size - UOS_RSA_SIG_SIZE);
+
+	/* Finally start the DMA */
+	I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(UOS_MOVE | START_DMA));
+
+	/* NB: Docs recommend not using the interrupt for completion.
+	 * FIXME: what's a valid timeout? */
+	ret = wait_for_atomic(i915_guc_get_status(dev_priv, &status), 10);
+
+	DRM_DEBUG_DRIVER("DMA status = 0x%x, GuC status 0x%x\n",
+			I915_READ(DMA_CTRL), status);
+
+	return ret;
+}
+
+static u32 get_gttype(struct drm_device *dev)
+{
+	/* XXX: GT type based on PCI device ID? field seems unused by fw */
+	return 0;
+}
+
+static u32 get_core_family(struct drm_device *dev)
+{
+	switch (INTEL_INFO(dev)->gen) {
+	case 8:
+		return GFXCORE_FAMILY_GEN8;
+	case 9:
+		return GFXCORE_FAMILY_GEN9;
+	default:
+		DRM_ERROR("GUC: unknown gen for scheduler init\n");
+		return GFXCORE_FAMILY_FORCE_ULONG;
+	}
+}
+
+static void set_guc_init_params(struct drm_i915_private *dev_priv)
+{
+	u32 params[GUC_CTL_MAX_DWORDS];
+	int i;
+
+	memset(&params, 0, sizeof(params));
+
+	params[GUC_CTL_DEVICE_INFO] |=
+		(get_gttype(dev_priv->dev) << GUC_CTL_GTTYPE_SHIFT) |
+		(get_core_family(dev_priv->dev) << GUC_CTL_COREFAMILY_SHIFT);
+
+	/* GuC ARAT increment is 10 ns. GuC default scheduler quantum is one
+	 * second. This ARAR is calculated by:
+	 * Scheduler-Quantum-in-ns / ARAT-increment-in-ns = 1000000000 / 10
+	 */
+	params[GUC_CTL_ARAT_HIGH] = 0;
+	params[GUC_CTL_ARAT_LOW] = 100000000;
+
+	params[GUC_CTL_WA] |= GUC_CTL_WA_UK_BY_DRIVER;
+
+	params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
+			GUC_CTL_VCS2_ENABLED;
+
+	/* XXX: Set up log buffer */
+
+	I915_WRITE(SOFT_SCRATCH(0), 0);
+
+	for (i = 0; i < GUC_CTL_MAX_DWORDS; i++)
+		I915_WRITE(SOFT_SCRATCH(1 + i), params[i]);
+}
+
+/**
+ * Loads the GuC firmware blob in to the MinuteIA.
+ */
+static int guc_load_ucode(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
+	bool pinned = false;
+	int ret;
+
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+	ret = i915_gem_obj_ggtt_pin(guc_fw->uc_fw_obj, 0, 0);
+	if (ret)
+		goto out;
+	pinned = true;
+
+	/* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
+	I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+
+	/* Set MMIO/WA for GuC init */
+
+	/* Enable MIA caching. GuC clock gating is disabled. */
+	I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE);
+
+	/* WaC6DisallowByGfxPause*/
+	I915_WRITE(GEN6_GFXPAUSE, 0x30FFF);
+
+	if (IS_GEN9(dev)) {
+		/* DOP Clock Gating Enable for GuC clocks */
+		I915_WRITE(GEN7_MISCCPCTL, (GEN8_DOP_CLOCK_GATE_GUC_ENABLE |
+					    I915_READ(GEN7_MISCCPCTL)));
+
+		/* allows for 5us before GT can go to RC6 */
+		I915_WRITE(GUC_ARAT_C6DIS, 0x1FF);
+	}
+
+	/* Copy RSA signature from the fw image to HW for verification */
+	ret = copy_rsa(dev_priv);
+	if (ret)
+		goto out;
+
+	set_guc_init_params(dev_priv);
+
+	/* FIXME: !UPSTREAM - I don't have real keys, so we need to disable the
+	 * authentication. This can only work if the part is fused in a special
+	 * configuration. Therefore, even if it leaked externally, it won't be
+	 * detrimental to security
+	 */
+	I915_WRITE(0xc068, 0x3);
+
+	ret = ucode_dma_xfer_sync(dev_priv);
+
+	/* We can free the object pages now, and we would, except we might as
+	 * well keep it around for suspend/resume. Instead, we just wait for the
+	 * DMA to complete, and unpin the object
+	 */
+
+out:
+	DRM_DEBUG_DRIVER("return %d, pinned %d\n", ret, pinned);
+
+	if (pinned)
+		i915_gem_object_ggtt_unpin(guc_fw->uc_fw_obj);
+
+	return ret;
+}
+
+/*
+ * Called from gem_init_hw() during driver loading and also after a GPU reset.
+ * Check that the firmware fetching process has succeeded, and if so transfer
+ * the loaded image to the hardware.
+ */
+int intel_guc_load_ucode(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
+	int err;
+
+	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_NONE;
+	if (guc_fw->uc_fw_fetch_status == INTEL_UC_FIRMWARE_NONE)
+		return 0;
+
+	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_PENDING;
+	err = intel_uc_fw_check(dev, guc_fw);
+	if (err)
+		goto fail;
+
+	err = guc_load_ucode(dev);
+	if (err)
+		goto fail;
+
+	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_SUCCESS;
+	return 0;
+
+fail:
+	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_FAIL;
+	return err;
+}
+
+void intel_guc_ucode_init(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
+	const char *path = NULL;
+
+	if (IS_GEN8(dev))
+		path = I915_GUC_UCODE_GEN8;
+	else if (IS_GEN9(dev))
+		path = I915_GUC_UCODE_GEN9;
+
+	intel_uc_fw_init(dev, guc_fw, "GuC", path, HAS_GUC_UCODE(dev));
+}
+
+void intel_guc_ucode_fini(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
+
+	intel_uc_fw_fini(dev, guc_fw);
+}
-- 
1.9.1

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

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

* [PATCH 05/18] drm/i915: Add firmware version check
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (3 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 04/18] drm/i915: GuC firmware loader yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 06/18] drm/i915: Defer default hardware context initialisation until first open yu.dai
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

Set the firmware version that required by HW. Driver sets required
version according to platform. After firmware is loaded but before
send to HW, the major.minor version is read from CSS header field,
which is 17th DWORD currently. The major version must be same; the
minor version must be newer than required.

Currently the GuC fw version is 1.0.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/intel_guc.h        |  1 +
 drivers/gpu/drm/i915/intel_guc_loader.c | 41 +++++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_uc_loader.c  |  6 ++++-
 drivers/gpu/drm/i915/intel_uc_loader.h  |  4 ++++
 4 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index d8e7c00..a06a7b3 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -50,6 +50,7 @@ struct intel_guc {
 
 #define UOS_RSA_SCRATCH_0	0xc200
 #define   UOS_RSA_SIG_SIZE	0x100
+#define   UOS_VERSION_OFFSET	0x11
 #define DMA_ADDR_0_LOW		0xc300
 #define DMA_ADDR_0_HIGH		0xc304
 #define DMA_ADDR_1_LOW		0xc308
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 91af710..b9923b7 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -248,16 +248,53 @@ fail:
 	return err;
 }
 
+/*
+ * Check the firmware that was found; return TRUE if acceptable.
+ *
+ * For the GuC, we just check the version number embedded at a well-known
+ * offset within the firmware blob; note that UOS_RSA_SIG_SIZE is given
+ * in *bytes*, whereas UOS_VERSION_OFFSET is in DWords!
+ */
+static bool intel_guc_ucode_check(struct intel_uc_fw *guc_fw)
+{
+	uint32_t *data = (void *)(guc_fw->uc_fw_blob->data + UOS_RSA_SIG_SIZE);
+	uint32_t version, major, minor;
+
+	version = data[UOS_VERSION_OFFSET];
+	major = version >> 16;
+	minor = version & 0xFFFF;
+
+	if (major == guc_fw->uc_fw_ver_major &&
+	    minor >= guc_fw->uc_fw_ver_minor) {
+		DRM_DEBUG_DRIVER("firmware version %d.%d OK (minimum %d.%d)\n",
+			 major, minor,
+			 guc_fw->uc_fw_ver_major, guc_fw->uc_fw_ver_minor);
+		return true;
+	}
+
+	DRM_ERROR("GuC firmware version %d.%d, required %d.%d\n",
+		 major, minor,
+		 guc_fw->uc_fw_ver_major, guc_fw->uc_fw_ver_minor);
+	return false;
+}
+
 void intel_guc_ucode_init(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 	const char *path = NULL;
 
-	if (IS_GEN8(dev))
+	if (IS_GEN8(dev)) {
 		path = I915_GUC_UCODE_GEN8;
-	else if (IS_GEN9(dev))
+		guc_fw->uc_fw_ver_major = 1;
+		guc_fw->uc_fw_ver_minor = 0;
+		guc_fw->uc_fw_check = intel_guc_ucode_check;
+	} else if (IS_GEN9(dev)) {
 		path = I915_GUC_UCODE_GEN9;
+		guc_fw->uc_fw_ver_major = 1;
+		guc_fw->uc_fw_ver_minor = 0;
+		guc_fw->uc_fw_check = intel_guc_ucode_check;
+	}
 
 	intel_uc_fw_init(dev, guc_fw, "GuC", path, HAS_GUC_UCODE(dev));
 }
diff --git a/drivers/gpu/drm/i915/intel_uc_loader.c b/drivers/gpu/drm/i915/intel_uc_loader.c
index 249e56e..986dcf3 100644
--- a/drivers/gpu/drm/i915/intel_uc_loader.c
+++ b/drivers/gpu/drm/i915/intel_uc_loader.c
@@ -49,10 +49,12 @@ static void uc_fw_finish(struct drm_device *dev, struct intel_uc_fw *uc_fw)
 		uc_fw->uc_name, uc_fw->uc_fw_fetch_status, uc_fw->uc_fw_blob);
 
 	fw = uc_fw->uc_fw_blob;
-	uc_fw->uc_fw_blob = NULL;
 	if (!fw)
 		goto fail;
 
+	if (uc_fw->uc_fw_check && !uc_fw->uc_fw_check(uc_fw))
+		goto fail;
+
 	obj = i915_gem_alloc_object(dev, round_up(fw->size, PAGE_SIZE));
 	if (!obj)
 		goto fail;
@@ -64,6 +66,7 @@ static void uc_fw_finish(struct drm_device *dev, struct intel_uc_fw *uc_fw)
 	uc_fw->uc_fw_obj = obj;
 	uc_fw->uc_fw_size = fw->size;
 	uc_fw->uc_fw_fetch_status = INTEL_UC_FIRMWARE_SUCCESS;
+	uc_fw->uc_fw_blob = NULL;
 	release_firmware(fw);
 	return;
 
@@ -77,6 +80,7 @@ fail:
 		drm_gem_object_unreference(&obj->base);
 
 	uc_fw->uc_fw_fetch_status = INTEL_UC_FIRMWARE_FAIL;
+	uc_fw->uc_fw_blob = NULL;
 	release_firmware(fw);		/* OK even if fw is NULL */
 }
 
diff --git a/drivers/gpu/drm/i915/intel_uc_loader.h b/drivers/gpu/drm/i915/intel_uc_loader.h
index 661d46a..31bf65c 100644
--- a/drivers/gpu/drm/i915/intel_uc_loader.h
+++ b/drivers/gpu/drm/i915/intel_uc_loader.h
@@ -68,11 +68,15 @@ struct intel_uc_fw {
 	struct drm_i915_gem_object *	uc_fw_obj;
 	enum intel_uc_fw_status		uc_fw_fetch_status;
 	enum intel_uc_fw_status		uc_fw_load_status;
+	uint32_t			uc_fw_ver_major;
+	uint32_t			uc_fw_ver_minor;
+	bool				(*uc_fw_check)(struct intel_uc_fw *);
 };
 
 void intel_uc_fw_init(struct drm_device *dev, struct intel_uc_fw *uc_fw,
 	const char *uc_name, const char *fw_path, bool has_ucode);
 int intel_uc_fw_check(struct drm_device *dev, struct intel_uc_fw *uc_fw);
 void intel_uc_fw_fini(struct drm_device *dev, struct intel_uc_fw *uc_fw);
+bool intel_uc_fw_version_check(struct intel_uc_fw *fw, const char *data);
 
 #endif
-- 
1.9.1

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

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

* [PATCH 06/18] drm/i915: Defer default hardware context initialisation until first open
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (4 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 05/18] drm/i915: Add firmware version check yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-27  8:45   ` Daniel Vetter
  2015-03-26 19:41 ` [PATCH 07/18] drm/i915: Move execlists defines from .c to .h yu.dai
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Dave Gordon <david.s.gordon@intel.com>

In order to fully initialise the default contexts, we have to execute
batchbuffer commands on the GPU engines. But we can't do that until any
required firmware has been loaded, which may not be possible during
driver load, because the filesystem(s) containing the firmware may not
be mounted until later.

Therefore, we now allow the first call to the firmware-loading code to
return -EAGAIN to indicate that it's not yet ready, and that it should
be retried when the device is first opened from user code, by which
time we expect that all required filesystems will have been mounted.
The late-retry code will then re-attempt to load the firmware if the
early attempt failed.

Issue: VIZ-4884
Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h         |  1 +
 drivers/gpu/drm/i915/i915_gem.c         |  9 ++++++++-
 drivers/gpu/drm/i915/i915_gem_context.c | 35 ++++++++++++++++++++++++++++-----
 drivers/gpu/drm/i915/intel_guc.h        |  2 +-
 drivers/gpu/drm/i915/intel_guc_loader.c | 22 ++++++++++++++++++---
 drivers/gpu/drm/i915/intel_uc_loader.c  | 12 +++++++++--
 6 files changed, 69 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1a60f86..45bdf30 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1755,6 +1755,7 @@ struct drm_i915_private {
 	/* hda/i915 audio component */
 	bool audio_component_registered;
 
+	bool contexts_ready;
 	uint32_t hw_context_size;
 	struct list_head context_list;
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 38e49d9..0037ccf 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4828,8 +4828,15 @@ i915_gem_init_hw(struct drm_device *dev)
 		i915_gem_cleanup_ringbuffer(dev);
 	}
 
+	/* We can't enable contexts until all firmware is loaded */
+	ret = intel_guc_load_ucode(dev, false);
+	if (ret == -EAGAIN)
+		return 0;		/* too early */
+
 	ret = i915_gem_context_enable(dev_priv);
-	if (ret && ret != -EIO) {
+	if (ret == 0) {
+		dev_priv->contexts_ready = true;
+	} else if (ret && ret != -EIO) {
 		DRM_ERROR("Context enable failed %d\n", ret);
 		i915_gem_cleanup_ringbuffer(dev);
 
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index f3e84c4..2353d8f 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -445,23 +445,48 @@ static int context_idr_cleanup(int id, void *p, void *data)
 	return 0;
 }
 
+/* Complete any late initialisation here */
+static int i915_gem_context_first_open(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	/* We can't enable contexts until all firmware is loaded */
+	ret = intel_guc_load_ucode(dev, true);
+	WARN_ON(ret == -EAGAIN);
+
+	ret = i915_gem_context_enable(dev_priv);
+	if (ret == 0)
+		dev_priv->contexts_ready = true;
+	return ret;
+}
+
 int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_file_private *file_priv = file->driver_priv;
 	struct intel_context *ctx;
+	int ret = 0;
 
 	idr_init(&file_priv->context_idr);
 
 	mutex_lock(&dev->struct_mutex);
-	ctx = i915_gem_create_context(dev, file_priv);
+
+	if (!dev_priv->contexts_ready)
+		ret = i915_gem_context_first_open(dev);
+
+	if (ret == 0) {
+		ctx = i915_gem_create_context(dev, file_priv);
+		if (IS_ERR(ctx))
+			ret = PTR_ERR(ctx);
+	}
+
 	mutex_unlock(&dev->struct_mutex);
 
-	if (IS_ERR(ctx)) {
+	if (ret)
 		idr_destroy(&file_priv->context_idr);
-		return PTR_ERR(ctx);
-	}
 
-	return 0;
+	return ret;
 }
 
 void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index a06a7b3..d8262cf 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -89,7 +89,7 @@ struct intel_guc {
 				 GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA)
 
 /* intel_guc_loader.c */
-extern int intel_guc_load_ucode(struct drm_device *dev);
+extern int intel_guc_load_ucode(struct drm_device *dev, bool wait);
 extern void intel_guc_ucode_fini(struct drm_device *dev);
 extern void intel_guc_ucode_init(struct drm_device *dev);
 
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index b9923b7..315e5d9 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -217,25 +217,41 @@ out:
 }
 
 /*
- * Called from gem_init_hw() during driver loading and also after a GPU reset.
  * Check that the firmware fetching process has succeeded, and if so transfer
  * the loaded image to the hardware.
+ *
+ * However, there are a few checks to do first. The very first call should have
+ * (wait == FALSE), but the fetch_state will still be PENDING as the firmware may
+ * not be available that early. Therefore, on this first call, we just return.
+ *
+ * The second call should come from the first open of the device (wait == TRUE).
+ * This is a good time to load the firmware into the device, as by this point it
+ * must be available.
+ *
+ * Any subsequent calls are expected to have wait == FALSE, and indicate that the
+ * hardware has been reset and so the firmware should be reloaded.
  */
-int intel_guc_load_ucode(struct drm_device *dev)
+int intel_guc_load_ucode(struct drm_device *dev, bool wait)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 	int err;
 
+	DRM_DEBUG_DRIVER("GuC: wait %d, fetch status %d, load status %d\n",
+		wait, guc_fw->uc_fw_fetch_status, guc_fw->uc_fw_load_status);
+
+	if (guc_fw->uc_fw_fetch_status == INTEL_UC_FIRMWARE_PENDING && !wait)
+		return -EAGAIN;
+
 	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_NONE;
 	if (guc_fw->uc_fw_fetch_status == INTEL_UC_FIRMWARE_NONE)
 		return 0;
 
-	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_PENDING;
 	err = intel_uc_fw_check(dev, guc_fw);
 	if (err)
 		goto fail;
 
+	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_PENDING;
 	err = guc_load_ucode(dev);
 	if (err)
 		goto fail;
diff --git a/drivers/gpu/drm/i915/intel_uc_loader.c b/drivers/gpu/drm/i915/intel_uc_loader.c
index 986dcf3..bc4b1e5 100644
--- a/drivers/gpu/drm/i915/intel_uc_loader.c
+++ b/drivers/gpu/drm/i915/intel_uc_loader.c
@@ -49,8 +49,16 @@ static void uc_fw_finish(struct drm_device *dev, struct intel_uc_fw *uc_fw)
 		uc_fw->uc_name, uc_fw->uc_fw_fetch_status, uc_fw->uc_fw_blob);
 
 	fw = uc_fw->uc_fw_blob;
-	if (!fw)
-		goto fail;
+	if (!fw) {
+		/* no firmware found; try again in case FS was not mounted */
+		DRM_DEBUG_DRIVER("retry fetching %s fw from <%s>\n",
+			uc_fw->uc_name, uc_fw->uc_fw_path);
+		if (request_firmware(&fw, uc_fw->uc_fw_path, &dev->pdev->dev))
+			goto fail;
+		DRM_DEBUG_DRIVER("fetch %s fw from <%s> succeeded, fw %p\n",
+			uc_fw->uc_name, uc_fw->uc_fw_path, fw);
+		uc_fw->uc_fw_blob = fw;
+	}
 
 	if (uc_fw->uc_fw_check && !uc_fw->uc_fw_check(uc_fw))
 		goto fail;
-- 
1.9.1

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

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

* [PATCH 07/18] drm/i915: Move execlists defines from .c to .h
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (5 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 06/18] drm/i915: Defer default hardware context initialisation until first open yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 08/18] drm/i915: Make several execlist helper functions external yu.dai
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Michael H. Nguyen

From: "Michael H. Nguyen" <michael.h.nguyen@intel.com>

Move defines from intel_lrc.c to i915_reg.h so they are
accessible by the guc files

Issue: VIZ-4884
Signed-off-by: Michael H. Nguyen <michael.h.nguyen@intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h  | 68 ++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.c | 67 ---------------------------------------
 2 files changed, 68 insertions(+), 67 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index dfd1eb4..651343d 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7323,4 +7323,72 @@ enum skl_disp_power_wells {
 #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
 #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
 
+/* Exec Lists */
+#define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
+#define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
+#define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE)
+
+#define RING_EXECLIST_QFULL		(1 << 0x2)
+#define RING_EXECLIST1_VALID		(1 << 0x3)
+#define RING_EXECLIST0_VALID		(1 << 0x4)
+#define RING_EXECLIST_ACTIVE_STATUS	(3 << 0xE)
+#define RING_EXECLIST1_ACTIVE		(1 << 0x11)
+#define RING_EXECLIST0_ACTIVE		(1 << 0x12)
+
+#define GEN8_CTX_STATUS_IDLE_ACTIVE	(1 << 0)
+#define GEN8_CTX_STATUS_PREEMPTED	(1 << 1)
+#define GEN8_CTX_STATUS_ELEMENT_SWITCH	(1 << 2)
+#define GEN8_CTX_STATUS_ACTIVE_IDLE	(1 << 3)
+#define GEN8_CTX_STATUS_COMPLETE	(1 << 4)
+#define GEN8_CTX_STATUS_LITE_RESTORE	(1 << 15)
+
+#define CTX_LRI_HEADER_0		0x01
+#define CTX_CONTEXT_CONTROL		0x02
+#define CTX_RING_HEAD			0x04
+#define CTX_RING_TAIL			0x06
+#define CTX_RING_BUFFER_START		0x08
+#define CTX_RING_BUFFER_CONTROL		0x0a
+#define CTX_BB_HEAD_U			0x0c
+#define CTX_BB_HEAD_L			0x0e
+#define CTX_BB_STATE			0x10
+#define CTX_SECOND_BB_HEAD_U		0x12
+#define CTX_SECOND_BB_HEAD_L		0x14
+#define CTX_SECOND_BB_STATE		0x16
+#define CTX_BB_PER_CTX_PTR		0x18
+#define CTX_RCS_INDIRECT_CTX		0x1a
+#define CTX_RCS_INDIRECT_CTX_OFFSET	0x1c
+#define CTX_LRI_HEADER_1		0x21
+#define CTX_CTX_TIMESTAMP		0x22
+#define CTX_PDP3_UDW			0x24
+#define CTX_PDP3_LDW			0x26
+#define CTX_PDP2_UDW			0x28
+#define CTX_PDP2_LDW			0x2a
+#define CTX_PDP1_UDW			0x2c
+#define CTX_PDP1_LDW			0x2e
+#define CTX_PDP0_UDW			0x30
+#define CTX_PDP0_LDW			0x32
+#define CTX_LRI_HEADER_2		0x41
+#define CTX_R_PWR_CLK_STATE		0x42
+#define CTX_GPGPU_CSR_BASE_ADDRESS	0x44
+
+#define GEN8_CTX_VALID (1<<0)
+#define GEN8_CTX_FORCE_PD_RESTORE (1<<1)
+#define GEN8_CTX_FORCE_RESTORE (1<<2)
+#define GEN8_CTX_L3LLC_COHERENT (1<<5)
+#define GEN8_CTX_PRIVILEGE (1<<8)
+enum {
+	ADVANCED_CONTEXT = 0,
+	LEGACY_CONTEXT,
+	ADVANCED_AD_CONTEXT,
+	LEGACY_64B_CONTEXT
+};
+#define GEN8_CTX_MODE_SHIFT 3
+enum {
+	FAULT_AND_HANG = 0,
+	FAULT_AND_HALT, /* Debug only */
+	FAULT_AND_STREAM,
+	FAULT_AND_CONTINUE /* Unsupported */
+};
+#define GEN8_CTX_ID_SHIFT 32
+
 #endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index fcb074b..f259359 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -136,73 +136,6 @@
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
-#define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
-#define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
-#define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE)
-
-#define RING_EXECLIST_QFULL		(1 << 0x2)
-#define RING_EXECLIST1_VALID		(1 << 0x3)
-#define RING_EXECLIST0_VALID		(1 << 0x4)
-#define RING_EXECLIST_ACTIVE_STATUS	(3 << 0xE)
-#define RING_EXECLIST1_ACTIVE		(1 << 0x11)
-#define RING_EXECLIST0_ACTIVE		(1 << 0x12)
-
-#define GEN8_CTX_STATUS_IDLE_ACTIVE	(1 << 0)
-#define GEN8_CTX_STATUS_PREEMPTED	(1 << 1)
-#define GEN8_CTX_STATUS_ELEMENT_SWITCH	(1 << 2)
-#define GEN8_CTX_STATUS_ACTIVE_IDLE	(1 << 3)
-#define GEN8_CTX_STATUS_COMPLETE	(1 << 4)
-#define GEN8_CTX_STATUS_LITE_RESTORE	(1 << 15)
-
-#define CTX_LRI_HEADER_0		0x01
-#define CTX_CONTEXT_CONTROL		0x02
-#define CTX_RING_HEAD			0x04
-#define CTX_RING_TAIL			0x06
-#define CTX_RING_BUFFER_START		0x08
-#define CTX_RING_BUFFER_CONTROL		0x0a
-#define CTX_BB_HEAD_U			0x0c
-#define CTX_BB_HEAD_L			0x0e
-#define CTX_BB_STATE			0x10
-#define CTX_SECOND_BB_HEAD_U		0x12
-#define CTX_SECOND_BB_HEAD_L		0x14
-#define CTX_SECOND_BB_STATE		0x16
-#define CTX_BB_PER_CTX_PTR		0x18
-#define CTX_RCS_INDIRECT_CTX		0x1a
-#define CTX_RCS_INDIRECT_CTX_OFFSET	0x1c
-#define CTX_LRI_HEADER_1		0x21
-#define CTX_CTX_TIMESTAMP		0x22
-#define CTX_PDP3_UDW			0x24
-#define CTX_PDP3_LDW			0x26
-#define CTX_PDP2_UDW			0x28
-#define CTX_PDP2_LDW			0x2a
-#define CTX_PDP1_UDW			0x2c
-#define CTX_PDP1_LDW			0x2e
-#define CTX_PDP0_UDW			0x30
-#define CTX_PDP0_LDW			0x32
-#define CTX_LRI_HEADER_2		0x41
-#define CTX_R_PWR_CLK_STATE		0x42
-#define CTX_GPGPU_CSR_BASE_ADDRESS	0x44
-
-#define GEN8_CTX_VALID (1<<0)
-#define GEN8_CTX_FORCE_PD_RESTORE (1<<1)
-#define GEN8_CTX_FORCE_RESTORE (1<<2)
-#define GEN8_CTX_L3LLC_COHERENT (1<<5)
-#define GEN8_CTX_PRIVILEGE (1<<8)
-enum {
-	ADVANCED_CONTEXT = 0,
-	LEGACY_CONTEXT,
-	ADVANCED_AD_CONTEXT,
-	LEGACY_64B_CONTEXT
-};
-#define GEN8_CTX_MODE_SHIFT 3
-enum {
-	FAULT_AND_HANG = 0,
-	FAULT_AND_HALT, /* Debug only */
-	FAULT_AND_STREAM,
-	FAULT_AND_CONTINUE /* Unsupported */
-};
-#define GEN8_CTX_ID_SHIFT 32
-
 static int intel_lr_context_pin(struct intel_engine_cs *ring,
 		struct intel_context *ctx);
 
-- 
1.9.1

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

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

* [PATCH 08/18] drm/i915: Make several execlist helper functions external
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (6 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 07/18] drm/i915: Move execlists defines from .c to .h yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 09/18] drm/i915: Add functions to allocate / release gem obj for GuC yu.dai
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

These functions will be used by GuC scheduler.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/intel_lrc.c | 6 +++---
 drivers/gpu/drm/i915/intel_lrc.h | 3 +++
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index f259359..2c18d59 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -187,8 +187,8 @@ u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj)
 	return lrca >> 12;
 }
 
-static uint64_t execlists_ctx_descriptor(struct intel_engine_cs *ring,
-					 struct drm_i915_gem_object *ctx_obj)
+uint64_t execlists_ctx_descriptor(struct intel_engine_cs *ring,
+				  struct drm_i915_gem_object *ctx_obj)
 {
 	struct drm_device *dev = ring->dev;
 	uint64_t desc;
@@ -1761,7 +1761,7 @@ void intel_lr_context_free(struct intel_context *ctx)
 	}
 }
 
-static uint32_t get_lr_context_size(struct intel_engine_cs *ring)
+uint32_t get_lr_context_size(struct intel_engine_cs *ring)
 {
 	int ret = 0;
 
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index adb731e4..d4e8378 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -68,6 +68,7 @@ int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
 			     int num_dwords);
 
 /* Logical Ring Contexts */
+uint32_t get_lr_context_size(struct intel_engine_cs *ring);
 void intel_lr_context_free(struct intel_context *ctx);
 int intel_lr_context_deferred_create(struct intel_context *ctx,
 				     struct intel_engine_cs *ring);
@@ -86,6 +87,8 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
 			       struct drm_i915_gem_object *batch_obj,
 			       u64 exec_start, u32 dispatch_flags);
 u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
+uint64_t execlists_ctx_descriptor(struct intel_engine_cs *ring,
+				  struct drm_i915_gem_object *ctx_obj);
 
 void intel_lrc_irq_handler(struct intel_engine_cs *ring);
 void intel_execlists_retire_requests(struct intel_engine_cs *ring);
-- 
1.9.1

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

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

* [PATCH 09/18] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (7 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 08/18] drm/i915: Make several execlist helper functions external yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-27  8:48   ` Daniel Vetter
  2015-03-26 19:41 ` [PATCH 10/18] drm/i915: Functions to support command submission via GuC yu.dai
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

All gem objects used by GuC are pinned to ggtt space out of range
[0, WOPCM size]. In GuC address space mapping, [0, WPOCM size] is
used internally for its Boot ROM, SRAM etc. Currently this WPOCM
size is 512K. This is done by using of PIN_OFFSET_BIAS.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/intel_guc.h        |  3 +++
 drivers/gpu/drm/i915/intel_guc_loader.c | 34 +++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index d8262cf..ae14c57 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -92,5 +92,8 @@ struct intel_guc {
 extern int intel_guc_load_ucode(struct drm_device *dev, bool wait);
 extern void intel_guc_ucode_fini(struct drm_device *dev);
 extern void intel_guc_ucode_init(struct drm_device *dev);
+struct drm_i915_gem_object *
+intel_guc_allocate_gem_obj(struct drm_device *dev, u32 size);
+void intel_guc_release_gem_obj(struct drm_i915_gem_object *obj);
 
 #endif
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 315e5d9..0500a53 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -30,6 +30,40 @@
 MODULE_FIRMWARE(I915_GUC_UCODE_GEN8);
 MODULE_FIRMWARE(I915_GUC_UCODE_GEN9);
 
+struct drm_i915_gem_object *
+intel_guc_allocate_gem_obj(struct drm_device *dev, u32 size)
+{
+	struct drm_i915_gem_object *obj;
+
+	obj = i915_gem_alloc_object(dev, size);
+	if (!obj)
+		return NULL;
+
+	if (i915_gem_object_get_pages(obj)) {
+		drm_gem_object_unreference(&obj->base);
+		return NULL;
+	}
+
+	if (i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
+			PIN_OFFSET_BIAS | GUC_WOPCM_SIZE_VALUE)) {
+		drm_gem_object_unreference(&obj->base);
+		return NULL;
+	}
+
+	return obj;
+}
+
+void intel_guc_release_gem_obj(struct drm_i915_gem_object *obj)
+{
+	if (!obj)
+		return;
+
+	if (i915_gem_obj_is_pinned(obj))
+		i915_gem_object_ggtt_unpin(obj);
+
+	drm_gem_object_unreference(&obj->base);
+}
+
 static int copy_rsa(struct drm_i915_private *dev_priv)
 {
 	struct sg_table *st = dev_priv->guc.guc_fw.uc_fw_obj->pages;
-- 
1.9.1

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

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

* [PATCH 10/18] drm/i915: Functions to support command submission via GuC
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (8 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 09/18] drm/i915: Add functions to allocate / release gem obj for GuC yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 11/18] drm/i915: Integration of GuC client yu.dai
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

To enable GuC command submission / scheduling, we need to setup
firmware initializaion properly. i915.enable_guc_scheduling is
introduced to enable / disable GuC submission.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/Makefile              |  3 +-
 drivers/gpu/drm/i915/i915_drv.h            |  1 +
 drivers/gpu/drm/i915/i915_params.c         |  4 ++
 drivers/gpu/drm/i915/intel_guc.h           | 10 ++++
 drivers/gpu/drm/i915/intel_guc_loader.c    | 49 +++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_scheduler.c | 87 ++++++++++++++++++++++++++++++
 6 files changed, 153 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/intel_guc_scheduler.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 6188302..50b2057 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -37,7 +37,8 @@ i915-y += i915_cmd_parser.o \
 	  i915_trace_points.o \
 	  intel_lrc.o \
 	  intel_ringbuffer.o \
-	  intel_uncore.o
+	  intel_uncore.o \
+	  intel_guc_scheduler.o
 
 # ancilliary microcontroller support
 i915-y += intel_uc_loader.o \
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 45bdf30..72cc12a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2471,6 +2471,7 @@ struct i915_params {
 	bool reset;
 	bool disable_display;
 	bool disable_vtd_wa;
+	bool enable_guc_scheduling;
 	int use_mmio_flip;
 	int mmio_debug;
 	bool verbose_state_checks;
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index f3b8b62..a4743ed 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -52,6 +52,7 @@ struct i915_params i915 __read_mostly = {
 	.mmio_debug = 0,
 	.verbose_state_checks = 1,
 	.nuclear_pageflip = 0,
+	.enable_guc_scheduling = false,
 };
 
 module_param_named(modeset, i915.modeset, int, 0400);
@@ -178,3 +179,6 @@ MODULE_PARM_DESC(verbose_state_checks,
 module_param_named_unsafe(nuclear_pageflip, i915.nuclear_pageflip, bool, 0600);
 MODULE_PARM_DESC(nuclear_pageflip,
 		 "Force atomic modeset functionality; only planes work for now (default: false).");
+
+module_param_named(enable_guc_scheduling, i915.enable_guc_scheduling, bool, 0400);
+MODULE_PARM_DESC(enable_guc_scheduling, "Enable GuC scheduling (default:false)");
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index ae14c57..7eabadf 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -29,6 +29,9 @@
 
 struct intel_guc {
 	struct intel_uc_fw guc_fw;
+
+	/* GuC-specific additions */
+	struct drm_i915_gem_object *ctx_pool_obj;
 };
 
 #define GUC_STATUS		0xc000
@@ -96,4 +99,11 @@ struct drm_i915_gem_object *
 intel_guc_allocate_gem_obj(struct drm_device *dev, u32 size);
 void intel_guc_release_gem_obj(struct drm_i915_gem_object *obj);
 
+/* intel_guc_scheduler.c */
+int guc_scheduler_init(struct drm_device *dev);
+void guc_scheduler_fini(struct drm_device *dev);
+int guc_scheduler_enable(struct drm_device *dev);
+void guc_scheduler_disable(struct drm_device *dev);
+bool sanitize_enable_guc_scheduling(struct drm_device *dev);
+
 #endif
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 0500a53..c266be3 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -177,6 +177,34 @@ static void set_guc_init_params(struct drm_i915_private *dev_priv)
 
 	/* XXX: Set up log buffer */
 
+	/* If GuC scheduling is enabled, setup params here. */
+	if (i915.enable_guc_scheduling) {
+		u32 pgs = i915_gem_obj_ggtt_offset(dev_priv->guc.ctx_pool_obj);
+		u32 ctx_in_16 = MAX_GUC_GPU_CONTEXTS / 16;
+
+		pgs >>= PAGE_SHIFT;
+		params[GUC_CTL_CTXINFO] = (pgs << GUC_CTL_BASE_ADDR_SHIFT) |
+			(ctx_in_16 << GUC_CTL_CTXNUM_IN16_SHIFT);
+
+		/* The shared data is one page following the Ring Context.
+		 * So the offset is the page number of LRC */
+		pgs = get_lr_context_size(&dev_priv->ring[RCS]) >> PAGE_SHIFT;
+		params[GUC_CTL_OFFSET] |= pgs << GUC_CTL_SHARED_DATA_SHIFT;
+
+		/* This must be non-zero for scheduler to initialize even the
+		 * firmware doesn't use it. Be note that we use separated obj
+		 * for actual ring buffer, while firmware may treat this as an
+		 * offset from Ring Context base. We must take care of this if
+		 * firmware starts using this field.
+		 */
+		params[GUC_CTL_OFFSET] |= 1 << GUC_CTL_RING_BUFFER_SHIFT;
+
+		params[GUC_CTL_FEATURE] |= GUC_CTL_KERNEL_SUBMISSIONS;
+
+		/* Unmask this bit to enable GuC scheduler */
+		params[GUC_CTL_FEATURE] &= ~GUC_CTL_DISABLE_SCHEDULER;
+	}
+
 	I915_WRITE(SOFT_SCRATCH(0), 0);
 
 	for (i = 0; i < GUC_CTL_MAX_DWORDS; i++)
@@ -271,6 +299,8 @@ int intel_guc_load_ucode(struct drm_device *dev, bool wait)
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 	int err;
 
+	i915.enable_guc_scheduling = sanitize_enable_guc_scheduling(dev);
+
 	DRM_DEBUG_DRIVER("GuC: wait %d, fetch status %d, load status %d\n",
 		wait, guc_fw->uc_fw_fetch_status, guc_fw->uc_fw_load_status);
 
@@ -285,15 +315,32 @@ int intel_guc_load_ucode(struct drm_device *dev, bool wait)
 	if (err)
 		goto fail;
 
+	err = guc_scheduler_init(dev);
+	if (err)
+		goto fail;
+
 	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_PENDING;
 	err = guc_load_ucode(dev);
 	if (err)
 		goto fail;
 
+	err = guc_scheduler_enable(dev);
+	if (err)
+		goto fail;
+
 	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_SUCCESS;
 	return 0;
 
 fail:
+	guc_scheduler_disable(dev);
+
+	if (i915.enable_guc_scheduling) {
+		DRM_ERROR("Failed to initialize GuC, declaring GPU wedged\n");
+		atomic_set_mask(I915_WEDGED,
+				&dev_priv->gpu_error.reset_counter);
+		i915.enable_guc_scheduling = false;
+	}
+
 	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_FAIL;
 	return err;
 }
@@ -354,5 +401,7 @@ void intel_guc_ucode_fini(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 
+	guc_scheduler_fini(dev);
+
 	intel_uc_fw_fini(dev, guc_fw);
 }
diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
new file mode 100644
index 0000000..ed744fb
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#include <linux/firmware.h>
+#include "i915_drv.h"
+#include "intel_guc.h"
+
+void guc_scheduler_fini(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+	struct drm_i915_gem_object *ctx_pool = guc->ctx_pool_obj;
+
+	guc_scheduler_disable(dev);
+
+	if (ctx_pool) {
+		intel_guc_release_gem_obj(ctx_pool);
+		guc->ctx_pool_obj = NULL;
+	}
+}
+
+/* Set up the resources needed by the firmware scheduler. Currently this only
+ * requires one object that can be mapped through the GGTT.
+ */
+int guc_scheduler_init(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	const size_t ctxsize = sizeof(struct guc_context_desc);
+	const size_t poolsize = MAX_GUC_GPU_CONTEXTS * ctxsize;
+	const size_t gemsize = round_up(poolsize, PAGE_SIZE);
+	struct intel_guc *guc = &dev_priv->guc;
+
+	if (!i915.enable_guc_scheduling)
+		return 0; /* not enabled  */
+
+	if (guc->ctx_pool_obj)
+		return 0; /* already allocated */
+
+	guc->ctx_pool_obj = intel_guc_allocate_gem_obj(dev_priv->dev, gemsize);
+	if (!guc->ctx_pool_obj)
+		return -ENOMEM;
+
+	return 0;
+}
+
+int guc_scheduler_enable(struct drm_device *dev)
+{
+	if (!i915.enable_guc_scheduling)
+		return 0;
+
+	/* TODO: placeholder for guc scheduler enabling */
+	return 0;
+}
+
+void guc_scheduler_disable(struct drm_device *dev)
+{
+	/* TODO: placeholder for guc scheduler disabling */
+}
+
+bool sanitize_enable_guc_scheduling(struct drm_device *dev)
+{
+	if (!HAS_GUC_UCODE(dev) || !HAS_GUC_SCHED(dev))
+		return false;
+
+	return i915.enable_guc_scheduling;
+}
+
-- 
1.9.1

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

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

* [PATCH 11/18] drm/i915: Integration of GuC client
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (9 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 10/18] drm/i915: Functions to support command submission via GuC yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 12/18] drm/i915: Interrupt routing for GuC scheduler yu.dai
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

Implementation of GuC client. A GuC client has its own doorbell
and workqueue. It maintains the doorbell cache line, process
description object and work queue item.

A default guc_client is created to do the in-order legacy execlist
submission.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/Makefile              |   3 +-
 drivers/gpu/drm/i915/i915_drv.h            |   5 +
 drivers/gpu/drm/i915/intel_guc.h           |  52 ++++
 drivers/gpu/drm/i915/intel_guc_client.c    | 399 +++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_loader.c    |  14 +-
 drivers/gpu/drm/i915/intel_guc_scheduler.c |  29 ++-
 6 files changed, 492 insertions(+), 10 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/intel_guc_client.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 50b2057..0407720 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -42,7 +42,8 @@ i915-y += i915_cmd_parser.o \
 
 # ancilliary microcontroller support
 i915-y += intel_uc_loader.o \
-	  intel_guc_loader.o
+	  intel_guc_loader.o \
+	  intel_guc_client.o
 
 # autogenerated null render state
 i915-y += intel_renderstate_gen6.o \
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 72cc12a..ba5da95 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1847,6 +1847,11 @@ static inline struct drm_i915_private *dev_to_i915(struct device *dev)
 	return to_i915(dev_get_drvdata(dev));
 }
 
+static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
+{
+	return container_of(guc, struct drm_i915_private, guc);
+}
+
 /* Iterate over initialised rings */
 #define for_each_ring(ring__, dev_priv__, i__) \
 	for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 7eabadf..09508e0 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -27,11 +27,38 @@
 #include "intel_guc_api.h"
 #include "intel_uc_loader.h"
 
+#define GUC_DB_SIZE	PAGE_SIZE
+#define GUC_WQ_SIZE	(PAGE_SIZE * 2)
+
+struct i915_guc_client {
+	struct drm_i915_gem_object *client_obj;
+	u32 priority;
+	off_t doorbell_offset;
+	off_t proc_desc_offset;
+	off_t wq_offset;
+	uint16_t doorbell_id;
+	uint32_t ctx_index;
+	uint32_t wq_size;
+};
+
+#define I915_MAX_DOORBELLS	256
+#define INVALID_DOORBELL_ID	I915_MAX_DOORBELLS
+
+#define INVALID_CTX_ID		(MAX_GUC_GPU_CONTEXTS+1)
+
 struct intel_guc {
 	struct intel_uc_fw guc_fw;
 
 	/* GuC-specific additions */
+	spinlock_t host2guc_lock;
+
 	struct drm_i915_gem_object *ctx_pool_obj;
+
+	struct i915_guc_client *execbuf_client;
+
+	struct ida ctx_ids;
+	int db_cacheline;
+	DECLARE_BITMAP(doorbell_bitmap, I915_MAX_DOORBELLS);
 };
 
 #define GUC_STATUS		0xc000
@@ -91,6 +118,22 @@ struct intel_guc {
 				 GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA | \
 				 GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA)
 
+#define HOST2GUC_INTERRUPT	0xc4c8
+#define   HOST2GUC_TRIGGER	(1<<0)
+
+#define DRBMISC1		0x1984
+#define   DOORBELL_ENABLE	(1<<0)
+
+#define GEN8_DRBREGL(x) (0x1000 + (x) * 8)
+#define   GEN8_DRB_VALID (1<<0)
+#define GEN8_DRBREGU(x) (0x1000 + (x) * 8 + 4)
+
+#define GEN8_GT_PM_CONFIG		0x138140
+#define   GEN8_GT_DOORBELL_ENABLE	(1<<0)
+
+#define GEN8_GTCR		0x4274
+#define   GEN8_GTCR_INVALIDATE	(1<<0)
+
 /* intel_guc_loader.c */
 extern int intel_guc_load_ucode(struct drm_device *dev, bool wait);
 extern void intel_guc_ucode_fini(struct drm_device *dev);
@@ -106,4 +149,13 @@ int guc_scheduler_enable(struct drm_device *dev);
 void guc_scheduler_disable(struct drm_device *dev);
 bool sanitize_enable_guc_scheduling(struct drm_device *dev);
 
+/* intel_guc_client.c */
+struct i915_guc_client*
+i915_guc_client_alloc(struct drm_device *dev, u32 priority);
+void i915_guc_client_free(struct drm_device *dev,
+			  struct i915_guc_client *client);
+int i915_guc_client_submit(struct i915_guc_client *client,
+			   struct intel_context *ctx,
+			   struct intel_engine_cs *ring);
+
 #endif
diff --git a/drivers/gpu/drm/i915/intel_guc_client.c b/drivers/gpu/drm/i915/intel_guc_client.c
new file mode 100644
index 0000000..f7672ff
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_client.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#include <linux/firmware.h>
+#include "i915_drv.h"
+#include "intel_guc.h"
+
+/*
+ * Read GuC command/status register (SOFT_SCRATCH_0)
+ * Return true if it contains a response rather than a command
+ */
+static inline bool i915_guc_get_response(struct drm_i915_private *dev_priv,
+					 u32 *status)
+{
+	u32 val = I915_READ(SOFT_SCRATCH(0));
+	*status = val;
+	return GUC2HOST_IS_RESPONSE(val);
+}
+
+static int intel_guc_action(struct intel_guc *guc, u32 *data, u32 len)
+{
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	u32 status;
+	int i;
+	int ret;
+
+	if (WARN_ON(len < 1 || len > 15))
+		return -EINVAL;
+
+	spin_lock(&dev_priv->guc.host2guc_lock);
+
+	for (i = 0; i < len; i++)
+		I915_WRITE(SOFT_SCRATCH(i), data[i]);
+
+	POSTING_READ(SOFT_SCRATCH(i - 1));
+
+	I915_WRITE(HOST2GUC_INTERRUPT, HOST2GUC_TRIGGER);
+
+	ret = wait_for_atomic(i915_guc_get_response(dev_priv, &status), 10);
+	if (status != GUC2HOST_STATUS_SUCCESS) {
+		/* either GuC doesn't response, which is a TIMEOUT,
+		 * or a failure code is returned. */
+		if (ret != -ETIMEDOUT)
+			ret = -EIO;
+
+		DRM_ERROR("GUC: host2guc action 0x%X failed. ret=%d "
+				"status=0x%08X response=0x%08X\n",
+				data[0], ret, status,
+				I915_READ(SOFT_SCRATCH(15)));
+	}
+
+	spin_unlock(&dev_priv->guc.host2guc_lock);
+
+	return ret;
+}
+
+static void guc_release_ctx_desc(struct intel_guc *guc, uint32_t id)
+{
+	spin_lock(&guc->host2guc_lock);
+	ida_simple_remove(&guc->ctx_ids, id);
+	spin_unlock(&guc->host2guc_lock);
+}
+
+static uint32_t guc_assign_ctx_desc(struct intel_guc *guc)
+{
+	int id;
+
+	spin_lock(&guc->host2guc_lock);
+	id = ida_simple_get(&guc->ctx_ids, 0,
+			    MAX_GUC_GPU_CONTEXTS, GFP_KERNEL);
+	spin_unlock(&guc->host2guc_lock);
+
+	return (id < 0) ? INVALID_CTX_ID : (uint32_t)id;
+}
+
+static void guc_release_doorbell(struct intel_guc *guc, uint16_t id)
+{
+	spin_lock(&guc->host2guc_lock);
+	bitmap_clear(guc->doorbell_bitmap, id, 1);
+	spin_unlock(&guc->host2guc_lock);
+}
+
+static uint16_t guc_assign_doorbell(struct intel_guc *guc, u32 priority)
+{
+	const uint16_t size = I915_MAX_DOORBELLS;
+	uint16_t id;
+
+	spin_lock(&guc->host2guc_lock);
+
+	/* The bitmap is split into two halves - high and normal priority. */
+	if (priority <= GUC_CTX_PRIORITY_HIGH) {
+		id = find_next_zero_bit(guc->doorbell_bitmap, size, size / 2);
+		if (id == size)
+			id = INVALID_DOORBELL_ID;
+	} else {
+		id = find_next_zero_bit(guc->doorbell_bitmap, size / 2, 0);
+		if (id == size / 2)
+			id = INVALID_DOORBELL_ID;
+	}
+
+	if (id != INVALID_DOORBELL_ID)
+		bitmap_set(guc->doorbell_bitmap, id, 1);
+
+	spin_unlock(&guc->host2guc_lock);
+
+	return id;
+}
+
+static off_t guc_select_doorbell_cacheline(struct intel_guc *guc)
+{
+	const int cacheline_size = boot_cpu_data.x86_clflush_size;
+	const int cacheline_per_page = PAGE_SIZE / cacheline_size;
+	off_t offset;
+
+	spin_lock(&guc->host2guc_lock);
+
+	/* Doorbell uses single cache line */
+	offset = cacheline_size * guc->db_cacheline;
+
+	/* Moving to next cache line to reduce contention */
+	guc->db_cacheline = (guc->db_cacheline + 1) % cacheline_per_page;
+
+	spin_unlock(&guc->host2guc_lock);
+
+	return offset;
+}
+
+static void init_ctx_desc(struct intel_guc *guc,
+			  struct i915_guc_client *client)
+{
+	struct guc_context_desc desc;
+	struct sg_table *sg;
+
+	memset(&desc, 0, sizeof(desc));
+
+	desc.attribute = GUC_CTX_DESC_ATTR_ACTIVE | GUC_CTX_DESC_ATTR_KERNEL;
+	desc.context_id = client->ctx_index;
+	desc.priority = client->priority;
+	desc.engines_used = (1 << RCS) | (1 << VCS) | (1 << BCS) |
+			    (1 << VECS) | (1 << VCS2); /* all engines */
+	desc.db_id = client->doorbell_id;
+
+	/*
+	 * The CPU address is only needed at certain points, so kmap_atomic on
+	 * demand instead of storing it in the ctx descriptor.
+	 * XXX: May make debug easier to have it mapped
+	 */
+	desc.db_trigger_cpu = 0;
+	desc.db_trigger_uk = client->doorbell_offset +
+		i915_gem_obj_ggtt_offset(client->client_obj);
+	desc.db_trigger_phy = client->doorbell_offset +
+		sg_dma_address(client->client_obj->pages->sgl);
+
+	desc.process_desc = client->proc_desc_offset +
+		i915_gem_obj_ggtt_offset(client->client_obj);
+
+	desc.wq_addr = client->wq_offset +
+		i915_gem_obj_ggtt_offset(client->client_obj);
+
+	desc.wq_size = client->wq_size;
+
+	/*
+	 * XXX: Take LRCs from an existing intel_context if this is not an
+	 * IsKMDCreatedContext client
+	 */
+	desc.desc_private = (uintptr_t)client;
+
+	/* Pool context is pinned already */
+	sg = guc->ctx_pool_obj->pages;
+	sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
+			     sizeof(desc) * client->ctx_index);
+}
+
+static void fini_ctx_desc(struct intel_guc *guc,
+			  struct i915_guc_client *client)
+{
+	struct guc_context_desc desc;
+	struct sg_table *sg;
+
+	memset(&desc, 0, sizeof(desc));
+
+	sg = guc->ctx_pool_obj->pages;
+	sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
+			     sizeof(desc) * client->ctx_index);
+}
+
+static void init_proc_desc(struct intel_guc *guc,
+			   struct i915_guc_client *client)
+{
+	struct guc_process_desc *desc;
+	void *base;
+
+	base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
+	desc = base + client->proc_desc_offset;
+
+	memset(desc, 0, sizeof(*desc));
+
+	/*
+	 * XXX: pDoorbell and WQVBaseAddress are pointers in process address
+	 * space for ring3 clients (set them as in mmap_ioctl) or kernel
+	 * space for kernel clients (map on demand instead? May make debug
+	 * easier to have it mapped).
+	 */
+	desc->wq_base_addr = 0;
+	desc->db_base_addr = 0;
+
+	desc->context_id = client->ctx_index;
+	desc->wq_size_bytes = client->wq_size;
+	desc->wq_status = WQ_STATUS_ACTIVE;
+	desc->priority = client->priority;
+
+	kunmap_atomic(base);
+}
+
+static int host2guc_allocate_doorbell(struct intel_guc *guc,
+				      struct i915_guc_client *client)
+{
+	u32 data[2];
+
+	data[0] = HOST2GUC_ACTION_ALLOCATE_DOORBELL;
+	data[1] = client->ctx_index;
+
+	return intel_guc_action(guc, data, 2);
+}
+
+static int host2guc_release_doorbell(struct intel_guc *guc,
+				     struct i915_guc_client *client)
+{
+	u32 data[2];
+
+	data[0] = HOST2GUC_ACTION_DEALLOCATE_DOORBELL;
+	data[1] = client->ctx_index;
+
+	return intel_guc_action(guc, data, 2);
+}
+
+static void init_doorbell(struct intel_guc *guc,
+			  struct i915_guc_client *client)
+{
+	struct guc_doorbell_info *doorbell;
+	void *base;
+
+	base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
+	doorbell = base + client->doorbell_offset;
+
+	doorbell->db_status = 1;
+	doorbell->cookie = 0;
+
+	kunmap_atomic(base);
+}
+
+static void disable_doorbell(struct intel_guc *guc,
+			     struct i915_guc_client *client)
+{
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	struct guc_doorbell_info *doorbell;
+	void *base;
+	int drbreg = GEN8_DRBREGL(client->doorbell_id);
+	int value;
+
+	base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
+	doorbell = base + client->doorbell_offset;
+
+	doorbell->db_status = 0;
+
+	kunmap_atomic(base);
+
+	I915_WRITE(drbreg, I915_READ(drbreg) & ~GEN8_DRB_VALID);
+
+	value = I915_READ(drbreg);
+	WARN_ON((value & GEN8_DRB_VALID) != 0);
+
+	I915_WRITE(GEN8_DRBREGU(client->doorbell_id), 0);
+	I915_WRITE(drbreg, 0);
+
+	/* XXX: wait for any interrupts */
+	/* XXX: wait for workqueue to drain */
+}
+
+void i915_guc_client_free(struct drm_device *dev,
+			  struct i915_guc_client *client)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+
+	if (!client)
+		return;
+
+	if (client->doorbell_id != INVALID_DOORBELL_ID) {
+		disable_doorbell(guc, client);
+		host2guc_release_doorbell(guc, client);
+		guc_release_doorbell(guc, client->doorbell_id);
+	}
+
+	/*
+	 * XXX: wait for any outstanding submissions before freeing memory.
+	 * Be sure to drop any locks
+	 */
+
+	intel_guc_release_gem_obj(client->client_obj);
+
+	if (client->ctx_index != INVALID_CTX_ID) {
+		fini_ctx_desc(guc, client);
+		guc_release_ctx_desc(guc, client->ctx_index);
+	}
+
+	kfree(client);
+}
+
+struct i915_guc_client*
+i915_guc_client_alloc(struct drm_device *dev, u32 priority)
+{
+	struct i915_guc_client *client;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+	struct drm_i915_gem_object *obj;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return NULL;
+
+	client->doorbell_id = INVALID_DOORBELL_ID;
+	client->priority = priority;
+
+	client->ctx_index = guc_assign_ctx_desc(guc);
+	if (client->ctx_index == INVALID_CTX_ID)
+		goto err;
+
+	/* The first page is doorbell/proc_desc. Two followed pages are wq. */
+	obj = intel_guc_allocate_gem_obj(dev, GUC_DB_SIZE + GUC_WQ_SIZE);
+	if (!obj)
+		goto err;
+
+	client->client_obj = obj;
+	client->wq_offset = GUC_DB_SIZE;
+	client->wq_size = GUC_WQ_SIZE;
+
+	client->doorbell_offset = guc_select_doorbell_cacheline(guc);
+
+	/*
+	 * Since the doorbell only requires a single cacheline, we can save
+	 * space by putting the application process descriptor in the same
+	 * page. Use the half of the page that doesn't include the doorbell.
+	 */
+	if (client->doorbell_offset >= (GUC_DB_SIZE / 2))
+		client->proc_desc_offset = 0;
+	else
+		client->proc_desc_offset = (GUC_DB_SIZE / 2);
+
+	client->doorbell_id = guc_assign_doorbell(guc, client->priority);
+	if (client->doorbell_id == INVALID_DOORBELL_ID)
+		/* XXX: evict a doorbell instead */
+		goto err;
+
+	init_ctx_desc(guc, client);
+	init_proc_desc(guc, client);
+	init_doorbell(guc, client);
+
+	/* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
+	I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+
+	/* XXX: Any cache flushes needed? General domain mgmt calls? */
+
+	if (host2guc_allocate_doorbell(guc, client))
+		goto err;
+
+	return client;
+
+err:
+	i915_guc_client_free(dev, client);
+	return NULL;
+}
+
+int i915_guc_client_submit(struct i915_guc_client *client,
+			   struct intel_context *ctx,
+			   struct intel_engine_cs *ring)
+{
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index c266be3..58e1e33 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -233,12 +233,19 @@ static int guc_load_ucode(struct drm_device *dev)
 
 	/* Set MMIO/WA for GuC init */
 
+	I915_WRITE(DRBMISC1, DOORBELL_ENABLE);
+
 	/* Enable MIA caching. GuC clock gating is disabled. */
 	I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE);
 
 	/* WaC6DisallowByGfxPause*/
 	I915_WRITE(GEN6_GFXPAUSE, 0x30FFF);
 
+	if (IS_SKYLAKE(dev))
+		I915_WRITE(GEN9_GT_PM_CONFIG, GEN8_GT_DOORBELL_ENABLE);
+	else
+		I915_WRITE(GEN8_GT_PM_CONFIG, GEN8_GT_DOORBELL_ENABLE);
+
 	if (IS_GEN9(dev)) {
 		/* DOP Clock Gating Enable for GuC clocks */
 		I915_WRITE(GEN7_MISCCPCTL, (GEN8_DOP_CLOCK_GATE_GUC_ENABLE |
@@ -255,13 +262,6 @@ static int guc_load_ucode(struct drm_device *dev)
 
 	set_guc_init_params(dev_priv);
 
-	/* FIXME: !UPSTREAM - I don't have real keys, so we need to disable the
-	 * authentication. This can only work if the part is fused in a special
-	 * configuration. Therefore, even if it leaked externally, it won't be
-	 * detrimental to security
-	 */
-	I915_WRITE(0xc068, 0x3);
-
 	ret = ucode_dma_xfer_sync(dev_priv);
 
 	/* We can free the object pages now, and we would, except we might as
diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
index ed744fb..a78b4b3 100644
--- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -36,6 +36,8 @@ void guc_scheduler_fini(struct drm_device *dev)
 	if (ctx_pool) {
 		intel_guc_release_gem_obj(ctx_pool);
 		guc->ctx_pool_obj = NULL;
+
+		ida_destroy(&guc->ctx_ids);
 	}
 }
 
@@ -60,21 +62,44 @@ int guc_scheduler_init(struct drm_device *dev)
 	if (!guc->ctx_pool_obj)
 		return -ENOMEM;
 
+	spin_lock_init(&dev_priv->guc.host2guc_lock);
+
+	ida_init(&guc->ctx_ids);
+
+	memset(guc->doorbell_bitmap, 0, sizeof(guc->doorbell_bitmap));
+	guc->db_cacheline = 0;
+
 	return 0;
 }
 
 int guc_scheduler_enable(struct drm_device *dev)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+
 	if (!i915.enable_guc_scheduling)
 		return 0;
 
-	/* TODO: placeholder for guc scheduler enabling */
+	/* client for execbuf submission */
+	guc->execbuf_client =
+			i915_guc_client_alloc(dev, GUC_CTX_PRIORITY_NORMAL);
+	if (!guc->execbuf_client) {
+		DRM_ERROR("Failed to create execbuf guc_client\n");
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
 void guc_scheduler_disable(struct drm_device *dev)
 {
-	/* TODO: placeholder for guc scheduler disabling */
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+
+	if (guc->execbuf_client) {
+		i915_guc_client_free(dev, guc->execbuf_client);
+		guc->execbuf_client = NULL;
+	}
 }
 
 bool sanitize_enable_guc_scheduling(struct drm_device *dev)
-- 
1.9.1

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

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

* [PATCH 12/18] drm/i915: Interrupt routing for GuC scheduler
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (10 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 11/18] drm/i915: Integration of GuC client yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 13/18] drm/i915: Enable commands submission via GuC yu.dai
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

Turn on interrupt steering to route necessary interrupts to GuC.

Issue: VIZ-4884
Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h            | 11 ++++--
 drivers/gpu/drm/i915/intel_guc.h           |  7 ++++
 drivers/gpu/drm/i915/intel_guc_scheduler.c | 55 +++++++++++++++++++++++++++++-
 3 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 651343d..26b0e92 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1372,12 +1372,18 @@ enum skl_disp_power_wells {
 #define GFX_MODE_GEN7	0x0229c
 #define RING_MODE_GEN7(ring)	((ring)->mmio_base+0x29c)
 #define   GFX_RUN_LIST_ENABLE		(1<<15)
+#define   GFX_INTERRUPT_STEERING	(1<<14)
 #define   GFX_TLB_INVALIDATE_EXPLICIT	(1<<13)
 #define   GFX_SURFACE_FAULT_ENABLE	(1<<12)
 #define   GFX_REPLAY_MODE		(1<<11)
 #define   GFX_PSMI_GRANULARITY		(1<<10)
 #define   GFX_PPGTT_ENABLE		(1<<9)
 
+#define   GFX_FORWARD_VBLANK_MASK	(3<<5)
+#define   GFX_FORWARD_VBLANK_NEVER	(0<<5)
+#define   GFX_FORWARD_VBLANK_ALWAYS	(1<<5)
+#define   GFX_FORWARD_VBLANK_COND	(2<<5)
+
 #define VLV_DISPLAY_BASE 0x180000
 #define VLV_MIPI_BASE VLV_DISPLAY_BASE
 
@@ -5196,11 +5202,12 @@ enum skl_disp_power_wells {
 #define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
 #define GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
 
-#define GEN8_BCS_IRQ_SHIFT 16
 #define GEN8_RCS_IRQ_SHIFT 0
-#define GEN8_VCS2_IRQ_SHIFT 16
+#define GEN8_BCS_IRQ_SHIFT 16
 #define GEN8_VCS1_IRQ_SHIFT 0
+#define GEN8_VCS2_IRQ_SHIFT 16
 #define GEN8_VECS_IRQ_SHIFT 0
+#define GEN8_WD_IRQ_SHIFT 16
 
 #define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe)))
 #define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe)))
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 09508e0..3228c68 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -134,6 +134,13 @@ struct intel_guc {
 #define GEN8_GTCR		0x4274
 #define   GEN8_GTCR_INVALIDATE	(1<<0)
 
+#define DE_GUCRMR		0x44054
+
+#define GUC_BCS_RCS_IER		0xC550
+#define GUC_VCS2_VCS1_IER	0xC554
+#define GUC_WD_VECS_IER		0xC558
+#define GUC_PM_P24C_IER		0xC55C
+
 /* intel_guc_loader.c */
 extern int intel_guc_load_ucode(struct drm_device *dev, bool wait);
 extern void intel_guc_ucode_fini(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
index a78b4b3..008f74c 100644
--- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -25,6 +25,53 @@
 #include "i915_drv.h"
 #include "intel_guc.h"
 
+static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
+{
+	struct intel_engine_cs *ring;
+	int i, irqs;
+
+	/* tell all command streamers to forward interrupts and vblank to GuC */
+	irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_ALWAYS);
+	irqs |= _MASKED_BIT_ENABLE(GFX_INTERRUPT_STEERING);
+	for_each_ring(ring, dev_priv, i)
+		I915_WRITE(RING_MODE_GEN7(ring), irqs);
+
+	/* tell DE to send (all) flip_done to GuC */
+	irqs = DERRMR_PIPEA_PRI_FLIP_DONE | DERRMR_PIPEA_SPR_FLIP_DONE |
+	       DERRMR_PIPEB_PRI_FLIP_DONE | DERRMR_PIPEB_SPR_FLIP_DONE |
+	       DERRMR_PIPEC_PRI_FLIP_DONE | DERRMR_PIPEC_SPR_FLIP_DONE;
+	/* Unmasked bits will cause GuC response message to be sent */
+	I915_WRITE(DE_GUCRMR, ~irqs);
+
+	/* route USER_INTERRUPT to Host, all others are sent to GuC. */
+	irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+	       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+	/* These three registers have the same bit definitions */
+	I915_WRITE(GUC_BCS_RCS_IER, ~irqs);
+	I915_WRITE(GUC_VCS2_VCS1_IER, ~irqs);
+	I915_WRITE(GUC_WD_VECS_IER, ~irqs);
+}
+
+static void direct_interrupts_to_host(struct drm_i915_private *dev_priv)
+{
+	struct intel_engine_cs *ring;
+	int i, irqs;
+
+	/* tell all command streamers NOT to forward interrupts and vblank to GuC */
+	irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_NEVER);
+	irqs |= _MASKED_BIT_DISABLE(GFX_INTERRUPT_STEERING);
+	for_each_ring(ring, dev_priv, i)
+		I915_WRITE(RING_MODE_GEN7(ring), irqs);
+
+	/* tell DE to send nothing to GuC */
+	I915_WRITE(DE_GUCRMR, ~0);
+
+	/* route all GT interrupts to the host */
+	I915_WRITE(GUC_BCS_RCS_IER, 0);
+	I915_WRITE(GUC_VCS2_VCS1_IER, 0);
+	I915_WRITE(GUC_WD_VECS_IER, 0);
+}
+
 void guc_scheduler_fini(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -77,8 +124,10 @@ int guc_scheduler_enable(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_guc *guc = &dev_priv->guc;
 
-	if (!i915.enable_guc_scheduling)
+	if (!i915.enable_guc_scheduling) {
+		direct_interrupts_to_host(dev_priv);
 		return 0;
+	}
 
 	/* client for execbuf submission */
 	guc->execbuf_client =
@@ -88,6 +137,8 @@ int guc_scheduler_enable(struct drm_device *dev)
 		return -ENOMEM;
 	}
 
+	direct_interrupts_to_guc(dev_priv);
+
 	return 0;
 }
 
@@ -96,6 +147,8 @@ void guc_scheduler_disable(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_guc *guc = &dev_priv->guc;
 
+	direct_interrupts_to_host(dev_priv);
+
 	if (guc->execbuf_client) {
 		i915_guc_client_free(dev, guc->execbuf_client);
 		guc->execbuf_client = NULL;
-- 
1.9.1

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

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

* [PATCH 13/18] drm/i915: Enable commands submission via GuC
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (11 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 12/18] drm/i915: Interrupt routing for GuC scheduler yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 14/18] drm/i915: debugfs of GuC status yu.dai
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

Add functions to submit work queue item and ring the door bell.
GuC TLB needs to be invalided if LRC context changes.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/intel_guc.h           |   3 +
 drivers/gpu/drm/i915/intel_guc_client.c    | 175 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_guc_scheduler.c |   2 +-
 drivers/gpu/drm/i915/intel_lrc.c           |  16 ++-
 4 files changed, 193 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 3228c68..498789d 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -31,6 +31,7 @@
 #define GUC_WQ_SIZE	(PAGE_SIZE * 2)
 
 struct i915_guc_client {
+	spinlock_t wq_lock;
 	struct drm_i915_gem_object *client_obj;
 	u32 priority;
 	off_t doorbell_offset;
@@ -39,6 +40,8 @@ struct i915_guc_client {
 	uint16_t doorbell_id;
 	uint32_t ctx_index;
 	uint32_t wq_size;
+	uint32_t wq_tail;
+	uint32_t cookie;
 };
 
 #define I915_MAX_DOORBELLS	256
diff --git a/drivers/gpu/drm/i915/intel_guc_client.c b/drivers/gpu/drm/i915/intel_guc_client.c
index f7672ff..2415bfa 100644
--- a/drivers/gpu/drm/i915/intel_guc_client.c
+++ b/drivers/gpu/drm/i915/intel_guc_client.c
@@ -22,6 +22,7 @@
  *
  */
 #include <linux/firmware.h>
+#include <linux/circ_buf.h>
 #include "i915_drv.h"
 #include "intel_guc.h"
 
@@ -372,6 +373,8 @@ i915_guc_client_alloc(struct drm_device *dev, u32 priority)
 		/* XXX: evict a doorbell instead */
 		goto err;
 
+	spin_lock_init(&client->wq_lock);
+
 	init_ctx_desc(guc, client);
 	init_proc_desc(guc, client);
 	init_doorbell(guc, client);
@@ -391,9 +394,179 @@ err:
 	return NULL;
 }
 
+
+/* Get valid workqueue item and return it back to offset */
+static int get_workqueue_space(struct i915_guc_client *gc, u32 *offset)
+{
+	struct guc_process_desc *desc;
+	void *base;
+	u32 size = sizeof(struct guc_wq_item);
+	int ret = 0, timeout_counter = 200;
+	unsigned long flags;
+
+	base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, 0));
+	desc = base + gc->proc_desc_offset;
+
+	while (timeout_counter-- > 0) {
+		spin_lock_irqsave(&gc->wq_lock, flags);
+
+		ret = wait_for(CIRC_SPACE(gc->wq_tail, desc->head,
+			       gc->wq_size) >= size, 1);
+
+		if (!ret) {
+			*offset = gc->wq_tail;
+
+			/* advance the tail for next workqueue item */
+			gc->wq_tail += size;
+			gc->wq_tail &= gc->wq_size - 1;
+
+			/* this will break the loop */
+			timeout_counter = 0;
+		}
+
+		spin_unlock_irqrestore(&gc->wq_lock, flags);
+	};
+
+	kunmap_atomic(base);
+
+	return ret;
+}
+
+
+static int add_workqueue_item(struct i915_guc_client *gc,
+			      struct intel_context *ctx,
+			      struct intel_engine_cs *ring)
+{
+	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+	struct drm_i915_gem_object *ctx_obj;
+	struct guc_wq_item *wqi;
+	void *base;
+	struct page *page;
+	u32 wq_off = 0, tail = ringbuf->tail, wq_len;
+	int ret;
+
+	ctx_obj = ctx->engine[ring->id].state;
+
+	WARN_ON(!i915_gem_obj_is_pinned(ctx_obj));
+	WARN_ON(!i915_gem_obj_is_pinned(ringbuf->obj));
+
+	/* Need this because of the deferred pin ctx and ring */
+	/* Shall we move this right after ring is pinned? */
+	page = i915_gem_object_get_page(ctx_obj, 1);
+	base = kmap_atomic(page);
+
+	*((u32 *)base + CTX_RING_BUFFER_START + 1) =
+		i915_gem_obj_ggtt_offset(ringbuf->obj);
+
+	kunmap_atomic(base);
+
+	ret = get_workqueue_space(gc, &wq_off);
+	if (ret)
+		return ret;
+
+	/* For now workqueue item is 4 DWs; workqueue buffer is 2 pages. So we
+	 * should not have the case where structure wqi is across page, neither
+	 * wrapped to the beginning. This simplifies the implementation below.
+	 *
+	 * XXX: if not the case, we need save data to a temp wqi and copy it to
+	 * workqueue buffer dw by dw.
+	 */
+	WARN_ON(sizeof(struct guc_wq_item) != 16);
+	WARN_ON(wq_off & 3);
+
+	/* wq starts from the page after doorbell / process_desc */
+	base = kmap_atomic(i915_gem_object_get_page(gc->client_obj,
+			(wq_off + GUC_DB_SIZE) >> PAGE_SHIFT));
+	wq_off &= PAGE_SIZE - 1;
+	wqi = (struct guc_wq_item *)((char *)base + wq_off);
+
+	/* len does not include the header */
+	wq_len = sizeof(struct guc_wq_item) / sizeof(u32) - 1;
+	wqi->header = WQ_TYPE_INORDER |
+			(wq_len << WQ_LEN_SHIFT) |
+			(ring->id << WQ_TARGET_SHIFT) |
+			WQ_NO_WCFLUSH_WAIT;
+
+	wqi->context_desc = (u32)execlists_ctx_descriptor(ring, ctx_obj);
+	/* tail index is in qw */
+	tail >>= 3;
+	wqi->ring_tail = tail << WQ_RING_TAIL_SHIFT;
+	wqi->fence_id = 0; /*XXX: what fence to be here */
+
+	kunmap_atomic(base);
+
+	return 0;
+}
+
+static int ring_doorbell(struct i915_guc_client *gc)
+{
+	struct guc_process_desc *desc;
+	union guc_doorbell_qw db_cmp, db_exc, db_ret;
+	union guc_doorbell_qw *db;
+	void *base;
+	int attempt = 2, ret = -EAGAIN;
+
+	base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, 0));
+	desc = base + gc->proc_desc_offset;
+
+	/* Update the tail so it is visible to GuC */
+	desc->tail = gc->wq_tail;
+
+	/* current cookie */
+	db_cmp.db_status = GUC_DOORBELL_ENABLED;
+	db_cmp.cookie = gc->cookie;
+
+	/* cookie to be updated */
+	db_exc.db_status = GUC_DOORBELL_ENABLED;
+	db_exc.cookie = gc->cookie + 1;
+	if (db_exc.cookie == 0)
+		db_exc.cookie = 1;
+
+	/* pointer of current doorbell cacheline */
+	db = base + gc->doorbell_offset;
+
+	while (attempt--) {
+		/* lets ring the doorbell */
+		db_ret.value_qw = atomic64_cmpxchg((atomic64_t *)db,
+			db_cmp.value_qw, db_exc.value_qw);
+
+		/* if the exchange was successfully executed */
+		if (db_ret.value_qw == db_cmp.value_qw) {
+			/* db was successfully rung */
+			gc->cookie = db_exc.cookie;
+			ret = 0;
+			break;
+		}
+
+		/* XXX: doorbell was lost and need to acquire it again */
+		if (db_ret.db_status == GUC_DOORBELL_DISABLED)
+			break;
+
+		DRM_ERROR("Cookie mismatch. Expected %d, returned %d\n",
+			  db_cmp.cookie, db_ret.cookie);
+
+		/* update the cookie to newly read cookie from GuC */
+		db_cmp.cookie = db_ret.cookie;
+		db_exc.cookie = db_ret.cookie + 1;
+		if (db_exc.cookie == 0)
+			db_exc.cookie = 1;
+	}
+
+	kunmap_atomic(base);
+	return ret;
+}
+
 int i915_guc_client_submit(struct i915_guc_client *client,
 			   struct intel_context *ctx,
 			   struct intel_engine_cs *ring)
 {
-	return 0;
+	int ret;
+
+	ret = add_workqueue_item(client, ctx, ring);
+	if (ret)
+		return ret;
+
+	ret = ring_doorbell(client);
+
+	return ret;
 }
diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
index 008f74c..c0b7231 100644
--- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -160,6 +160,6 @@ bool sanitize_enable_guc_scheduling(struct drm_device *dev)
 	if (!HAS_GUC_UCODE(dev) || !HAS_GUC_SCHED(dev))
 		return false;
 
-	return i915.enable_guc_scheduling;
+	return i915.enable_execlists && i915.enable_guc_scheduling;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 2c18d59..967ebf7 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -735,13 +735,17 @@ intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf,
 				      struct drm_i915_gem_request *request)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 
 	intel_logical_ring_advance(ringbuf);
 
 	if (intel_ring_stopped(ring))
 		return;
 
-	execlists_context_queue(ring, ctx, ringbuf->tail, request);
+	if (dev_priv->guc.execbuf_client)
+		i915_guc_client_submit(dev_priv->guc.execbuf_client, ctx, ring);
+	else
+		execlists_context_queue(ring, ctx, ringbuf->tail, request);
 }
 
 static int intel_lr_context_pin(struct intel_engine_cs *ring,
@@ -749,6 +753,7 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,
 {
 	struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state;
 	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	int ret = 0;
 
 	WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));
@@ -761,6 +766,10 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,
 		ret = intel_pin_and_map_ringbuffer_obj(ring->dev, ringbuf);
 		if (ret)
 			goto unpin_ctx_obj;
+
+		/* Invalidate GuC TLB. */
+		if (i915.enable_guc_scheduling)
+			I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
 	}
 
 	return ret;
@@ -1305,8 +1314,13 @@ out:
 static int gen8_init_rcs_context(struct intel_engine_cs *ring,
 		       struct intel_context *ctx)
 {
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	int ret;
 
+	/* Invalidate GuC TLB. */
+	if (i915.enable_guc_scheduling)
+		I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+
 	ret = intel_logical_ring_workarounds_emit(ring, ctx);
 	if (ret)
 		return ret;
-- 
1.9.1

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

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

* [PATCH 14/18] drm/i915: debugfs of GuC status
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (12 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 13/18] drm/i915: Enable commands submission via GuC yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 15/18] drm/i915: Enable GuC firmware log yu.dai
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

Now print out Bootrom, uKernel and MIA Core status. The scratch reg
0 & 15 are used for communication between driver and firmware. Their
status is also printed out.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c     | 73 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc.h        | 13 ++++++
 drivers/gpu/drm/i915/intel_guc_client.c | 33 +++++++++++----
 3 files changed, 112 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 007c7d7..59ad3fc 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2239,6 +2239,77 @@ static int i915_llc(struct seq_file *m, void *data)
 	return 0;
 }
 
+static void i915_uc_load_status_info(struct seq_file *m, struct intel_uc_fw *uc_fw)
+{
+	seq_printf(m, "%s firmware status:\n\tpath: <%s>\n\tfetch: %d\n\tload: %d\n",
+			uc_fw->uc_name,
+			uc_fw->uc_fw_path,
+			uc_fw->uc_fw_fetch_status,
+			uc_fw->uc_fw_load_status);
+}
+
+static int i915_guc_load_status_info(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = m->private;
+	struct drm_i915_private *dev_priv = node->minor->dev->dev_private;
+	u32 tmp, i;
+
+	i915_uc_load_status_info(m, &dev_priv->guc.guc_fw);
+
+	tmp = I915_READ(GUC_STATUS);
+
+	seq_puts(m, "\nResponse from GuC:\n");
+	seq_printf(m, "\tBootrom status = 0x%x\n",
+		(tmp & GS_BOOTROM_MASK) >> GS_BOOTROM_SHIFT);
+	seq_printf(m, "\tuKernel status = 0x%x\n",
+		(tmp & GS_UKERNEL_MASK) >> GS_UKERNEL_SHIFT);
+	seq_printf(m, "\tMIA Core status = 0x%x\n",
+		(tmp & GS_MIA_MASK) >> GS_MIA_SHIFT);
+	seq_puts(m, "Scratch registers value:\n");
+	for (i = 0; i < 16; i++)
+		seq_printf(m, "\t%2d: \t0x%x\n", i, I915_READ(SOFT_SCRATCH(i)));
+
+	return 0;
+}
+
+static int i915_guc_info(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 = dev->dev_private;
+	struct intel_guc guc;
+	struct i915_guc_client client;
+
+	memset(&client, 0, sizeof(struct i915_guc_client));
+
+	/* Take a local copy of the GuC data, so we can dump it at leisure */
+	spin_lock(&dev_priv->guc.host2guc_lock);
+	guc = dev_priv->guc;
+	if (guc.execbuf_client) {
+		spin_lock(&guc.execbuf_client->wq_lock);
+		client = *guc.execbuf_client;
+		spin_unlock(&guc.execbuf_client->wq_lock);
+	}
+	spin_unlock(&dev_priv->guc.host2guc_lock);
+
+	seq_printf(m, "GuC total action count: %llu\n", guc.action_count);
+	seq_printf(m, "GuC last action command: 0x%x\n", guc.action_cmd);
+	seq_printf(m, "GuC last action status: 0x%x\n", guc.action_status);
+
+	seq_printf(m, "GuC action failure count: %u\n", guc.action_fail);
+	seq_printf(m, "GuC last action error code: %d\n", guc.action_err);
+
+	seq_printf(m, "GuC execbuf client @ %p:\n", guc.execbuf_client);
+	seq_printf(m, "\tTotal submissions: %llu\n", client.submissions);
+	seq_printf(m, "\tFailed to queue: %u\n", client.q_fail);
+	seq_printf(m, "\tFailed doorbell: %u\n", client.b_fail);
+	seq_printf(m, "\tLast submission result: %d\n", client.retcode);
+
+	/* Add more as required ... */
+
+	return 0;
+}
+
 static int i915_edp_psr_status(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = m->private;
@@ -4661,6 +4732,8 @@ static const struct drm_info_list i915_debugfs_list[] = {
 	{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
 	{"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
 	{"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
+	{"i915_guc_info", i915_guc_info, 0},
+	{"i915_guc_load_status", i915_guc_load_status_info, 0},
 	{"i915_frequency_info", i915_frequency_info, 0},
 	{"i915_hangcheck_info", i915_hangcheck_info, 0},
 	{"i915_drpc_info", i915_drpc_info, 0},
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 498789d..e20c332 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -42,6 +42,12 @@ struct i915_guc_client {
 	uint32_t wq_size;
 	uint32_t wq_tail;
 	uint32_t cookie;
+
+	/* GuC submission statistics & status */
+	uint64_t submissions;
+	uint32_t q_fail;
+	uint32_t b_fail;
+	int retcode;
 };
 
 #define I915_MAX_DOORBELLS	256
@@ -62,6 +68,13 @@ struct intel_guc {
 	struct ida ctx_ids;
 	int db_cacheline;
 	DECLARE_BITMAP(doorbell_bitmap, I915_MAX_DOORBELLS);
+
+	/* Action status & statistics */
+	uint64_t action_count;		/* Total commands issued	*/
+	uint32_t action_cmd;		/* Last command word		*/
+	uint32_t action_status;		/* Last return status		*/
+	uint32_t action_fail;		/* Total number of failures	*/
+	int32_t action_err;		/* Last error code		*/
 };
 
 #define GUC_STATUS		0xc000
diff --git a/drivers/gpu/drm/i915/intel_guc_client.c b/drivers/gpu/drm/i915/intel_guc_client.c
index 2415bfa..264e0ab 100644
--- a/drivers/gpu/drm/i915/intel_guc_client.c
+++ b/drivers/gpu/drm/i915/intel_guc_client.c
@@ -50,6 +50,9 @@ static int intel_guc_action(struct intel_guc *guc, u32 *data, u32 len)
 
 	spin_lock(&dev_priv->guc.host2guc_lock);
 
+	dev_priv->guc.action_count += 1;
+	dev_priv->guc.action_cmd = data[0];
+
 	for (i = 0; i < len; i++)
 		I915_WRITE(SOFT_SCRATCH(i), data[i]);
 
@@ -68,7 +71,11 @@ static int intel_guc_action(struct intel_guc *guc, u32 *data, u32 len)
 				"status=0x%08X response=0x%08X\n",
 				data[0], ret, status,
 				I915_READ(SOFT_SCRATCH(15)));
+
+		dev_priv->guc.action_fail += 1;
+		dev_priv->guc.action_err = ret;
 	}
+	dev_priv->guc.action_status = status;
 
 	spin_unlock(&dev_priv->guc.host2guc_lock);
 
@@ -560,13 +567,25 @@ int i915_guc_client_submit(struct i915_guc_client *client,
 			   struct intel_context *ctx,
 			   struct intel_engine_cs *ring)
 {
-	int ret;
-
-	ret = add_workqueue_item(client, ctx, ring);
-	if (ret)
-		return ret;
+	int q_ret, b_ret;
+	unsigned long flags;
 
-	ret = ring_doorbell(client);
+	q_ret = add_workqueue_item(client, ctx, ring);
+	if (q_ret == 0)
+		b_ret = ring_doorbell(client);
+
+	spin_lock_irqsave(&client->wq_lock, flags);
+	client->submissions += 1;
+	if (q_ret) {
+		client->q_fail += 1;
+		client->retcode = q_ret;
+	} else if (b_ret) {
+		client->b_fail += 1;
+		client->retcode = q_ret = b_ret;
+	} else {
+		client->retcode = 0;
+	}
+	spin_unlock_irqrestore(&client->wq_lock, flags);
 
-	return ret;
+	return q_ret;
 }
-- 
1.9.1

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

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

* [PATCH 15/18] drm/i915: Enable GuC firmware log
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (13 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 14/18] drm/i915: debugfs of GuC status yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 16/18] drm/i915: Ring Context allocating for GuC yu.dai
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

Allocate a gem obj to hold GuC log data. Also a debugfs interface
(i915_guc_log_dump) is provided to print out the log content.

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c        | 29 +++++++++++++++
 drivers/gpu/drm/i915/i915_drv.h            |  1 +
 drivers/gpu/drm/i915/i915_params.c         |  5 +++
 drivers/gpu/drm/i915/intel_guc.h           |  3 +-
 drivers/gpu/drm/i915/intel_guc_loader.c    | 60 +++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_guc_scheduler.c |  9 ++---
 6 files changed, 99 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 59ad3fc..42d3df8 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2310,6 +2310,34 @@ static int i915_guc_info(struct seq_file *m, void *data)
 	return 0;
 }
 
+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 = dev->dev_private;
+	struct drm_i915_gem_object *log_obj = dev_priv->guc.log_obj;
+	u32 *log;
+	int i = 0, pg;
+
+	if (!log_obj)
+		return 0;
+
+	for (pg = 0; pg < log_obj->base.size / PAGE_SIZE; pg++) {
+		log = kmap_atomic(i915_gem_object_get_page(log_obj, pg));
+
+		for (i = 0; i < PAGE_SIZE / sizeof(u32); i += 4)
+			seq_printf(m, "0x%08x 0x%08x 0x%08x 0x%08x\n",
+				   *(log + i), *(log + i + 1),
+				   *(log + i + 2), *(log + i + 3));
+
+		kunmap_atomic(log);
+	}
+
+	seq_putc(m, '\n');
+
+	return 0;
+}
+
 static int i915_edp_psr_status(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = m->private;
@@ -4734,6 +4762,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
 	{"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
 	{"i915_guc_info", i915_guc_info, 0},
 	{"i915_guc_load_status", i915_guc_load_status_info, 0},
+	{"i915_guc_log_dump", i915_guc_log_dump, 0},
 	{"i915_frequency_info", i915_frequency_info, 0},
 	{"i915_hangcheck_info", i915_hangcheck_info, 0},
 	{"i915_drpc_info", i915_drpc_info, 0},
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index ba5da95..5fde3fc 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2477,6 +2477,7 @@ struct i915_params {
 	bool disable_display;
 	bool disable_vtd_wa;
 	bool enable_guc_scheduling;
+	unsigned int guc_log_level;
 	int use_mmio_flip;
 	int mmio_debug;
 	bool verbose_state_checks;
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index a4743ed..4877130 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -53,6 +53,7 @@ struct i915_params i915 __read_mostly = {
 	.verbose_state_checks = 1,
 	.nuclear_pageflip = 0,
 	.enable_guc_scheduling = false,
+	.guc_log_level = 0,
 };
 
 module_param_named(modeset, i915.modeset, int, 0400);
@@ -182,3 +183,7 @@ MODULE_PARM_DESC(nuclear_pageflip,
 
 module_param_named(enable_guc_scheduling, i915.enable_guc_scheduling, bool, 0400);
 MODULE_PARM_DESC(enable_guc_scheduling, "Enable GuC scheduling (default:false)");
+
+module_param_named(guc_log_level, i915.guc_log_level, int, 0400);
+MODULE_PARM_DESC(guc_log_level,
+	"GuC firmware logging level (0:disabled, 1~4:enabled)");
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index e20c332..3c41483 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -62,6 +62,7 @@ struct intel_guc {
 	spinlock_t host2guc_lock;
 
 	struct drm_i915_gem_object *ctx_pool_obj;
+	struct drm_i915_gem_object *log_obj;
 
 	struct i915_guc_client *execbuf_client;
 
@@ -170,7 +171,7 @@ int guc_scheduler_init(struct drm_device *dev);
 void guc_scheduler_fini(struct drm_device *dev);
 int guc_scheduler_enable(struct drm_device *dev);
 void guc_scheduler_disable(struct drm_device *dev);
-bool sanitize_enable_guc_scheduling(struct drm_device *dev);
+void sanitize_enable_guc_scheduling(struct drm_device *dev);
 
 /* intel_guc_client.c */
 struct i915_guc_client*
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 58e1e33..7c33cc5 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -30,6 +30,10 @@
 MODULE_FIRMWARE(I915_GUC_UCODE_GEN8);
 MODULE_FIRMWARE(I915_GUC_UCODE_GEN9);
 
+#define GUC_LOG_DPC_PAGES	3
+#define GUC_LOG_ISR_PAGES	3
+#define GUC_LOG_CRASH_PAGES	1
+
 struct drm_i915_gem_object *
 intel_guc_allocate_gem_obj(struct drm_device *dev, u32 size)
 {
@@ -152,6 +156,51 @@ static u32 get_core_family(struct drm_device *dev)
 	}
 }
 
+static void create_guc_log(struct intel_guc *guc, u32 *params)
+{
+	struct drm_i915_private *dev_priv =
+			container_of(guc, struct drm_i915_private, guc);
+	struct drm_i915_gem_object *obj;
+	u32 flags, size;
+
+	/* The first page is to save log buffer state. Allocate one
+	 * extra page for others in case for overlap */
+	size = (1 + GUC_LOG_DPC_PAGES + 1 +
+		GUC_LOG_ISR_PAGES + 1 +
+		GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT;
+
+	if (!guc->log_obj) {
+		obj = intel_guc_allocate_gem_obj(dev_priv->dev, size);
+		if (!obj) {
+			/* logging will be off */
+			*(params + GUC_CTL_LOG_PARAMS) = 0;
+			i915.guc_log_level = 0;
+			return;
+		}
+
+		guc->log_obj = obj;
+	}
+	else
+		obj = guc->log_obj;
+
+	/* each allocated unit is a page */
+	flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL |
+		(GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) |
+		(GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) |
+		(GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT);
+
+	size = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; /* in pages */
+	flags |= size << GUC_LOG_BUF_ADDR_SHIFT;
+
+	*(params + GUC_CTL_LOG_PARAMS) = flags;
+
+	i915.guc_log_level--;
+	if (i915.guc_log_level > GUC_LOG_VERBOSITY_ULTRA)
+		i915.guc_log_level = GUC_LOG_VERBOSITY_ULTRA;
+
+	*(params + GUC_CTL_DEBUG) |= i915.guc_log_level;
+}
+
 static void set_guc_init_params(struct drm_i915_private *dev_priv)
 {
 	u32 params[GUC_CTL_MAX_DWORDS];
@@ -175,7 +224,9 @@ static void set_guc_init_params(struct drm_i915_private *dev_priv)
 	params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
 			GUC_CTL_VCS2_ENABLED;
 
-	/* XXX: Set up log buffer */
+	/* Set up log buffer */
+	if (i915.guc_log_level > 0)
+		create_guc_log(&dev_priv->guc, params);
 
 	/* If GuC scheduling is enabled, setup params here. */
 	if (i915.enable_guc_scheduling) {
@@ -299,7 +350,7 @@ int intel_guc_load_ucode(struct drm_device *dev, bool wait)
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 	int err;
 
-	i915.enable_guc_scheduling = sanitize_enable_guc_scheduling(dev);
+	sanitize_enable_guc_scheduling(dev);
 
 	DRM_DEBUG_DRIVER("GuC: wait %d, fetch status %d, load status %d\n",
 		wait, guc_fw->uc_fw_fetch_status, guc_fw->uc_fw_load_status);
@@ -401,6 +452,11 @@ void intel_guc_ucode_fini(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 
+	if (dev_priv->guc.log_obj) {
+		intel_guc_release_gem_obj(dev_priv->guc.log_obj);
+		dev_priv->guc.log_obj = NULL;
+	}
+
 	guc_scheduler_fini(dev);
 
 	intel_uc_fw_fini(dev, guc_fw);
diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
index c0b7231..ea1ff28 100644
--- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -155,11 +155,10 @@ void guc_scheduler_disable(struct drm_device *dev)
 	}
 }
 
-bool sanitize_enable_guc_scheduling(struct drm_device *dev)
+void sanitize_enable_guc_scheduling(struct drm_device *dev)
 {
-	if (!HAS_GUC_UCODE(dev) || !HAS_GUC_SCHED(dev))
-		return false;
-
-	return i915.enable_execlists && i915.enable_guc_scheduling;
+	if (!HAS_GUC_UCODE(dev) || !HAS_GUC_SCHED(dev) ||
+	    !i915.enable_execlists)
+		i915.enable_guc_scheduling = false;
 }
 
-- 
1.9.1

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

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

* [PATCH 16/18] drm/i915: Ring Context allocating for GuC
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (14 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 15/18] drm/i915: Enable GuC firmware log yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-26 19:41 ` [PATCH 17/18] drm/i915: Taking forcewake during GuC load yu.dai
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

GuC firmware uses the one page after Ring Context as shared data.
However, GuC uses same offset to address this page for all rings.
So we have to allocate same size of lrc context for all rings.

Also, reduce ring buffer size to 4 pages. In GuC, work queue tail is
referenced by 11 bits (WQ_RING_TAIL_MASK). It is in QW, so total 14
bits (4 pages).

Issue: VIZ-4884
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/intel_lrc.c        | 23 ++++++++---------------
 drivers/gpu/drm/i915/intel_ringbuffer.c |  2 +-
 2 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 967ebf7..d7a42ab 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -1781,20 +1781,10 @@ uint32_t get_lr_context_size(struct intel_engine_cs *ring)
 
 	WARN_ON(INTEL_INFO(ring->dev)->gen < 8);
 
-	switch (ring->id) {
-	case RCS:
-		if (INTEL_INFO(ring->dev)->gen >= 9)
-			ret = GEN9_LR_CONTEXT_RENDER_SIZE;
-		else
-			ret = GEN8_LR_CONTEXT_RENDER_SIZE;
-		break;
-	case VCS:
-	case BCS:
-	case VECS:
-	case VCS2:
-		ret = GEN8_LR_CONTEXT_OTHER_SIZE;
-		break;
-	}
+	if (INTEL_INFO(ring->dev)->gen >= 9)
+		ret = GEN9_LR_CONTEXT_RENDER_SIZE;
+	else
+		ret = GEN8_LR_CONTEXT_RENDER_SIZE;
 
 	return ret;
 }
@@ -1843,6 +1833,9 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 	WARN_ON(ctx->engine[ring->id].state);
 
 	context_size = round_up(get_lr_context_size(ring), 4096);
+	/* One extra page as the sharing data between driver and GuC */
+	if (i915.enable_guc_scheduling)
+		context_size += PAGE_SIZE;
 
 	ctx_obj = i915_gem_alloc_context_obj(dev, context_size);
 	if (IS_ERR(ctx_obj)) {
@@ -1871,7 +1864,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 
 	ringbuf->ring = ring;
 
-	ringbuf->size = 32 * PAGE_SIZE;
+	ringbuf->size = 4 * PAGE_SIZE;
 	ringbuf->effective_size = ringbuf->size;
 	ringbuf->head = 0;
 	ringbuf->tail = 0;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 441e250..127cd01 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1972,7 +1972,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
 	INIT_LIST_HEAD(&ring->active_list);
 	INIT_LIST_HEAD(&ring->request_list);
 	INIT_LIST_HEAD(&ring->execlist_queue);
-	ringbuf->size = 32 * PAGE_SIZE;
+	ringbuf->size = 4 * PAGE_SIZE;
 	ringbuf->ring = ring;
 	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
 
-- 
1.9.1

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

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

* [PATCH 17/18] drm/i915: Taking forcewake during GuC load.
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (15 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 16/18] drm/i915: Ring Context allocating for GuC yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-27  8:55   ` Daniel Vetter
  2015-03-26 19:41 ` [PATCH 18/18] drm/i915: Notify GuC when RC6 state is changed yu.dai
  2015-03-27  8:59 ` [PATCH 00/18] Command submission via GuC for SKL Daniel Vetter
  18 siblings, 1 reply; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Sagar Kamble

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

Need to take forcewake before GuC loading.

Issue: VIZ-4884
Change-Id: Ie422fc1e122933b161ff63cab23622197e6bba54
Signed-off-by: Sagar Kamble <sagar.a.kamble@intel.com>
---
 drivers/gpu/drm/i915/intel_guc_loader.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 7c33cc5..4ae9e84 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -273,6 +273,7 @@ static int guc_load_ucode(struct drm_device *dev)
 	int ret;
 
 	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
 	ret = i915_gem_obj_ggtt_pin(guc_fw->uc_fw_obj, 0, 0);
 	if (ret)
@@ -326,6 +327,8 @@ out:
 	if (pinned)
 		i915_gem_object_ggtt_unpin(guc_fw->uc_fw_obj);
 
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+
 	return ret;
 }
 
-- 
1.9.1

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

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

* [PATCH 18/18] drm/i915: Notify GuC when RC6 state is changed
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (16 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 17/18] drm/i915: Taking forcewake during GuC load yu.dai
@ 2015-03-26 19:41 ` yu.dai
  2015-03-27  1:24   ` shuang.he
  2015-03-27  8:54   ` Daniel Vetter
  2015-03-27  8:59 ` [PATCH 00/18] Command submission via GuC for SKL Daniel Vetter
  18 siblings, 2 replies; 29+ messages in thread
From: yu.dai @ 2015-03-26 19:41 UTC (permalink / raw)
  To: intel-gfx

From: Alex Dai <yu.dai@intel.com>

Whenever RC6 state (0xA210) is changed, driver needs to notify GuC
via guc_action.

Issue: VIZ-4884
Change-Id: I15c661a915c670691d020471ecaccb00f7afb624
Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/intel_guc.h           |  1 +
 drivers/gpu/drm/i915/intel_guc_api.h       |  1 +
 drivers/gpu/drm/i915/intel_guc_client.c    | 16 ++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_scheduler.c |  3 +++
 drivers/gpu/drm/i915/intel_pm.c            |  4 ++++
 5 files changed, 25 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 3c41483..baa2446 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -181,5 +181,6 @@ void i915_guc_client_free(struct drm_device *dev,
 int i915_guc_client_submit(struct i915_guc_client *client,
 			   struct intel_context *ctx,
 			   struct intel_engine_cs *ring);
+int host2guc_sample_forcewake(struct intel_guc *guc, bool enable);
 
 #endif
diff --git a/drivers/gpu/drm/i915/intel_guc_api.h b/drivers/gpu/drm/i915/intel_guc_api.h
index 3d4f74a..94c914e 100644
--- a/drivers/gpu/drm/i915/intel_guc_api.h
+++ b/drivers/gpu/drm/i915/intel_guc_api.h
@@ -190,6 +190,7 @@ struct guc_context_desc {
 /* 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_LIMIT
diff --git a/drivers/gpu/drm/i915/intel_guc_client.c b/drivers/gpu/drm/i915/intel_guc_client.c
index 264e0ab..29450d2 100644
--- a/drivers/gpu/drm/i915/intel_guc_client.c
+++ b/drivers/gpu/drm/i915/intel_guc_client.c
@@ -262,6 +262,22 @@ static int host2guc_release_doorbell(struct intel_guc *guc,
 	return intel_guc_action(guc, data, 2);
 }
 
+int host2guc_sample_forcewake(struct intel_guc *guc, bool enable)
+{
+	u32 data[2];
+
+	if (guc->guc_fw.uc_fw_load_status != INTEL_UC_FIRMWARE_SUCCESS)
+		return -ENODEV;
+
+	data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE;
+	if (enable)
+		data[1] = 3; /* Bit0: Render, Bit1: Media */
+	else
+		data[1] = 0;
+
+	return intel_guc_action(guc, data, 2);
+}
+
 static void init_doorbell(struct intel_guc *guc,
 			  struct i915_guc_client *client)
 {
diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
index ea1ff28..bd7ea0e 100644
--- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -139,6 +139,9 @@ int guc_scheduler_enable(struct drm_device *dev)
 
 	direct_interrupts_to_guc(dev_priv);
 
+	flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+	host2guc_sample_forcewake(guc, dev_priv->rps.enabled);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index fa4ccb3..dfde98d 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -4113,6 +4113,8 @@ static void gen9_disable_rps(struct drm_device *dev)
 
 	I915_WRITE(GEN6_RC_CONTROL, 0);
 	I915_WRITE(GEN9_PG_ENABLE, 0);
+
+	host2guc_sample_forcewake(&dev_priv->guc, 0);
 }
 
 static void gen6_disable_rps(struct drm_device *dev)
@@ -4330,6 +4332,8 @@ static void gen9_enable_rc6(struct drm_device *dev)
 
 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 
+	host2guc_sample_forcewake(&dev_priv->guc,
+			rc6_mask & GEN6_RC_CTL_RC6_ENABLE);
 }
 
 static void gen8_enable_rps(struct drm_device *dev)
-- 
1.9.1

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

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

* Re: [PATCH 18/18] drm/i915: Notify GuC when RC6 state is changed
  2015-03-26 19:41 ` [PATCH 18/18] drm/i915: Notify GuC when RC6 state is changed yu.dai
@ 2015-03-27  1:24   ` shuang.he
  2015-03-27  8:54   ` Daniel Vetter
  1 sibling, 0 replies; 29+ messages in thread
From: shuang.he @ 2015-03-27  1:24 UTC (permalink / raw)
  To: shuang.he, ethan.gao, intel-gfx, yu.dai

Tested-By: PRC QA PRTS (Patch Regression Test System Contact: shuang.he@intel.com)
Task id: 6065
-------------------------------------Summary-------------------------------------
Platform          Delta          drm-intel-nightly          Series Applied
PNV                 -2              276/276              274/276
ILK                 -1              303/303              302/303
SNB                 -1              304/304              303/304
IVB                 -1              339/339              338/339
BYT                 -1              287/287              286/287
HSW                 -2              362/362              360/362
BDW                 -1              310/310              309/310
-------------------------------------Detailed-------------------------------------
Platform  Test                                drm-intel-nightly          Series Applied
 PNV  igt@gem_userptr_blits@minor-normal-sync      DMESG_WARN(1)PASS(3)      DMESG_WARN(1)PASS(1)
(dmesg patch applied)WARNING:at_drivers/gpu/drm/i915/i915_gem_evict.c:#i915_gem_evict_vm[i915]()@WARNING:.* at .* i915_gem_evict_vm+0x
*PNV  igt@drv_debugfs_reader      PASS(2)      DMESG_WARN(2)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*ILK  igt@drv_suspend@debugfs-reader      PASS(2)      DMESG_WARN(2)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*SNB  igt@drv_debugfs_reader      PASS(2)      DMESG_WARN(2)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*IVB  igt@drv_debugfs_reader      PASS(2)      DMESG_WARN(2)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*BYT  igt@drv_debugfs_reader      PASS(2)      DMESG_WARN(2)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*HSW  igt@gem_storedw_loop_bsd      PASS(2)      DMESG_WARN(1)PASS(1)
(dmesg patch applied)drm:i915_hangcheck_elapsed[i915]]*ERROR*Hangcheck_timer_elapsed...bsd_ring_idle@Hangcheck timer elapsed... bsd ring idle
*HSW  igt@pm_rpm@debugfs-read      PASS(2)      DMESG_WARN(2)
(dmesg patch applied)WARNING:at_drivers/gpu/drm/i915/intel_uncore.c:#assert_device_not_suspended[i915]()@WARNING:.* at .* assert_device_not_suspended+0x
drm:fw_domains_get[i915]]*ERROR*render:timed_out_waiting_for_forcewake_ack_to_clear@render: timed out waiting for forcewake ack to clear.
drm:fw_domains_get_with_thread_status[i915]]*ERROR*GT_thread_status_wait_timed_out@GT thread status wait timed out
INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*BDW  igt@gem_userptr_blits@forked-sync-swapping-mempressure-normal      PASS(2)      DMESG_WARN(2)
(dmesg patch applied)drm:intel_uc_fw_check[i915]]*ERROR*Failed_to_fetch_GuC_firmware_from<i915/guc_gen8.bin>@Failed to fetch GuC firmware from
INFO:possible_circular_locking_dependency_detected@INFO: possible circular locking dependency detected
Note: You need to pay more attention to line start with '*'
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 06/18] drm/i915: Defer default hardware context initialisation until first open
  2015-03-26 19:41 ` [PATCH 06/18] drm/i915: Defer default hardware context initialisation until first open yu.dai
@ 2015-03-27  8:45   ` Daniel Vetter
  2015-03-30 19:11     ` Yu Dai
  2015-03-31  9:29     ` Chris Wilson
  0 siblings, 2 replies; 29+ messages in thread
From: Daniel Vetter @ 2015-03-27  8:45 UTC (permalink / raw)
  To: yu.dai; +Cc: intel-gfx

On Thu, Mar 26, 2015 at 12:41:13PM -0700, yu.dai@intel.com wrote:
> From: Dave Gordon <david.s.gordon@intel.com>
> 
> In order to fully initialise the default contexts, we have to execute
> batchbuffer commands on the GPU engines. But we can't do that until any
> required firmware has been loaded, which may not be possible during
> driver load, because the filesystem(s) containing the firmware may not
> be mounted until later.
> 
> Therefore, we now allow the first call to the firmware-loading code to
> return -EAGAIN to indicate that it's not yet ready, and that it should
> be retried when the device is first opened from user code, by which
> time we expect that all required filesystems will have been mounted.
> The late-retry code will then re-attempt to load the firmware if the
> early attempt failed.

We've tried a similar approach a while back and it doesn't work well in
conjunction with rps - the hw tends to fall over if the context state
isn't properly initialized when going into rc6.

Why exactly can't we load that firmware right at boot-up, or at least
stall correctly until it's there?
-Daniel

> 
> Issue: VIZ-4884
> Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
> Signed-off-by: Alex Dai <yu.dai@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h         |  1 +
>  drivers/gpu/drm/i915/i915_gem.c         |  9 ++++++++-
>  drivers/gpu/drm/i915/i915_gem_context.c | 35 ++++++++++++++++++++++++++++-----
>  drivers/gpu/drm/i915/intel_guc.h        |  2 +-
>  drivers/gpu/drm/i915/intel_guc_loader.c | 22 ++++++++++++++++++---
>  drivers/gpu/drm/i915/intel_uc_loader.c  | 12 +++++++++--
>  6 files changed, 69 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 1a60f86..45bdf30 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1755,6 +1755,7 @@ struct drm_i915_private {
>  	/* hda/i915 audio component */
>  	bool audio_component_registered;
>  
> +	bool contexts_ready;
>  	uint32_t hw_context_size;
>  	struct list_head context_list;
>  
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 38e49d9..0037ccf 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -4828,8 +4828,15 @@ i915_gem_init_hw(struct drm_device *dev)
>  		i915_gem_cleanup_ringbuffer(dev);
>  	}
>  
> +	/* We can't enable contexts until all firmware is loaded */
> +	ret = intel_guc_load_ucode(dev, false);
> +	if (ret == -EAGAIN)
> +		return 0;		/* too early */
> +
>  	ret = i915_gem_context_enable(dev_priv);
> -	if (ret && ret != -EIO) {
> +	if (ret == 0) {
> +		dev_priv->contexts_ready = true;
> +	} else if (ret && ret != -EIO) {
>  		DRM_ERROR("Context enable failed %d\n", ret);
>  		i915_gem_cleanup_ringbuffer(dev);
>  
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
> index f3e84c4..2353d8f 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -445,23 +445,48 @@ static int context_idr_cleanup(int id, void *p, void *data)
>  	return 0;
>  }
>  
> +/* Complete any late initialisation here */
> +static int i915_gem_context_first_open(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	int ret;
> +
> +	/* We can't enable contexts until all firmware is loaded */
> +	ret = intel_guc_load_ucode(dev, true);
> +	WARN_ON(ret == -EAGAIN);
> +
> +	ret = i915_gem_context_enable(dev_priv);
> +	if (ret == 0)
> +		dev_priv->contexts_ready = true;
> +	return ret;
> +}
> +
>  int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
>  {
> +	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct drm_i915_file_private *file_priv = file->driver_priv;
>  	struct intel_context *ctx;
> +	int ret = 0;
>  
>  	idr_init(&file_priv->context_idr);
>  
>  	mutex_lock(&dev->struct_mutex);
> -	ctx = i915_gem_create_context(dev, file_priv);
> +
> +	if (!dev_priv->contexts_ready)
> +		ret = i915_gem_context_first_open(dev);
> +
> +	if (ret == 0) {
> +		ctx = i915_gem_create_context(dev, file_priv);
> +		if (IS_ERR(ctx))
> +			ret = PTR_ERR(ctx);
> +	}
> +
>  	mutex_unlock(&dev->struct_mutex);
>  
> -	if (IS_ERR(ctx)) {
> +	if (ret)
>  		idr_destroy(&file_priv->context_idr);
> -		return PTR_ERR(ctx);
> -	}
>  
> -	return 0;
> +	return ret;
>  }
>  
>  void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index a06a7b3..d8262cf 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -89,7 +89,7 @@ struct intel_guc {
>  				 GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA)
>  
>  /* intel_guc_loader.c */
> -extern int intel_guc_load_ucode(struct drm_device *dev);
> +extern int intel_guc_load_ucode(struct drm_device *dev, bool wait);
>  extern void intel_guc_ucode_fini(struct drm_device *dev);
>  extern void intel_guc_ucode_init(struct drm_device *dev);
>  
> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
> index b9923b7..315e5d9 100644
> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> @@ -217,25 +217,41 @@ out:
>  }
>  
>  /*
> - * Called from gem_init_hw() during driver loading and also after a GPU reset.
>   * Check that the firmware fetching process has succeeded, and if so transfer
>   * the loaded image to the hardware.
> + *
> + * However, there are a few checks to do first. The very first call should have
> + * (wait == FALSE), but the fetch_state will still be PENDING as the firmware may
> + * not be available that early. Therefore, on this first call, we just return.
> + *
> + * The second call should come from the first open of the device (wait == TRUE).
> + * This is a good time to load the firmware into the device, as by this point it
> + * must be available.
> + *
> + * Any subsequent calls are expected to have wait == FALSE, and indicate that the
> + * hardware has been reset and so the firmware should be reloaded.
>   */
> -int intel_guc_load_ucode(struct drm_device *dev)
> +int intel_guc_load_ucode(struct drm_device *dev, bool wait)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
>  	int err;
>  
> +	DRM_DEBUG_DRIVER("GuC: wait %d, fetch status %d, load status %d\n",
> +		wait, guc_fw->uc_fw_fetch_status, guc_fw->uc_fw_load_status);
> +
> +	if (guc_fw->uc_fw_fetch_status == INTEL_UC_FIRMWARE_PENDING && !wait)
> +		return -EAGAIN;
> +
>  	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_NONE;
>  	if (guc_fw->uc_fw_fetch_status == INTEL_UC_FIRMWARE_NONE)
>  		return 0;
>  
> -	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_PENDING;
>  	err = intel_uc_fw_check(dev, guc_fw);
>  	if (err)
>  		goto fail;
>  
> +	guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_PENDING;
>  	err = guc_load_ucode(dev);
>  	if (err)
>  		goto fail;
> diff --git a/drivers/gpu/drm/i915/intel_uc_loader.c b/drivers/gpu/drm/i915/intel_uc_loader.c
> index 986dcf3..bc4b1e5 100644
> --- a/drivers/gpu/drm/i915/intel_uc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_uc_loader.c
> @@ -49,8 +49,16 @@ static void uc_fw_finish(struct drm_device *dev, struct intel_uc_fw *uc_fw)
>  		uc_fw->uc_name, uc_fw->uc_fw_fetch_status, uc_fw->uc_fw_blob);
>  
>  	fw = uc_fw->uc_fw_blob;
> -	if (!fw)
> -		goto fail;
> +	if (!fw) {
> +		/* no firmware found; try again in case FS was not mounted */
> +		DRM_DEBUG_DRIVER("retry fetching %s fw from <%s>\n",
> +			uc_fw->uc_name, uc_fw->uc_fw_path);
> +		if (request_firmware(&fw, uc_fw->uc_fw_path, &dev->pdev->dev))
> +			goto fail;
> +		DRM_DEBUG_DRIVER("fetch %s fw from <%s> succeeded, fw %p\n",
> +			uc_fw->uc_name, uc_fw->uc_fw_path, fw);
> +		uc_fw->uc_fw_blob = fw;
> +	}
>  
>  	if (uc_fw->uc_fw_check && !uc_fw->uc_fw_check(uc_fw))
>  		goto fail;
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 09/18] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-03-26 19:41 ` [PATCH 09/18] drm/i915: Add functions to allocate / release gem obj for GuC yu.dai
@ 2015-03-27  8:48   ` Daniel Vetter
  2015-03-27  8:49     ` Daniel Vetter
  0 siblings, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2015-03-27  8:48 UTC (permalink / raw)
  To: yu.dai; +Cc: intel-gfx

On Thu, Mar 26, 2015 at 12:41:16PM -0700, yu.dai@intel.com wrote:
> From: Alex Dai <yu.dai@intel.com>
> 
> All gem objects used by GuC are pinned to ggtt space out of range
> [0, WOPCM size]. In GuC address space mapping, [0, WPOCM size] is
> used internally for its Boot ROM, SRAM etc. Currently this WPOCM
> size is 512K. This is done by using of PIN_OFFSET_BIAS.
> 
> Issue: VIZ-4884
> Signed-off-by: Alex Dai <yu.dai@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_guc.h        |  3 +++
>  drivers/gpu/drm/i915/intel_guc_loader.c | 34 +++++++++++++++++++++++++++++++++
>  2 files changed, 37 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index d8262cf..ae14c57 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -92,5 +92,8 @@ struct intel_guc {
>  extern int intel_guc_load_ucode(struct drm_device *dev, bool wait);
>  extern void intel_guc_ucode_fini(struct drm_device *dev);
>  extern void intel_guc_ucode_init(struct drm_device *dev);
> +struct drm_i915_gem_object *
> +intel_guc_allocate_gem_obj(struct drm_device *dev, u32 size);
> +void intel_guc_release_gem_obj(struct drm_i915_gem_object *obj);
>  
>  #endif
> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
> index 315e5d9..0500a53 100644
> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> @@ -30,6 +30,40 @@
>  MODULE_FIRMWARE(I915_GUC_UCODE_GEN8);
>  MODULE_FIRMWARE(I915_GUC_UCODE_GEN9);
>  
> +struct drm_i915_gem_object *
> +intel_guc_allocate_gem_obj(struct drm_device *dev, u32 size)
> +{
> +	struct drm_i915_gem_object *obj;
> +
> +	obj = i915_gem_alloc_object(dev, size);
> +	if (!obj)
> +		return NULL;
> +
> +	if (i915_gem_object_get_pages(obj)) {
> +		drm_gem_object_unreference(&obj->base);
> +		return NULL;
> +	}
> +
> +	if (i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
> +			PIN_OFFSET_BIAS | GUC_WOPCM_SIZE_VALUE)) {

Please add a comment here about how much pin bias you exactly need and
why. Otherwise this will be extremely arcane knowledge lost when someone
reworks the pin bias stuff or changes the default offset.

Or well just use the right offset directly, since atm PIN_OFFSET_BIAS is
256k and you claim to need 512k.
-Daniel

> +		drm_gem_object_unreference(&obj->base);
> +		return NULL;
> +	}
> +
> +	return obj;
> +}
> +
> +void intel_guc_release_gem_obj(struct drm_i915_gem_object *obj)
> +{
> +	if (!obj)
> +		return;
> +
> +	if (i915_gem_obj_is_pinned(obj))
> +		i915_gem_object_ggtt_unpin(obj);
> +
> +	drm_gem_object_unreference(&obj->base);
> +}
> +
>  static int copy_rsa(struct drm_i915_private *dev_priv)
>  {
>  	struct sg_table *st = dev_priv->guc.guc_fw.uc_fw_obj->pages;
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 09/18] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-03-27  8:48   ` Daniel Vetter
@ 2015-03-27  8:49     ` Daniel Vetter
  0 siblings, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2015-03-27  8:49 UTC (permalink / raw)
  To: yu.dai; +Cc: intel-gfx

On Fri, Mar 27, 2015 at 09:48:20AM +0100, Daniel Vetter wrote:
> On Thu, Mar 26, 2015 at 12:41:16PM -0700, yu.dai@intel.com wrote:
> > From: Alex Dai <yu.dai@intel.com>
> > 
> > All gem objects used by GuC are pinned to ggtt space out of range
> > [0, WOPCM size]. In GuC address space mapping, [0, WPOCM size] is
> > used internally for its Boot ROM, SRAM etc. Currently this WPOCM
> > size is 512K. This is done by using of PIN_OFFSET_BIAS.
> > 
> > Issue: VIZ-4884
> > Signed-off-by: Alex Dai <yu.dai@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_guc.h        |  3 +++
> >  drivers/gpu/drm/i915/intel_guc_loader.c | 34 +++++++++++++++++++++++++++++++++
> >  2 files changed, 37 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> > index d8262cf..ae14c57 100644
> > --- a/drivers/gpu/drm/i915/intel_guc.h
> > +++ b/drivers/gpu/drm/i915/intel_guc.h
> > @@ -92,5 +92,8 @@ struct intel_guc {
> >  extern int intel_guc_load_ucode(struct drm_device *dev, bool wait);
> >  extern void intel_guc_ucode_fini(struct drm_device *dev);
> >  extern void intel_guc_ucode_init(struct drm_device *dev);
> > +struct drm_i915_gem_object *
> > +intel_guc_allocate_gem_obj(struct drm_device *dev, u32 size);
> > +void intel_guc_release_gem_obj(struct drm_i915_gem_object *obj);
> >  
> >  #endif
> > diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
> > index 315e5d9..0500a53 100644
> > --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> > +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> > @@ -30,6 +30,40 @@
> >  MODULE_FIRMWARE(I915_GUC_UCODE_GEN8);
> >  MODULE_FIRMWARE(I915_GUC_UCODE_GEN9);
> >  
> > +struct drm_i915_gem_object *
> > +intel_guc_allocate_gem_obj(struct drm_device *dev, u32 size)
> > +{
> > +	struct drm_i915_gem_object *obj;
> > +
> > +	obj = i915_gem_alloc_object(dev, size);
> > +	if (!obj)
> > +		return NULL;
> > +
> > +	if (i915_gem_object_get_pages(obj)) {
> > +		drm_gem_object_unreference(&obj->base);
> > +		return NULL;
> > +	}
> > +
> > +	if (i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
> > +			PIN_OFFSET_BIAS | GUC_WOPCM_SIZE_VALUE)) {
> 
> Please add a comment here about how much pin bias you exactly need and
> why. Otherwise this will be extremely arcane knowledge lost when someone
> reworks the pin bias stuff or changes the default offset.
> 
> Or well just use the right offset directly, since atm PIN_OFFSET_BIAS is
> 256k and you claim to need 512k.

Strike that all, I'm blind and your code is all fine.

Sorry for the mess.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 18/18] drm/i915: Notify GuC when RC6 state is changed
  2015-03-26 19:41 ` [PATCH 18/18] drm/i915: Notify GuC when RC6 state is changed yu.dai
  2015-03-27  1:24   ` shuang.he
@ 2015-03-27  8:54   ` Daniel Vetter
  1 sibling, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2015-03-27  8:54 UTC (permalink / raw)
  To: yu.dai; +Cc: intel-gfx

On Thu, Mar 26, 2015 at 12:41:25PM -0700, yu.dai@intel.com wrote:
> From: Alex Dai <yu.dai@intel.com>
> 
> Whenever RC6 state (0xA210) is changed, driver needs to notify GuC
> via guc_action.
> 
> Issue: VIZ-4884
> Change-Id: I15c661a915c670691d020471ecaccb00f7afb624
> Signed-off-by: Alex Dai <yu.dai@intel.com>

What exactly is the interaction here? Please elaborate in the commit
message, since as-is this looks extremely racy: If the guc can fall over
if we change rc6 behind it's back it can still fall over right between
when we change rc6 mode and when we tell the guc.

Also note that rc6 setup is delayed in resume/driver load (because it
takes forever) and we expect the gpu to be fully working while we enable
rc6. If the guc falls over on resume because of this there's a problem. We
might need specific igt testcases which race resume against gpu
submissions.
-Daniel

> ---
>  drivers/gpu/drm/i915/intel_guc.h           |  1 +
>  drivers/gpu/drm/i915/intel_guc_api.h       |  1 +
>  drivers/gpu/drm/i915/intel_guc_client.c    | 16 ++++++++++++++++
>  drivers/gpu/drm/i915/intel_guc_scheduler.c |  3 +++
>  drivers/gpu/drm/i915/intel_pm.c            |  4 ++++
>  5 files changed, 25 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index 3c41483..baa2446 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -181,5 +181,6 @@ void i915_guc_client_free(struct drm_device *dev,
>  int i915_guc_client_submit(struct i915_guc_client *client,
>  			   struct intel_context *ctx,
>  			   struct intel_engine_cs *ring);
> +int host2guc_sample_forcewake(struct intel_guc *guc, bool enable);
>  
>  #endif
> diff --git a/drivers/gpu/drm/i915/intel_guc_api.h b/drivers/gpu/drm/i915/intel_guc_api.h
> index 3d4f74a..94c914e 100644
> --- a/drivers/gpu/drm/i915/intel_guc_api.h
> +++ b/drivers/gpu/drm/i915/intel_guc_api.h
> @@ -190,6 +190,7 @@ struct guc_context_desc {
>  /* 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_LIMIT
> diff --git a/drivers/gpu/drm/i915/intel_guc_client.c b/drivers/gpu/drm/i915/intel_guc_client.c
> index 264e0ab..29450d2 100644
> --- a/drivers/gpu/drm/i915/intel_guc_client.c
> +++ b/drivers/gpu/drm/i915/intel_guc_client.c
> @@ -262,6 +262,22 @@ static int host2guc_release_doorbell(struct intel_guc *guc,
>  	return intel_guc_action(guc, data, 2);
>  }
>  
> +int host2guc_sample_forcewake(struct intel_guc *guc, bool enable)
> +{
> +	u32 data[2];
> +
> +	if (guc->guc_fw.uc_fw_load_status != INTEL_UC_FIRMWARE_SUCCESS)
> +		return -ENODEV;
> +
> +	data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE;
> +	if (enable)
> +		data[1] = 3; /* Bit0: Render, Bit1: Media */
> +	else
> +		data[1] = 0;
> +
> +	return intel_guc_action(guc, data, 2);
> +}
> +
>  static void init_doorbell(struct intel_guc *guc,
>  			  struct i915_guc_client *client)
>  {
> diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
> index ea1ff28..bd7ea0e 100644
> --- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
> +++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
> @@ -139,6 +139,9 @@ int guc_scheduler_enable(struct drm_device *dev)
>  
>  	direct_interrupts_to_guc(dev_priv);
>  
> +	flush_delayed_work(&dev_priv->rps.delayed_resume_work);
> +	host2guc_sample_forcewake(guc, dev_priv->rps.enabled);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index fa4ccb3..dfde98d 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -4113,6 +4113,8 @@ static void gen9_disable_rps(struct drm_device *dev)
>  
>  	I915_WRITE(GEN6_RC_CONTROL, 0);
>  	I915_WRITE(GEN9_PG_ENABLE, 0);
> +
> +	host2guc_sample_forcewake(&dev_priv->guc, 0);
>  }
>  
>  static void gen6_disable_rps(struct drm_device *dev)
> @@ -4330,6 +4332,8 @@ static void gen9_enable_rc6(struct drm_device *dev)
>  
>  	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
>  
> +	host2guc_sample_forcewake(&dev_priv->guc,
> +			rc6_mask & GEN6_RC_CTL_RC6_ENABLE);
>  }
>  
>  static void gen8_enable_rps(struct drm_device *dev)
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 17/18] drm/i915: Taking forcewake during GuC load.
  2015-03-26 19:41 ` [PATCH 17/18] drm/i915: Taking forcewake during GuC load yu.dai
@ 2015-03-27  8:55   ` Daniel Vetter
  0 siblings, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2015-03-27  8:55 UTC (permalink / raw)
  To: yu.dai; +Cc: intel-gfx, Sagar Kamble

On Thu, Mar 26, 2015 at 12:41:24PM -0700, yu.dai@intel.com wrote:
> From: Sagar Kamble <sagar.a.kamble@intel.com>
> 
> Need to take forcewake before GuC loading.

Please explain why and how things fall over if we're not doing this.
-Daniel

> 
> Issue: VIZ-4884
> Change-Id: Ie422fc1e122933b161ff63cab23622197e6bba54
> Signed-off-by: Sagar Kamble <sagar.a.kamble@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_guc_loader.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
> index 7c33cc5..4ae9e84 100644
> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> @@ -273,6 +273,7 @@ static int guc_load_ucode(struct drm_device *dev)
>  	int ret;
>  
>  	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
>  
>  	ret = i915_gem_obj_ggtt_pin(guc_fw->uc_fw_obj, 0, 0);
>  	if (ret)
> @@ -326,6 +327,8 @@ out:
>  	if (pinned)
>  		i915_gem_object_ggtt_unpin(guc_fw->uc_fw_obj);
>  
> +	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
> +
>  	return ret;
>  }
>  
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 00/18] Command submission via GuC for SKL
  2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
                   ` (17 preceding siblings ...)
  2015-03-26 19:41 ` [PATCH 18/18] drm/i915: Notify GuC when RC6 state is changed yu.dai
@ 2015-03-27  8:59 ` Daniel Vetter
  18 siblings, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2015-03-27  8:59 UTC (permalink / raw)
  To: yu.dai; +Cc: intel-gfx

On Thu, Mar 26, 2015 at 12:41:07PM -0700, yu.dai@intel.com wrote:
> From: Alex Dai <yu.dai@intel.com>
> 
> This series of patch is to enable ExecList submission via GuC. Here are some
> key points related to this series, not in particular order.
> 
> *** i915_guc_client ***
> We use the term client to avoid confusion with contexts. A i915_guc_client is
> equivalent to GuC object guc_context_desc. This context descriptor is allocated
> from a pool of 1024 entries. Kernel driver will allocate doorbell and workqueue
> for it. Also the process descriptor (guc_process_desc), which is mapped to
> client space. So the client can write Work Item then ring the doorbell.
> 
> To simplify the implementation, we allocate one gem object that contains all
> pages for doorbell, process descriptor and workqueue.
> 
> *** intel_guc ***
> Top level structure of guc. It handles firmware loading and manages client pool
> and doorbells. intel_guc owns a i915_guc_client to do the legacy submission.
> 
> ** The Scratch registers ***
> There are 16 MMIO-based registers start from 0xC180. The kernel driver writes a
> value to the action register (SOFT_SCRATCH_0) along with any data. It then
> triggers an interrupt on the GuC via another register write (0xC4C8). Firmware
> writes a success/fail code back to the action register after processes the
> request. The kernel driver polls waiting for this update and then proceeds.
> 
> Details in intel_guc_action()
> 
> *** Work Items ***
> There are several types of work items that the host may place into a workqueue,
> each with its own requirements and limitations. Currently only WQ_TYPE_INORDER
> is used to support legacy submission via GuC, which represents in-order queue.
> The kernel driver packs ring tail pointer and an ELSP context descriptor dword
> into Work Item.
> 
> Details in add_workqueue_item()
> 
> *** Doorbells ***
> Doorbells are interrupts to uKernel. A doorbell is a single cache line (QW)
> mapped into process space.
> 
> Details in ring_doorbell()
> 
> *** Firmware versioning ***
> The firmware build process will generate a version header file with major and
> minor version defined. The versions are built into CSS header of firmware too.
> i915 kernel driver set the minimal firmware version required by each platform.
> The firmware installation package will install (symbolic link) proper version
> of firmware.
> 
> *** Firmware log ***
> Firmware log is enabled by setting i915.guc_log_level to non-negative level.
> Log data is printed out via reading debugfs i915_guc_log_dump. Reading from
> i915_guc_load_status will print out firmware loading status and scratch
> registers value.
> 
> TODO: the buffer works like a ring. To not missing any data, driver should
> handle a GuC2Host interrupt (triggered when log buffer is half full) from GuC.
> 
> *** Ring buffer size ***
> It is up to 16K (4 pages) per LRC. Not HW limitation but firmware is setup in
> this way.
> 
> *** GuC address space ***
> GuC is not expecting any gfx GGTT address that falls into range [0, WOPCM_TOP),
> which is reserved for Boot ROM, SRAM and WOPCM. Currently this top address is
> 512K in order to fit in big HuC firmware.
> 
> In order to exclude 0-512K address space from GGTT, all gfx objects used by GuC
> is pinned with PIN_OFFSET_BIAS along with size of WOPCM.

There's lots of great comments both in the code and overview text in this
coverletter here, but no kerneldoc. Can you please create a patch on top
to document the new guc stuff in an overview section and also document the
non-static functions you're adding?

Thanks, Daniel
> 
> Alex Dai (13):
>   drm/i915: Add guc firmware interface headers
>   drm/i915: GuC firmware loader
>   drm/i915: Add firmware version check
>   drm/i915: Make several execlist helper functions external
>   drm/i915: Add functions to allocate / release gem obj for GuC
>   drm/i915: Functions to support command submission via GuC
>   drm/i915: Integration of GuC client
>   drm/i915: Interrupt routing for GuC scheduler
>   drm/i915: Enable commands submission via GuC
>   drm/i915: debugfs of GuC status
>   drm/i915: Enable GuC firmware log
>   drm/i915: Ring Context allocating for GuC
>   drm/i915: Notify GuC when RC6 state is changed
> 
> Dave Gordon (2):
>   drm/i915: Unified firmware loading mechanism
>   drm/i915: Defer default hardware context initialisation until first
>     open
> 
> Michael H. Nguyen (2):
>   drm/i915: Add i915_gem_object_write() to i915_gem.c
>   drm/i915: Move execlists defines from .c to .h
> 
> Sagar Kamble (1):
>   drm/i915: Taking forcewake during GuC load.
> 
>  drivers/gpu/drm/i915/Makefile              |   8 +-
>  drivers/gpu/drm/i915/i915_debugfs.c        | 102 +++++
>  drivers/gpu/drm/i915/i915_dma.c            |   6 +
>  drivers/gpu/drm/i915/i915_drv.h            |  17 +
>  drivers/gpu/drm/i915/i915_gem.c            |  39 +-
>  drivers/gpu/drm/i915/i915_gem_context.c    |  35 +-
>  drivers/gpu/drm/i915/i915_gem_stolen.c     |  10 +
>  drivers/gpu/drm/i915/i915_params.c         |   9 +
>  drivers/gpu/drm/i915/i915_reg.h            |  83 +++-
>  drivers/gpu/drm/i915/intel_guc.h           | 186 +++++++++
>  drivers/gpu/drm/i915/intel_guc_api.h       | 218 +++++++++++
>  drivers/gpu/drm/i915/intel_guc_client.c    | 607 +++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_guc_loader.c    | 466 ++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_guc_scheduler.c | 167 ++++++++
>  drivers/gpu/drm/i915/intel_lrc.c           | 112 ++----
>  drivers/gpu/drm/i915/intel_lrc.h           |   3 +
>  drivers/gpu/drm/i915/intel_pm.c            |   4 +
>  drivers/gpu/drm/i915/intel_ringbuffer.c    |   2 +-
>  drivers/gpu/drm/i915/intel_uc_loader.c     | 220 +++++++++++
>  drivers/gpu/drm/i915/intel_uc_loader.h     |  82 ++++
>  20 files changed, 2279 insertions(+), 97 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/intel_guc.h
>  create mode 100644 drivers/gpu/drm/i915/intel_guc_api.h
>  create mode 100644 drivers/gpu/drm/i915/intel_guc_client.c
>  create mode 100644 drivers/gpu/drm/i915/intel_guc_loader.c
>  create mode 100644 drivers/gpu/drm/i915/intel_guc_scheduler.c
>  create mode 100644 drivers/gpu/drm/i915/intel_uc_loader.c
>  create mode 100644 drivers/gpu/drm/i915/intel_uc_loader.h
> 
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 06/18] drm/i915: Defer default hardware context initialisation until first open
  2015-03-27  8:45   ` Daniel Vetter
@ 2015-03-30 19:11     ` Yu Dai
  2015-03-31 13:11       ` Daniel Vetter
  2015-03-31  9:29     ` Chris Wilson
  1 sibling, 1 reply; 29+ messages in thread
From: Yu Dai @ 2015-03-30 19:11 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 2862 bytes --]



On 03/27/2015 01:45 AM, Daniel Vetter wrote:
> On Thu, Mar 26, 2015 at 12:41:13PM -0700, yu.dai@intel.com wrote:
> > From: Dave Gordon <david.s.gordon@intel.com>
> >
> > In order to fully initialise the default contexts, we have to execute
> > batchbuffer commands on the GPU engines. But we can't do that until any
> > required firmware has been loaded, which may not be possible during
> > driver load, because the filesystem(s) containing the firmware may not
> > be mounted until later.
> >
> > Therefore, we now allow the first call to the firmware-loading code to
> > return -EAGAIN to indicate that it's not yet ready, and that it should
> > be retried when the device is first opened from user code, by which
> > time we expect that all required filesystems will have been mounted.
> > The late-retry code will then re-attempt to load the firmware if the
> > early attempt failed.
>
> We've tried a similar approach a while back and it doesn't work well in
> conjunction with rps - the hw tends to fall over if the context state
> isn't properly initialized when going into rc6.
I believe patch 18/18 of this series is to notify GuC when RC6 is on and 
off. I don't know much details of implementation inside firmware, but I 
believe GuC will take care of it properly.
> Why exactly can't we load that firmware right at boot-up, or at least
> stall correctly until it's there?
Dave G. wrote a very good comment about this. Sorry I lost it during 
patch squashing. Here is a copy of it. I will amend the comment in next 
version.

The GuC loader uses an asynchronous thread to fetch the firmware image
(aka "binary blob") from a file. This thread has then had to wait for
the mainline driver loading code to complete GEM initialisation before
it can convert the blob into a GEM object and transfer it to the GuC's
memory.

Unfortunately, with this scheme, the GuC loading was occurring*after*
the internally-generated batches used to initialise contexts had already
been submitted (using direct access to the ELSP, since the GuC wasn't
ready).

In addition, the one-way synchronisation mechanism resulted in the
firmware image being transfeered to the GuC at an indeterminate time
(just "sometime" after the mainline thread releases the device's
struct_mutex), with consequent confusion.

Rather than complicate the loader further by adding a second sync point
and arranging the handover of the struct_mutex from one thread to the
other, this commit reverses the synchronisation so that the mainline
thread waits for the asynchronous thread rather than vice versa. The
firmware loader now only has to save the reference to the blob and
signal a completion; the mainline thread can then continue with the rest
of the loading process when it catches up. The result is a much simpler
(and fully deterministic) process for loading the GuC firmware.


-Alex

[-- Attachment #1.2: Type: text/html, Size: 4352 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

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

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

* Re: [PATCH 06/18] drm/i915: Defer default hardware context initialisation until first open
  2015-03-27  8:45   ` Daniel Vetter
  2015-03-30 19:11     ` Yu Dai
@ 2015-03-31  9:29     ` Chris Wilson
  1 sibling, 0 replies; 29+ messages in thread
From: Chris Wilson @ 2015-03-31  9:29 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

On Fri, Mar 27, 2015 at 09:45:27AM +0100, Daniel Vetter wrote:
> On Thu, Mar 26, 2015 at 12:41:13PM -0700, yu.dai@intel.com wrote:
> > From: Dave Gordon <david.s.gordon@intel.com>
> > 
> > In order to fully initialise the default contexts, we have to execute
> > batchbuffer commands on the GPU engines. But we can't do that until any
> > required firmware has been loaded, which may not be possible during
> > driver load, because the filesystem(s) containing the firmware may not
> > be mounted until later.
> > 
> > Therefore, we now allow the first call to the firmware-loading code to
> > return -EAGAIN to indicate that it's not yet ready, and that it should
> > be retried when the device is first opened from user code, by which
> > time we expect that all required filesystems will have been mounted.
> > The late-retry code will then re-attempt to load the firmware if the
> > early attempt failed.
> 
> We've tried a similar approach a while back and it doesn't work well in
> conjunction with rps - the hw tends to fall over if the context state
> isn't properly initialized when going into rc6.
> 
> Why exactly can't we load that firmware right at boot-up, or at least
> stall correctly until it's there?

Note that is is very simple to build up a request queue prior to
enabling the submission port. Without having to touch core GEM code at
all.
-Chris

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

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

* Re: [PATCH 06/18] drm/i915: Defer default hardware context initialisation until first open
  2015-03-30 19:11     ` Yu Dai
@ 2015-03-31 13:11       ` Daniel Vetter
  0 siblings, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2015-03-31 13:11 UTC (permalink / raw)
  To: Yu Dai; +Cc: intel-gfx

On Mon, Mar 30, 2015 at 12:11:51PM -0700, Yu Dai wrote:
> 
> 
> On 03/27/2015 01:45 AM, Daniel Vetter wrote:
> >On Thu, Mar 26, 2015 at 12:41:13PM -0700, yu.dai@intel.com wrote:
> >> From: Dave Gordon <david.s.gordon@intel.com>
> >>
> >> In order to fully initialise the default contexts, we have to execute
> >> batchbuffer commands on the GPU engines. But we can't do that until any
> >> required firmware has been loaded, which may not be possible during
> >> driver load, because the filesystem(s) containing the firmware may not
> >> be mounted until later.
> >>
> >> Therefore, we now allow the first call to the firmware-loading code to
> >> return -EAGAIN to indicate that it's not yet ready, and that it should
> >> be retried when the device is first opened from user code, by which
> >> time we expect that all required filesystems will have been mounted.
> >> The late-retry code will then re-attempt to load the firmware if the
> >> early attempt failed.
> >
> >We've tried a similar approach a while back and it doesn't work well in
> >conjunction with rps - the hw tends to fall over if the context state
> >isn't properly initialized when going into rc6.
> I believe patch 18/18 of this series is to notify GuC when RC6 is on and
> off. I don't know much details of implementation inside firmware, but I
> believe GuC will take care of it properly.
> >Why exactly can't we load that firmware right at boot-up, or at least
> >stall correctly until it's there?
> Dave G. wrote a very good comment about this. Sorry I lost it during patch
> squashing. Here is a copy of it. I will amend the comment in next version.
> 
> The GuC loader uses an asynchronous thread to fetch the firmware image
> (aka "binary blob") from a file. This thread has then had to wait for
> the mainline driver loading code to complete GEM initialisation before
> it can convert the blob into a GEM object and transfer it to the GuC's
> memory.
> 
> Unfortunately, with this scheme, the GuC loading was occurring*after*
> the internally-generated batches used to initialise contexts had already
> been submitted (using direct access to the ELSP, since the GuC wasn't
> ready).
> 
> In addition, the one-way synchronisation mechanism resulted in the
> firmware image being transfeered to the GuC at an indeterminate time
> (just "sometime" after the mainline thread releases the device's
> struct_mutex), with consequent confusion.
> 
> Rather than complicate the loader further by adding a second sync point
> and arranging the handover of the struct_mutex from one thread to the
> other, this commit reverses the synchronisation so that the mainline
> thread waits for the asynchronous thread rather than vice versa. The
> firmware loader now only has to save the reference to the blob and
> signal a completion; the mainline thread can then continue with the rest
> of the loading process when it catches up. The result is a much simpler
> (and fully deterministic) process for loading the GuC firmware.

Still sounds rather fragile. Chris suggestion to just not submit anything
until guc firmware is loaded and then kick of a submission of all
outstanding requests sounds much better. That would naturally insert
minimal amounts of sync points everywhere you need them using the normal
GEM execution tracking.

The only other change we'd need (I think at least, didn't check details)
is to wait for the hw context init asynchronously in the rps worker.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

end of thread, other threads:[~2015-03-31 13:09 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-26 19:41 [PATCH 00/18] Command submission via GuC for SKL yu.dai
2015-03-26 19:41 ` [PATCH 01/18] drm/i915: Add guc firmware interface headers yu.dai
2015-03-26 19:41 ` [PATCH 02/18] drm/i915: Add i915_gem_object_write() to i915_gem.c yu.dai
2015-03-26 19:41 ` [PATCH 03/18] drm/i915: Unified firmware loading mechanism yu.dai
2015-03-26 19:41 ` [PATCH 04/18] drm/i915: GuC firmware loader yu.dai
2015-03-26 19:41 ` [PATCH 05/18] drm/i915: Add firmware version check yu.dai
2015-03-26 19:41 ` [PATCH 06/18] drm/i915: Defer default hardware context initialisation until first open yu.dai
2015-03-27  8:45   ` Daniel Vetter
2015-03-30 19:11     ` Yu Dai
2015-03-31 13:11       ` Daniel Vetter
2015-03-31  9:29     ` Chris Wilson
2015-03-26 19:41 ` [PATCH 07/18] drm/i915: Move execlists defines from .c to .h yu.dai
2015-03-26 19:41 ` [PATCH 08/18] drm/i915: Make several execlist helper functions external yu.dai
2015-03-26 19:41 ` [PATCH 09/18] drm/i915: Add functions to allocate / release gem obj for GuC yu.dai
2015-03-27  8:48   ` Daniel Vetter
2015-03-27  8:49     ` Daniel Vetter
2015-03-26 19:41 ` [PATCH 10/18] drm/i915: Functions to support command submission via GuC yu.dai
2015-03-26 19:41 ` [PATCH 11/18] drm/i915: Integration of GuC client yu.dai
2015-03-26 19:41 ` [PATCH 12/18] drm/i915: Interrupt routing for GuC scheduler yu.dai
2015-03-26 19:41 ` [PATCH 13/18] drm/i915: Enable commands submission via GuC yu.dai
2015-03-26 19:41 ` [PATCH 14/18] drm/i915: debugfs of GuC status yu.dai
2015-03-26 19:41 ` [PATCH 15/18] drm/i915: Enable GuC firmware log yu.dai
2015-03-26 19:41 ` [PATCH 16/18] drm/i915: Ring Context allocating for GuC yu.dai
2015-03-26 19:41 ` [PATCH 17/18] drm/i915: Taking forcewake during GuC load yu.dai
2015-03-27  8:55   ` Daniel Vetter
2015-03-26 19:41 ` [PATCH 18/18] drm/i915: Notify GuC when RC6 state is changed yu.dai
2015-03-27  1:24   ` shuang.he
2015-03-27  8:54   ` Daniel Vetter
2015-03-27  8:59 ` [PATCH 00/18] Command submission via GuC for SKL Daniel Vetter

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.