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

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

v3:
a) Fix regressions found in igt. The debugfs entries for GuC should not be
   avaliable for no-GuC platform.
b) Firmware name is changed to <platform core>_guc_ver<major version>.bin. In
   this way, end user can roll back to old kernel without knowledge of which
   version firmware is needed by kernel, as long as all version of firmware
   are kept in disk.
c) Fix a lockdep issue in allocating context_desc id.
d) Modify code accordingly because of recent change in ppgtt PDP.
e) Firmware loading for GEN8 is dropped becasuse there is no use case for now.

v2:
a) Add kernel-doc patch. All comments here have been moved into source code.
b) Change the way to load fw because a signed firmware has different layout.
c) One previous patch to notify GuC about RC6 feature is dropped for future
   submission. Need to double check the potential racing condition.

v1: 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 (10):
  drm/i915: Add guc firmware interface headers
  drm/i915: GuC firmware loader
  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
  Documentation/drm: kerneldoc for GuC

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.

 Documentation/DocBook/drm.tmpl             |  19 +
 drivers/gpu/drm/i915/Makefile              |   8 +-
 drivers/gpu/drm/i915/i915_debugfs.c        | 108 +++++
 drivers/gpu/drm/i915/i915_dma.c            |   6 +
 drivers/gpu/drm/i915/i915_drv.h            |  18 +
 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            |  92 +++-
 drivers/gpu/drm/i915/intel_guc.h           | 191 +++++++++
 drivers/gpu/drm/i915/intel_guc_api.h       | 217 ++++++++++
 drivers/gpu/drm/i915/intel_guc_client.c    | 645 +++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_loader.c    | 550 ++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_scheduler.c | 156 +++++++
 drivers/gpu/drm/i915/intel_lrc.c           | 126 ++----
 drivers/gpu/drm/i915/intel_lrc.h           |   2 +
 drivers/gpu/drm/i915/intel_ringbuffer.c    |   2 +-
 drivers/gpu/drm/i915/intel_uc_loader.c     | 247 +++++++++++
 drivers/gpu/drm/i915/intel_uc_loader.h     |  82 ++++
 20 files changed, 2454 insertions(+), 108 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] 37+ messages in thread

* [PATCH v3 01/15] drm/i915: Add guc firmware interface headers
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-17 21:21 ` [PATCH v3 02/15] drm/i915: Add i915_gem_object_write() to i915_gem.c yu.dai
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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] 37+ messages in thread

* [PATCH v3 02/15] drm/i915: Add i915_gem_object_write() to i915_gem.c
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
  2015-04-17 21:21 ` [PATCH v3 01/15] drm/i915: Add guc firmware interface headers yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-21 18:41   ` Dave Gordon
  2015-04-17 21:21 ` [PATCH v3 03/15] drm/i915: Unified firmware loading mechanism yu.dai
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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 40ef672..6e8d106 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2645,6 +2645,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 f7b8766..44154fe 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -5260,3 +5260,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] 37+ messages in thread

* [PATCH v3 03/15] drm/i915: Unified firmware loading mechanism
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
  2015-04-17 21:21 ` [PATCH v3 01/15] drm/i915: Add guc firmware interface headers yu.dai
  2015-04-17 21:21 ` [PATCH v3 02/15] drm/i915: Add i915_gem_object_write() to i915_gem.c yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-23 17:12   ` Dave Gordon
  2015-04-17 21:21 ` [PATCH v3 04/15] drm/i915: GuC firmware loader yu.dai
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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 | 244 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_uc_loader.h |  78 +++++++++++
 3 files changed, 325 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..bc499f4
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_uc_loader.c
@@ -0,0 +1,244 @@
+/*
+ * 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"
+
+/**
+ * DOC: Microcontroller (uC) firmware loading support
+ *
+ * Provide a more generic way to load firmware between the mainline driver (aka
+ * "main thread") and the loader (aka "async thread"). The firmware (aka "binary
+ * blob") loading process is split into two stages: fetch and load.
+ *
+ * For the first (fetch) stage, the mainline driver issues an firmware request
+ * call (request_firmware_nowait) to OS. The asynchronous thread will fetch the
+ * firmware blob from an external file into a GEM object, then notify mainline
+ * thread when it is done. The second (load) stage happens in main thread, which
+ * is to load the blob content into an onboard microcontroller. The load stage
+ * is implemented in mainline driver, but the intel_uc_fw_status provides the
+ * common code to track the phases of fetching or loading the firmware.
+ *
+ */
+
+/*
+ * 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;
+	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;
+	}
+
+	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;
+	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;
+	uc_fw->uc_fw_blob = NULL;
+	release_firmware(fw);		/* OK even if fw is NULL */
+}
+
+/**
+ * intel_uc_fw_check() - check the status of the firmware fetching process
+ * @dev:	drm device
+ * @uc_fw:	intel_uc_fw structure
+
+ * If it's still PENDING, wait for completion first, then check and return the
+ * outcome.
+ *
+ * Return:	non-zero code on error
+ */
+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);
+}
+
+/**
+ * intel_uc_fw_init() - initiate the fetching of firmware
+ * @dev:	drm device
+ * @uc_fw:	intel_uc_fw structure
+ * @name:	firmware name
+ * @fw_path:	path prefix
+ *
+ * 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)
+{
+	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 (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);
+}
+
+/**
+ * intel_uc_fw_fini() - clean up all uC firmware-related data
+ * @dev:	drm device
+ * @uc_fw:	intel_uc_fw structure
+ */
+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..0994f98
--- /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);
+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] 37+ messages in thread

* [PATCH v3 04/15] drm/i915: GuC firmware loader
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (2 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 03/15] drm/i915: Unified firmware loading mechanism yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-23 17:48   ` Dave Gordon
  2015-04-17 21:21 ` [PATCH v3 05/15] drm/i915: Defer default hardware context initialisation until first open yu.dai
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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         |   7 +
 drivers/gpu/drm/i915/i915_gem_stolen.c  |  10 +
 drivers/gpu/drm/i915/i915_reg.h         |   4 +-
 drivers/gpu/drm/i915/intel_guc.h        | 103 ++++++++++
 drivers/gpu/drm/i915/intel_guc_loader.c | 348 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_uc_loader.c  |   3 +
 drivers/gpu/drm/i915/intel_uc_loader.h  |   4 +
 9 files changed, 486 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 e44116f..5d50b5b 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);
@@ -861,6 +862,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;
@@ -1108,6 +1113,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_context_fini(dev);
 	mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 6e8d106..235fc08 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:
  */
@@ -1581,6 +1582,8 @@ struct drm_i915_private {
 
 	struct intel_gmbus gmbus[GMBUS_NUM_PINS];
 
+	struct intel_guc guc;
+
 	/** gmbus_mutex protects against concurrent usage of the single hw gmbus
 	 * controller on different i2c buses. */
 	struct mutex gmbus_mutex;
@@ -2430,6 +2433,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))
+#define HAS_GUC_SCHED(dev)	(IS_GEN9(dev))
+
 #define INTEL_PCH_DEVICE_ID_MASK		0xff00
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE		0x3b00
 #define INTEL_PCH_CPT_DEVICE_ID_TYPE		0x1c00
@@ -3008,6 +3014,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 348ed5a..fbf7667 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 d47afbc..f7c00dc 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -6693,7 +6693,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..4fafcec
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -0,0 +1,103 @@
+/*
+ * 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_CSS_HEADER_OFFSET	0
+#define UOS_CSS_HEADER_SIZE	0x80
+#define   UOS_VER_MINOR_OFFSET	0x44
+#define   UOS_VER_MAJOR_OFFSET	0x46
+#define UOS_RSA_SIG_OFFSET	0x80
+#define UOS_RSA_SIG_SIZE	0x100
+#define UOS_CSS_SIGNING_SIZE	0x204
+#define UOS_UCODE_OFFSET	(UOS_CSS_HEADER_SIZE + UOS_CSS_SIGNING_SIZE)
+
+#define UOS_RSA_SCRATCH_0	0xc200
+#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..a999044
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -0,0 +1,348 @@
+/*
+ * 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"
+
+/**
+ * DOC: GuC
+ *
+ * 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 replace the legacy
+ * ExecList submission.
+ *
+ * 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.
+ * i915 kernel driver set the minimal firmware version required per platform.
+ * The firmware installation package will install (symbolic link) proper version
+ * of firmware.
+ *
+ */
+
+#define I915_SKL_GUC_UCODE "i915/skl_guc_ver1.bin"
+MODULE_FIRMWARE(I915_SKL_GUC_UCODE);
+#define I915_BXT_GUC_UCODE "i915/bxt_guc_ver1.bin"
+MODULE_FIRMWARE(I915_BXT_GUC_UCODE);
+
+/* 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.
+
+ * GuC Firmware layout:
+ * +-------------------------------+  ----
+ * |          CSS header           |  128B
+ * +-------------------------------+  ----
+ * |         RSA signature         |  256B
+ * +-------------------------------+  ----
+ * |         RSA public Key        |  256B
+ * +-------------------------------+  ----
+ * |       Public key modulus      |    4B
+ * +-------------------------------+  ----
+ * |             uCode             |
+ * +-------------------------------+  ----
+ *
+ * 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.
+ *
+ * Be note that GuC need the CSS header plus uKernel code to be copied as one
+ * chunk of data. RSA sig data is loaded via MMIO.
+ */
+static int ucode_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;
+	unsigned long offset;
+	struct sg_table *sg = fw_obj->pages;
+	u32 status, ucode_size, *blob;
+	int i, ret = 0;
+
+	/* Copy RSA signature from the fw image to HW for verification */
+	blob = (uint32_t *)(dev_priv->guc.guc_fw.uc_fw_blob->data
+			+ UOS_RSA_SIG_OFFSET);
+	for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(uint32_t); i++)
+		I915_WRITE(UOS_RSA_SCRATCH_0 + i * sizeof(uint32_t), blob[i]);
+
+	/* Re-arrange data per GuC request (CSS header + uCode) */
+
+	/* Copy CSS header  */
+	blob = (uint32_t *)(dev_priv->guc.guc_fw.uc_fw_blob->data
+			+ UOS_CSS_HEADER_OFFSET);
+	sg_copy_from_buffer(sg->sgl, sg->nents, blob, UOS_CSS_HEADER_SIZE);
+
+	/* Copy ucode */
+	blob = (uint32_t *)(dev_priv->guc.guc_fw.uc_fw_blob->data
+			+ UOS_UCODE_OFFSET);
+	ucode_size = guc_fw->uc_fw_size - UOS_UCODE_OFFSET;
+	sg_pcopy_from_buffer(sg->sgl, sg->nents, blob,
+			ucode_size, UOS_CSS_HEADER_SIZE);
+
+	/* Set the source address for the new blob */
+	offset = i915_gem_obj_ggtt_offset(fw_obj);
+	I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
+	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, ucode_size + UOS_CSS_HEADER_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);
+	}
+
+	set_guc_init_params(dev_priv);
+
+	ret = ucode_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;
+}
+
+/**
+ * intel_guc_load_ucode() - load ucode to hw
+ *
+ * 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;
+}
+
+/*
+ * 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 major / minor version are two
+ * bytes each - in *u16*
+ */
+static bool intel_guc_ucode_check(struct intel_uc_fw *guc_fw)
+{
+	uint32_t major, minor;
+	u8 *css_header = (u8 *)guc_fw->uc_fw_blob->data + UOS_CSS_HEADER_OFFSET;
+
+	major = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET);
+	minor = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET);
+
+	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;
+}
+
+/**
+ * intel_guc_ucode_init() - init a firmware loading request
+ */
+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 (!HAS_GUC_UCODE(dev)) {
+		guc_fw->uc_fw_fetch_status = INTEL_UC_FIRMWARE_NONE;
+		guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_NONE;
+		return;
+	}
+
+	if (IS_SKYLAKE(dev)) {
+		path = I915_SKL_GUC_UCODE;
+		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_BROXTON(dev)) {
+		path = I915_BXT_GUC_UCODE;
+		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);
+}
+
+/**
+ * intel_guc_ucode_fini() - clean up firmware blob allocated
+ */
+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);
+}
diff --git a/drivers/gpu/drm/i915/intel_uc_loader.c b/drivers/gpu/drm/i915/intel_uc_loader.c
index bc499f4..65031ff 100644
--- a/drivers/gpu/drm/i915/intel_uc_loader.c
+++ b/drivers/gpu/drm/i915/intel_uc_loader.c
@@ -77,6 +77,9 @@ static void uc_fw_finish(struct drm_device *dev, struct intel_uc_fw *uc_fw)
 		uc_fw->uc_fw_blob = fw;
 	}
 
+	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;
diff --git a/drivers/gpu/drm/i915/intel_uc_loader.h b/drivers/gpu/drm/i915/intel_uc_loader.h
index 0994f98..4ed6e94 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);
 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] 37+ messages in thread

* [PATCH v3 05/15] drm/i915: Defer default hardware context initialisation until first open
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (3 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 04/15] drm/i915: GuC firmware loader yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-23 12:25   ` Dave Gordon
  2015-04-17 21:21 ` [PATCH v3 06/15] drm/i915: Move execlists defines from .c to .h yu.dai
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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 | 25 +++++++++++++++++++++--
 5 files changed, 63 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 235fc08..d128ac4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1760,6 +1760,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 44154fe..b7bd288 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4888,8 +4888,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 e4c57a3..3795df2 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -447,23 +447,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 4fafcec..0a73122 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -96,7 +96,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 a999044..a17f210 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -246,24 +246,45 @@ out:
  * intel_guc_load_ucode() - load ucode to hw
  *
  * 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;
 
+	if (!HAS_GUC_UCODE(dev))
+		return 0;
+
+	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;
-- 
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] 37+ messages in thread

* [PATCH v3 06/15] drm/i915: Move execlists defines from .c to .h
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (4 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 05/15] drm/i915: Defer default hardware context initialisation until first open yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-22 14:02   ` Dave Gordon
  2015-04-17 21:21 ` [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC yu.dai
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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  | 77 ++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.c | 76 ---------------------------------------
 2 files changed, 77 insertions(+), 76 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index f7c00dc..9ec7bdc 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7748,4 +7748,81 @@ 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)
+
+#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) { \
+	const u64 _addr = test_bit(n, ppgtt->pdp.used_pdpes) ? \
+		ppgtt->pdp.page_directory[n]->daddr : \
+		ppgtt->scratch_pd->daddr; \
+	reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \
+	reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \
+}
+
+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 a798d75..a9814a2 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -136,82 +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)
-
-#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) { \
-	const u64 _addr = test_bit(n, ppgtt->pdp.used_pdpes) ? \
-		ppgtt->pdp.page_directory[n]->daddr : \
-		ppgtt->scratch_pd->daddr; \
-	reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \
-	reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \
-}
-
-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] 37+ messages in thread

* [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (5 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 06/15] drm/i915: Move execlists defines from .c to .h yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-18 13:47   ` Chris Wilson
  2015-04-17 21:21 ` [PATCH v3 08/15] drm/i915: Functions to support command submission via GuC yu.dai
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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 | 55 +++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 0a73122..6b2b5bf 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -99,5 +99,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 a17f210..04c2b11 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -40,6 +40,12 @@
  * The firmware installation package will install (symbolic link) proper version
  * of firmware.
  *
+ * GuC address space:
+ * GuC does not allow 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 exclude 0-512K address space from GGTT, all gfx objects
+ * used by GuC is pinned with PIN_OFFSET_BIAS along with size of WOPCM.
+ *
  */
 
 #define I915_SKL_GUC_UCODE "i915/skl_guc_ver1.bin"
@@ -47,6 +53,55 @@ MODULE_FIRMWARE(I915_SKL_GUC_UCODE);
 #define I915_BXT_GUC_UCODE "i915/bxt_guc_ver1.bin"
 MODULE_FIRMWARE(I915_BXT_GUC_UCODE);
 
+/**
+ * intel_guc_allocate_gem_obj() - Allocate gem object for GuC usage
+ * @dev:	drm device
+ * @size:	size of object
+ *
+ * This is a wrapper to create a gem obj. In order to use it inside GuC, the
+ * object needs to be pinned lifetime. Also we must pin it to gtt space other
+ * than [0, GUC_WOPCM_SIZE] because this range is reserved inside GuC.
+ *
+ * Return:	A drm_i915_gem_object if successful, otherwise NULL.
+ */
+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;
+}
+
+/**
+ * intel_guc_release_gem_obj() - Release gem object allocated for GuC usage
+ * @obj:	gem obj to be released
+  */
+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);
+}
+
 /* Read GuC status register (GUC_STATUS)
  * Return true if get a success code from normal boot or RC6 boot
  */
-- 
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] 37+ messages in thread

* [PATCH v3 08/15] drm/i915: Functions to support command submission via GuC
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (6 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-18 13:48   ` Chris Wilson
  2015-04-17 21:21 ` [PATCH v3 09/15] drm/i915: Integration of GuC client yu.dai
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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.

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/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           |  9 ++++
 drivers/gpu/drm/i915/intel_guc_loader.c    | 56 ++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_guc_scheduler.c | 78 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.c           | 23 +++------
 drivers/gpu/drm/i915/intel_ringbuffer.c    |  2 +-
 8 files changed, 158 insertions(+), 18 deletions(-)
 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 d128ac4..4134db9 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2498,6 +2498,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 bb64415..9ad2e27 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 = {
 	.mmio_debug = 0,
 	.verbose_state_checks = 1,
 	.nuclear_pageflip = 0,
+	.enable_guc_scheduling = false,
 };
 
 module_param_named(modeset, i915.modeset, int, 0400);
@@ -184,3 +185,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 6b2b5bf..d49549c 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
@@ -103,4 +106,10 @@ 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);
+
 #endif
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 04c2b11..15c055a 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -236,6 +236,36 @@ 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 = IS_GEN9(dev_priv->dev) ? GEN9_LR_CONTEXT_RENDER_SIZE :
+				GEN8_LR_CONTEXT_RENDER_SIZE;
+		pgs >>= 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++)
@@ -322,8 +352,13 @@ int intel_guc_load_ucode(struct drm_device *dev, bool wait)
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 	int err;
 
-	if (!HAS_GUC_UCODE(dev))
+	if (!HAS_GUC_UCODE(dev)) {
+		i915.enable_guc_scheduling = false;
 		return 0;
+	}
+
+	if (!HAS_GUC_SCHED(dev))
+		i915.enable_guc_scheduling = false;
 
 	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);
@@ -339,15 +374,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;
 }
@@ -420,5 +472,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..1047192
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -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.
+ *
+ */
+#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 */
+}
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index a9814a2..e5d6a74 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -1722,20 +1722,10 @@ static 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;
 }
@@ -1784,6 +1774,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_object(dev, context_size);
 	if (IS_ERR(ctx_obj)) {
@@ -1812,7 +1805,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 de8c074..8f13e80 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1993,7 +1993,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
 	INIT_LIST_HEAD(&ring->request_list);
 	INIT_LIST_HEAD(&ring->execlist_queue);
 	i915_gem_batch_pool_init(dev, &ring->batch_pool);
-	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] 37+ messages in thread

* [PATCH v3 09/15] drm/i915: Integration of GuC client
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (7 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 08/15] drm/i915: Functions to support command submission via GuC yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-17 21:21 ` [PATCH v3 10/15] drm/i915: Interrupt routing for GuC scheduler yu.dai
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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    | 430 +++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_loader.c    |   7 +
 drivers/gpu/drm/i915/intel_guc_scheduler.c |  29 +-
 6 files changed, 523 insertions(+), 3 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 4134db9..6760b9a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1850,6 +1850,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 d49549c..72c4ce2 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
@@ -98,6 +125,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);
@@ -112,4 +155,13 @@ void guc_scheduler_fini(struct drm_device *dev);
 int guc_scheduler_enable(struct drm_device *dev);
 void guc_scheduler_disable(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..094c553
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_client.c
@@ -0,0 +1,430 @@
+/*
+ * 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"
+
+/**
+ * DOC: GuC Client
+ *
+ * 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.
+ *
+ * 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.
+ * See intel_guc_action()
+ *
+ * Doorbells:
+ * Doorbells are interrupts to uKernel. A doorbell is a single cache line (QW)
+ * mapped into process space.
+ *
+ */
+
+/*
+ * 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_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);
+		ida_simple_remove(&guc->ctx_ids, client->ctx_index);
+	}
+
+	kfree(client);
+}
+
+/**
+ * i915_guc_client_alloc() - Allocate an i915_guc_client
+ * @dev:	drm device
+ * @priority:	four levels priority _CRITICAL, _HIGH, _NORMAL and _LOW
+ * 		The kernel client to replace ExecList submission is created with
+ * 		NORMAL priority. Priority of a client for scheduler can be HIGH,
+ * 		while a preemption context can use CRITICAL.
+ *
+ * Return:	An i915_guc_client object if success.
+ */
+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 = (uint32_t)ida_simple_get(&guc->ctx_ids, 0,
+			MAX_GUC_GPU_CONTEXTS, GFP_KERNEL);
+	if (client->ctx_index >= MAX_GUC_GPU_CONTEXTS) {
+		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;
+}
+
+/**
+ * i915_guc_client_submit() - Submit commands through GuC
+ * @client:	the guc client where commands will go through
+ * @ctx:	LRC where commands come from
+ * @ring:	HW engine that will excute the commands
+ *
+ * Return:	0 if succeed
+ */
+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 15c055a..c784d64 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -294,12 +294,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 |
diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
index 1047192..962443c 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,19 +62,42 @@ 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;
+	}
 }
-- 
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] 37+ messages in thread

* [PATCH v3 10/15] drm/i915: Interrupt routing for GuC scheduler
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (8 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 09/15] drm/i915: Integration of GuC client yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-17 21:21 ` [PATCH v3 11/15] drm/i915: Enable commands submission via GuC yu.dai
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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 9ec7bdc..ccffd02 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1610,12 +1610,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
 
@@ -5565,11 +5571,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 72c4ce2..cf3da73 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -141,6 +141,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 962443c..669d066 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] 37+ messages in thread

* [PATCH v3 11/15] drm/i915: Enable commands submission via GuC
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (9 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 10/15] drm/i915: Interrupt routing for GuC scheduler yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-17 21:21 ` [PATCH v3 12/15] drm/i915: debugfs of GuC status yu.dai
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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 | 198 +++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_lrc.c        |  27 ++++-
 drivers/gpu/drm/i915/intel_lrc.h        |   2 +
 4 files changed, 223 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index cf3da73..56c15e3 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 094c553..d74bc5fd 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"
 
@@ -52,6 +53,14 @@
  * Doorbells are interrupts to uKernel. A doorbell is a single cache line (QW)
  * mapped into process space.
  *
+ * 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 needed 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.
+ * See add_workqueue_item()
+ *
  */
 
 /*
@@ -395,6 +404,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);
@@ -414,6 +425,183 @@ 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 void guc_update_context(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 = ctx->engine[ring->id].state;
+	struct page *page;
+	uint32_t *reg_state;
+
+	page = i915_gem_object_get_page(ctx_obj, 1);
+	reg_state = kmap_atomic(page);
+
+	reg_state[CTX_RING_BUFFER_START + 1] =
+			i915_gem_obj_ggtt_offset(ringbuf->obj);
+
+	/* True PPGTT with dynamic page allocation: update PDP registers and
+	 * point the unallocated PDPs to the scratch page
+	 */
+	if (ctx->ppgtt) {
+		ASSIGN_CTX_PDP(ctx->ppgtt, reg_state, 3);
+		ASSIGN_CTX_PDP(ctx->ppgtt, reg_state, 2);
+		ASSIGN_CTX_PDP(ctx->ppgtt, reg_state, 1);
+		ASSIGN_CTX_PDP(ctx->ppgtt, reg_state, 0);
+	}
+
+	kunmap_atomic(reg_state);
+}
+
+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;
+	u32 wq_off = 0, tail = ringbuf->tail, wq_len;
+	int ret;
+
+	ctx_obj = ctx->engine[ring->id].state;
+
+	/* Need this because of the deferred pin ctx and ring */
+	/* Shall we move this right after ring is pinned? */
+	guc_update_context(ctx, ring);
+
+	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;
+}
+
 /**
  * i915_guc_client_submit() - Submit commands through GuC
  * @client:	the guc client where commands will go through
@@ -426,5 +614,13 @@ 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_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index e5d6a74..67e19f1 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;
@@ -628,13 +628,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 logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf,
@@ -898,18 +902,23 @@ 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));
 	if (ctx->engine[ring->id].pin_count++ == 0) {
-		ret = i915_gem_obj_ggtt_pin(ctx_obj,
-				GEN8_LR_CONTEXT_ALIGN, 0);
+		ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN,
+				PIN_OFFSET_BIAS | GUC_WOPCM_SIZE_VALUE);
 		if (ret)
 			goto reset_pin_count;
 
 		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;
@@ -1258,8 +1267,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;
@@ -1786,7 +1800,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 	}
 
 	if (is_global_default_ctx) {
-		ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0);
+		ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN,
+				PIN_OFFSET_BIAS | GUC_WOPCM_SIZE_VALUE);
 		if (ret) {
 			DRM_DEBUG_DRIVER("Pin LRC backing obj failed: %d\n",
 					ret);
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 04d3a6d..19c9a02 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -85,6 +85,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] 37+ messages in thread

* [PATCH v3 12/15] drm/i915: debugfs of GuC status
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (10 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 11/15] drm/i915: Enable commands submission via GuC yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-17 21:21 ` [PATCH v3 13/15] drm/i915: Enable GuC firmware log yu.dai
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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     | 79 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc.h        | 13 ++++++
 drivers/gpu/drm/i915/intel_guc_client.c | 33 +++++++++++---
 3 files changed, 118 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 9c2b9e4..f12bbee 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2310,6 +2310,83 @@ 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;
+
+	if (!HAS_GUC_UCODE(dev_priv->dev))
+		return 0;
+
+	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;
+
+	if (!i915.enable_guc_scheduling)
+		return 0;
+
+	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;
@@ -4776,6 +4853,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 56c15e3..641fd14 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 d74bc5fd..3590e2c 100644
--- a/drivers/gpu/drm/i915/intel_guc_client.c
+++ b/drivers/gpu/drm/i915/intel_guc_client.c
@@ -87,6 +87,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]);
 
@@ -105,7 +108,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);
 
@@ -614,13 +621,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] 37+ messages in thread

* [PATCH v3 13/15] drm/i915: Enable GuC firmware log
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (11 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 12/15] drm/i915: debugfs of GuC status yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-17 21:21 ` [PATCH v3 14/15] drm/i915: Taking forcewake during GuC load yu.dai
  2015-04-17 21:21 ` [PATCH v3 15/15] Documentation/drm: kerneldoc for GuC yu.dai
  14 siblings, 0 replies; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 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        |  1 +
 drivers/gpu/drm/i915/intel_guc_loader.c | 64 ++++++++++++++++++++++++++++++++-
 5 files changed, 99 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index f12bbee..0ce1e23 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2387,6 +2387,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;
@@ -4855,6 +4883,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 6760b9a..24b94da 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2504,6 +2504,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 9ad2e27..95e4eb7 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -54,6 +54,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);
@@ -188,3 +189,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 641fd14..54572f7 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;
 
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index c784d64..d1fd11e 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -46,6 +46,12 @@
  * 512K. 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.
  *
+ * 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.
+ *
  */
 
 #define I915_SKL_GUC_UCODE "i915/skl_guc_ver1.bin"
@@ -53,6 +59,10 @@ MODULE_FIRMWARE(I915_SKL_GUC_UCODE);
 #define I915_BXT_GUC_UCODE "i915/bxt_guc_ver1.bin"
 MODULE_FIRMWARE(I915_BXT_GUC_UCODE);
 
+#define GUC_LOG_DPC_PAGES	3
+#define GUC_LOG_ISR_PAGES	3
+#define GUC_LOG_CRASH_PAGES	1
+
 /**
  * intel_guc_allocate_gem_obj() - Allocate gem object for GuC usage
  * @dev:	drm device
@@ -211,6 +221,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];
@@ -234,7 +289,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) {
@@ -479,6 +536,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);
-- 
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] 37+ messages in thread

* [PATCH v3 14/15] drm/i915: Taking forcewake during GuC load.
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (12 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 13/15] drm/i915: Enable GuC firmware log yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-28 15:22   ` Dave Gordon
  2015-04-17 21:21 ` [PATCH v3 15/15] Documentation/drm: kerneldoc for GuC yu.dai
  14 siblings, 1 reply; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 UTC (permalink / raw)
  To: intel-gfx

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

The firmware loader will use GuC DMA engine to move data from
ggtt to WOPCM. 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 d1fd11e..f19eb90 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -340,6 +340,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)
@@ -388,6 +389,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] 37+ messages in thread

* [PATCH v3 15/15] Documentation/drm: kerneldoc for GuC
  2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
                   ` (13 preceding siblings ...)
  2015-04-17 21:21 ` [PATCH v3 14/15] drm/i915: Taking forcewake during GuC load yu.dai
@ 2015-04-17 21:21 ` yu.dai
  2015-04-18  1:13   ` shuang.he
  14 siblings, 1 reply; 37+ messages in thread
From: yu.dai @ 2015-04-17 21:21 UTC (permalink / raw)
  To: intel-gfx

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

Add overview design of GuC, plus some key points related to
the implementation.

Signed-off-by: Alex Dai <yu.dai@intel.com>
---
 Documentation/DocBook/drm.tmpl | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index a8509c2..35199f0 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -4206,6 +4206,25 @@ int num_ioctls;</synopsis>
     </sect1>
 
     <sect1>
+      <title>GuC Scheduler</title>
+      <sect2>
+        <title>Microcontroller (uC) firmware loading support</title>
+!Pdrivers/gpu/drm/i915/intel_uc_loader.c Microcontroller (uC) firmware loading support
+!Idrivers/gpu/drm/i915/intel_uc_loader.c
+      </sect2>
+      <sect2>
+        <title>GuC</title>
+!Pdrivers/gpu/drm/i915/intel_guc_loader.c GuC
+!Idrivers/gpu/drm/i915/intel_guc_loader.c
+      </sect2>
+      <sect2>
+        <title>GuC Client</title>
+!Pdrivers/gpu/drm/i915/intel_guc_client.c GuC Client
+!Idrivers/gpu/drm/i915/intel_guc_client.c
+      </sect2>
+    </sect1>
+
+    <sect1>
       <title> Tracing </title>
       <para>
     This sections covers all things related to the tracepoints implemented in
-- 
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] 37+ messages in thread

* Re: [PATCH v3 15/15] Documentation/drm: kerneldoc for GuC
  2015-04-17 21:21 ` [PATCH v3 15/15] Documentation/drm: kerneldoc for GuC yu.dai
@ 2015-04-18  1:13   ` shuang.he
  0 siblings, 0 replies; 37+ messages in thread
From: shuang.he @ 2015-04-18  1:13 UTC (permalink / raw)
  To: shuang.he, ethan.gao, intel-gfx, yu.dai

Tested-By: Intel Graphics QA PRTS (Patch Regression Test System Contact: shuang.he@intel.com)
Task id: 6226
-------------------------------------Summary-------------------------------------
Platform          Delta          drm-intel-nightly          Series Applied
PNV                                  276/276              276/276
ILK                                  302/302              302/302
SNB                                  318/318              318/318
IVB                                  341/341              341/341
BYT                                  287/287              287/287
HSW                 -1              395/395              394/395
BDW                                  318/318              318/318
-------------------------------------Detailed-------------------------------------
Platform  Test                                drm-intel-nightly          Series Applied
 HSW  igt@gem_pwrite_pread@snooped-pwrite-blt-cpu_mmap-performance      DMESG_WARN(1)PASS(8)      DMESG_WARN(1)PASS(1)
(dmesg patch applied)drm:i915_hangcheck_elapsed[i915]]*ERROR*Hangcheck_timer_elapsed...blitter_ring_idle@Hangcheck timer elapsed... blitter ring idle
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] 37+ messages in thread

* Re: [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-04-17 21:21 ` [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC yu.dai
@ 2015-04-18 13:47   ` Chris Wilson
  2015-04-20 16:02     ` Yu Dai
  0 siblings, 1 reply; 37+ messages in thread
From: Chris Wilson @ 2015-04-18 13:47 UTC (permalink / raw)
  To: yu.dai; +Cc: intel-gfx

On Fri, Apr 17, 2015 at 02:21:12PM -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.

If the region is reserved, remove that region from the GGTT drm_mm range
manager. Then the restriction is applied to all objects and not in a
hodge-podge fashion like this.
-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] 37+ messages in thread

* Re: [PATCH v3 08/15] drm/i915: Functions to support command submission via GuC
  2015-04-17 21:21 ` [PATCH v3 08/15] drm/i915: Functions to support command submission via GuC yu.dai
@ 2015-04-18 13:48   ` Chris Wilson
  2015-04-20 16:07     ` Yu Dai
  0 siblings, 1 reply; 37+ messages in thread
From: Chris Wilson @ 2015-04-18 13:48 UTC (permalink / raw)
  To: yu.dai; +Cc: intel-gfx

On Fri, Apr 17, 2015 at 02:21:13PM -0700, yu.dai@intel.com wrote:
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index de8c074..8f13e80 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1993,7 +1993,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
>  	INIT_LIST_HEAD(&ring->request_list);
>  	INIT_LIST_HEAD(&ring->execlist_queue);
>  	i915_gem_batch_pool_init(dev, &ring->batch_pool);
> -	ringbuf->size = 32 * PAGE_SIZE;
> +	ringbuf->size = 4 * PAGE_SIZE;
>  	ringbuf->ring = ring;
>  	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));

NAK.
-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] 37+ messages in thread

* Re: [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-04-18 13:47   ` Chris Wilson
@ 2015-04-20 16:02     ` Yu Dai
  2015-04-20 19:52       ` Chris Wilson
  0 siblings, 1 reply; 37+ messages in thread
From: Yu Dai @ 2015-04-20 16:02 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx



On 04/18/2015 06:47 AM, Chris Wilson wrote:
> On Fri, Apr 17, 2015 at 02:21:12PM -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.
>
> If the region is reserved, remove that region from the GGTT drm_mm range
> manager. Then the restriction is applied to all objects and not in a
> hodge-podge fashion like this.
>
I don't think I have clearly explained this. GTT range [0, WPOCM size] 
can't be used by GuC firmware, but still others can use it without any 
issue. PIN_OFFSET_BIAS is great for such use case.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v3 08/15] drm/i915: Functions to support command submission via GuC
  2015-04-18 13:48   ` Chris Wilson
@ 2015-04-20 16:07     ` Yu Dai
  2015-04-20 19:43       ` Chris Wilson
  0 siblings, 1 reply; 37+ messages in thread
From: Yu Dai @ 2015-04-20 16:07 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx



On 04/18/2015 06:48 AM, Chris Wilson wrote:
> On Fri, Apr 17, 2015 at 02:21:13PM -0700, yu.dai@intel.com wrote:
> > diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> > index de8c074..8f13e80 100644
> > --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> > +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> > @@ -1993,7 +1993,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
> >  	INIT_LIST_HEAD(&ring->request_list);
> >  	INIT_LIST_HEAD(&ring->execlist_queue);
> >  	i915_gem_batch_pool_init(dev, &ring->batch_pool);
> > -	ringbuf->size = 32 * PAGE_SIZE;
> > +	ringbuf->size = 4 * PAGE_SIZE;
> >  	ringbuf->ring = ring;
> >  	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
>
> NAK.
>
First of all, GuC firmware reserves limited bits for ring buffer. 4 
pages is max for now. Second, considering the ring buffer is per-context 
now, there is no need to allocate 32 pages for it.

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

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

* Re: [PATCH v3 08/15] drm/i915: Functions to support command submission via GuC
  2015-04-20 16:07     ` Yu Dai
@ 2015-04-20 19:43       ` Chris Wilson
  2015-04-20 20:01         ` Yu Dai
  0 siblings, 1 reply; 37+ messages in thread
From: Chris Wilson @ 2015-04-20 19:43 UTC (permalink / raw)
  To: Yu Dai; +Cc: intel-gfx

On Mon, Apr 20, 2015 at 09:07:28AM -0700, Yu Dai wrote:
> 
> 
> On 04/18/2015 06:48 AM, Chris Wilson wrote:
> >On Fri, Apr 17, 2015 at 02:21:13PM -0700, yu.dai@intel.com wrote:
> >> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> >> index de8c074..8f13e80 100644
> >> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> >> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> >> @@ -1993,7 +1993,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
> >>  	INIT_LIST_HEAD(&ring->request_list);
> >>  	INIT_LIST_HEAD(&ring->execlist_queue);
> >>  	i915_gem_batch_pool_init(dev, &ring->batch_pool);
> >> -	ringbuf->size = 32 * PAGE_SIZE;
> >> +	ringbuf->size = 4 * PAGE_SIZE;
> >>  	ringbuf->ring = ring;
> >>  	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
> >
> >NAK.
> >
> First of all, GuC firmware reserves limited bits for ring buffer. 4
> pages is max for now. Second, considering the ring buffer is
> per-context now, there is no need to allocate 32 pages for it.

Please look at which function you are changing and explain how this is
not in the least broken.
-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] 37+ messages in thread

* Re: [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-04-20 16:02     ` Yu Dai
@ 2015-04-20 19:52       ` Chris Wilson
  2015-04-20 20:09         ` Yu Dai
  0 siblings, 1 reply; 37+ messages in thread
From: Chris Wilson @ 2015-04-20 19:52 UTC (permalink / raw)
  To: Yu Dai; +Cc: intel-gfx

On Mon, Apr 20, 2015 at 09:02:20AM -0700, Yu Dai wrote:
> 
> 
> On 04/18/2015 06:47 AM, Chris Wilson wrote:
> >On Fri, Apr 17, 2015 at 02:21:12PM -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.
> >
> >If the region is reserved, remove that region from the GGTT drm_mm range
> >manager. Then the restriction is applied to all objects and not in a
> >hodge-podge fashion like this.
> >
> I don't think I have clearly explained this. GTT range [0, WPOCM
> size] can't be used by GuC firmware, but still others can use it
> without any issue. PIN_OFFSET_BIAS is great for such use case.

You mean that the GuC redirects the [0, WOPCM] range to an internal set
of preallocated PTEs?
-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] 37+ messages in thread

* Re: [PATCH v3 08/15] drm/i915: Functions to support command submission via GuC
  2015-04-20 19:43       ` Chris Wilson
@ 2015-04-20 20:01         ` Yu Dai
  0 siblings, 0 replies; 37+ messages in thread
From: Yu Dai @ 2015-04-20 20:01 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx



On 04/20/2015 12:43 PM, Chris Wilson wrote:
> On Mon, Apr 20, 2015 at 09:07:28AM -0700, Yu Dai wrote:
> >
> >
> > On 04/18/2015 06:48 AM, Chris Wilson wrote:
> > >On Fri, Apr 17, 2015 at 02:21:13PM -0700, yu.dai@intel.com wrote:
> > >> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> > >> index de8c074..8f13e80 100644
> > >> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> > >> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> > >> @@ -1993,7 +1993,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
> > >>  	INIT_LIST_HEAD(&ring->request_list);
> > >>  	INIT_LIST_HEAD(&ring->execlist_queue);
> > >>  	i915_gem_batch_pool_init(dev, &ring->batch_pool);
> > >> -	ringbuf->size = 32 * PAGE_SIZE;
> > >> +	ringbuf->size = 4 * PAGE_SIZE;
> > >>  	ringbuf->ring = ring;
> > >>  	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
> > >
> > >NAK.
> > >
> > First of all, GuC firmware reserves limited bits for ring buffer. 4
> > pages is max for now. Second, considering the ring buffer is
> > per-context now, there is no need to allocate 32 pages for it.
>
> Please look at which function you are changing and explain how this is
> not in the least broken.
>
You are right, Chris. I should not touch this legacy ringbuf submission. 
Thanks for catch this.

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

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

* Re: [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-04-20 19:52       ` Chris Wilson
@ 2015-04-20 20:09         ` Yu Dai
  2015-04-20 20:33           ` Chris Wilson
  0 siblings, 1 reply; 37+ messages in thread
From: Yu Dai @ 2015-04-20 20:09 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx



On 04/20/2015 12:52 PM, Chris Wilson wrote:
> On Mon, Apr 20, 2015 at 09:02:20AM -0700, Yu Dai wrote:
> >
> >
> > On 04/18/2015 06:47 AM, Chris Wilson wrote:
> > >On Fri, Apr 17, 2015 at 02:21:12PM -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.
> > >
> > >If the region is reserved, remove that region from the GGTT drm_mm range
> > >manager. Then the restriction is applied to all objects and not in a
> > >hodge-podge fashion like this.
> > >
> > I don't think I have clearly explained this. GTT range [0, WPOCM
> > size] can't be used by GuC firmware, but still others can use it
> > without any issue. PIN_OFFSET_BIAS is great for such use case.
>
> You mean that the GuC redirects the [0, WOPCM] range to an internal set
> of preallocated PTEs?
>
There is no preallocated PTEs. But GuC treats address within that range 
as the Boot ROM or micro-kernel code / data that resides in its own 
SRAM. Only when it receives address above WPOCM, it will go through GGTT 
to access DRAM memory.

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

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

* Re: [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-04-20 20:09         ` Yu Dai
@ 2015-04-20 20:33           ` Chris Wilson
  2015-04-21 17:23             ` Dave Gordon
  0 siblings, 1 reply; 37+ messages in thread
From: Chris Wilson @ 2015-04-20 20:33 UTC (permalink / raw)
  To: Yu Dai; +Cc: intel-gfx

On Mon, Apr 20, 2015 at 01:09:18PM -0700, Yu Dai wrote:
> 
> 
> On 04/20/2015 12:52 PM, Chris Wilson wrote:
> >On Mon, Apr 20, 2015 at 09:02:20AM -0700, Yu Dai wrote:
> >>
> >>
> >> On 04/18/2015 06:47 AM, Chris Wilson wrote:
> >> >On Fri, Apr 17, 2015 at 02:21:12PM -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.
> >> >
> >> >If the region is reserved, remove that region from the GGTT drm_mm range
> >> >manager. Then the restriction is applied to all objects and not in a
> >> >hodge-podge fashion like this.
> >> >
> >> I don't think I have clearly explained this. GTT range [0, WPOCM
> >> size] can't be used by GuC firmware, but still others can use it
> >> without any issue. PIN_OFFSET_BIAS is great for such use case.
> >
> >You mean that the GuC redirects the [0, WOPCM] range to an internal set
> >of preallocated PTEs?
> >
> There is no preallocated PTEs. But GuC treats address within that
> range as the Boot ROM or micro-kernel code / data that resides in
> its own SRAM. Only when it receives address above WPOCM, it will go
> through GGTT to access DRAM memory.

Then I agree your original explanation was very confusing. :)

For the actual code, can you allocate from stolen memory rather than
system memory? Also the call to get_pages() is redundant, and by itself
misleading since the pages will only be valid whilst pinned which is
only done indirectly here.
-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] 37+ messages in thread

* Re: [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-04-20 20:33           ` Chris Wilson
@ 2015-04-21 17:23             ` Dave Gordon
  2015-04-21 20:41               ` Chris Wilson
  0 siblings, 1 reply; 37+ messages in thread
From: Dave Gordon @ 2015-04-21 17:23 UTC (permalink / raw)
  To: Chris Wilson, Yu Dai; +Cc: intel-gfx

On 20/04/15 21:33, Chris Wilson wrote:
> On Mon, Apr 20, 2015 at 01:09:18PM -0700, Yu Dai wrote:
>>
>> On 04/20/2015 12:52 PM, Chris Wilson wrote:
>>> On Mon, Apr 20, 2015 at 09:02:20AM -0700, Yu Dai wrote:
>>>>
>>>> On 04/18/2015 06:47 AM, Chris Wilson wrote:
>>>>> On Fri, Apr 17, 2015 at 02:21:12PM -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.
>>>>>
>>>>> If the region is reserved, remove that region from the GGTT drm_mm range
>>>>> manager. Then the restriction is applied to all objects and not in a
>>>>> hodge-podge fashion like this.
>>>>>
>>>> I don't think I have clearly explained this. GTT range [0, WPOCM
>>>> size] can't be used by GuC firmware, but still others can use it
>>>> without any issue. PIN_OFFSET_BIAS is great for such use case.
>>>
>>> You mean that the GuC redirects the [0, WOPCM] range to an internal set
>>> of preallocated PTEs?
>>>
>> There is no preallocated PTEs. But GuC treats address within that
>> range as the Boot ROM or micro-kernel code / data that resides in
>> its own SRAM. Only when it receives address above WPOCM, it will go
>> through GGTT to access DRAM memory.
> 
> Then I agree your original explanation was very confusing. :)
> 
> For the actual code, can you allocate from stolen memory rather than
> system memory? Also the call to get_pages() is redundant, and by itself
> misleading since the pages will only be valid whilst pinned which is
> only done indirectly here.
> -Chris

All objects to be shared between the CPU and the GuC must:
* be permanently resident in real memory, not paged out to shmfs
* be permanently mapped into the GGTT at addresses above WOPCM

Pinning the object into the GGTT will necessarily result in it
being kept resident in main memory (i915_gem_object_bind_to_vm()
calls _get_pages() and then _pin_pages()).

So we can just lose the _get_pages() call here.

We have three users of this function:
* the GuC context pool (one per system)
* the GuC log (one per system)
* GuC clients (currently two, maybe more eventually)

The CPU accesses the context pool only via SG copy operations
(BTW, there's a bug there, which I'll describe separately) so
it doesn't need to be directly addressable.

The GuC log is only accessed via debugfs, which uses kmap_atomic()
on each page in turn.

The client data is updated every time we pass work to the GuC;
at the moment this is also done with kmap_atomic(), but maybe
the mapping could be set up and left in place instead.

Do the different access patterns make any difference when we
choose what to (try to) allocate from stolen?

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

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

* Re: [PATCH v3 02/15] drm/i915: Add i915_gem_object_write() to i915_gem.c
  2015-04-17 21:21 ` [PATCH v3 02/15] drm/i915: Add i915_gem_object_write() to i915_gem.c yu.dai
@ 2015-04-21 18:41   ` Dave Gordon
  2015-04-21 18:46     ` Dave Gordon
  0 siblings, 1 reply; 37+ messages in thread
From: Dave Gordon @ 2015-04-21 18:41 UTC (permalink / raw)
  To: yu.dai, intel-gfx; +Cc: Michael H. Nguyen

On 17/04/15 22:21, yu.dai@intel.com wrote:
> 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 40ef672..6e8d106 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2645,6 +2645,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 f7b8766..44154fe 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -5260,3 +5260,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);

The second cast (size_t) is not required; better still, without
that cast the code fits on one line :)

> +	i915_gem_object_unpin_pages(obj);
> +
> +	if (WARN(bytes != size,
> +		 "Failed to upload all data (completed %zu bytes out of %zu total",

There's a mismatched parenthesis in the warning message above.
Also the line is just a bit too long, according to checkpatch :(
Perhaps just "Incomplete transfer, wrote %zu of %zu bytes" ?

The caller is going to issue a message too, if we ever reach
this case, so this code doesn't have to explain too much.

With these fixed,

Reviewed-by: Dave Gordon <david.s.gordon@intel.com>

> +		 bytes, size)) {
> +		i915_gem_object_put_pages(obj);
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> 

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

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

* Re: [PATCH v3 02/15] drm/i915: Add i915_gem_object_write() to i915_gem.c
  2015-04-21 18:41   ` Dave Gordon
@ 2015-04-21 18:46     ` Dave Gordon
  0 siblings, 0 replies; 37+ messages in thread
From: Dave Gordon @ 2015-04-21 18:46 UTC (permalink / raw)
  To: yu.dai, intel-gfx; +Cc: Michael H. Nguyen

On 21/04/15 19:41, Dave Gordon wrote:
> On 17/04/15 22:21, yu.dai@intel.com wrote:
>> 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 40ef672..6e8d106 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.h
>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> @@ -2645,6 +2645,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 f7b8766..44154fe 100644
>> --- a/drivers/gpu/drm/i915/i915_gem.c
>> +++ b/drivers/gpu/drm/i915/i915_gem.c
>> @@ -5260,3 +5260,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);
> 
> The second cast (size_t) is not required; better still, without
> that cast the code fits on one line :)
> 
>> +	i915_gem_object_unpin_pages(obj);
>> +
>> +	if (WARN(bytes != size,
>> +		 "Failed to upload all data (completed %zu bytes out of %zu total",
> 
> There's a mismatched parenthesis in the warning message above.
> Also the line is just a bit too long, according to checkpatch :(
> Perhaps just "Incomplete transfer, wrote %zu of %zu bytes" ?

Also a WARNing should have a trailing newline, so that would be
"Incomplete transfer, wrote %zu of %zu bytes\n" !

> The caller is going to issue a message too, if we ever reach
> this case, so this code doesn't have to explain too much.
> 
> With these fixed,
> 
> Reviewed-by: Dave Gordon <david.s.gordon@intel.com>
> 
>> +		 bytes, size)) {
>> +		i915_gem_object_put_pages(obj);
>> +		return -EIO;
>> +	}
>> +
>> +	return 0;
>> +}
>>
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx


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

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

* Re: [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-04-21 17:23             ` Dave Gordon
@ 2015-04-21 20:41               ` Chris Wilson
  0 siblings, 0 replies; 37+ messages in thread
From: Chris Wilson @ 2015-04-21 20:41 UTC (permalink / raw)
  To: Dave Gordon; +Cc: intel-gfx

On Tue, Apr 21, 2015 at 06:23:52PM +0100, Dave Gordon wrote:
> On 20/04/15 21:33, Chris Wilson wrote:
> > On Mon, Apr 20, 2015 at 01:09:18PM -0700, Yu Dai wrote:
> >>
> >> On 04/20/2015 12:52 PM, Chris Wilson wrote:
> >>> On Mon, Apr 20, 2015 at 09:02:20AM -0700, Yu Dai wrote:
> >>>>
> >>>> On 04/18/2015 06:47 AM, Chris Wilson wrote:
> >>>>> On Fri, Apr 17, 2015 at 02:21:12PM -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.
> >>>>>
> >>>>> If the region is reserved, remove that region from the GGTT drm_mm range
> >>>>> manager. Then the restriction is applied to all objects and not in a
> >>>>> hodge-podge fashion like this.
> >>>>>
> >>>> I don't think I have clearly explained this. GTT range [0, WPOCM
> >>>> size] can't be used by GuC firmware, but still others can use it
> >>>> without any issue. PIN_OFFSET_BIAS is great for such use case.
> >>>
> >>> You mean that the GuC redirects the [0, WOPCM] range to an internal set
> >>> of preallocated PTEs?
> >>>
> >> There is no preallocated PTEs. But GuC treats address within that
> >> range as the Boot ROM or micro-kernel code / data that resides in
> >> its own SRAM. Only when it receives address above WPOCM, it will go
> >> through GGTT to access DRAM memory.
> > 
> > Then I agree your original explanation was very confusing. :)
> > 
> > For the actual code, can you allocate from stolen memory rather than
> > system memory? Also the call to get_pages() is redundant, and by itself
> > misleading since the pages will only be valid whilst pinned which is
> > only done indirectly here.
> > -Chris
> 
> All objects to be shared between the CPU and the GuC must:
> * be permanently resident in real memory, not paged out to shmfs

Look at my suggested create_internal() as an alternative allocator then.

> * be permanently mapped into the GGTT at addresses above WOPCM
> 
> Pinning the object into the GGTT will necessarily result in it
> being kept resident in main memory (i915_gem_object_bind_to_vm()
> calls _get_pages() and then _pin_pages()).
> 
> So we can just lose the _get_pages() call here.
> 
> We have three users of this function:
> * the GuC context pool (one per system)
> * the GuC log (one per system)
> * GuC clients (currently two, maybe more eventually)
> 
> The CPU accesses the context pool only via SG copy operations
> (BTW, there's a bug there, which I'll describe separately) so
> it doesn't need to be directly addressable.
> 
> The GuC log is only accessed via debugfs, which uses kmap_atomic()
> on each page in turn.
> 
> The client data is updated every time we pass work to the GuC;
> at the moment this is also done with kmap_atomic(), but maybe
> the mapping could be set up and left in place instead.

Yes, please look over my suggested performance improvements to fix up
execlists submission. Keeping the kmap whilst the client is active is a
big one.
 
> Do the different access patterns make any difference when we
> choose what to (try to) allocate from stolen?

Yes. Because of a silly hw design we cannot have direct CPU access to
stolen memory. Also if the kernel only accesses through kmapping, then
can we pin the objects high in the GGTT above the aperture?
-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] 37+ messages in thread

* Re: [PATCH v3 06/15] drm/i915: Move execlists defines from .c to .h
  2015-04-17 21:21 ` [PATCH v3 06/15] drm/i915: Move execlists defines from .c to .h yu.dai
@ 2015-04-22 14:02   ` Dave Gordon
  0 siblings, 0 replies; 37+ messages in thread
From: Dave Gordon @ 2015-04-22 14:02 UTC (permalink / raw)
  To: yu.dai, intel-gfx; +Cc: Michael H. Nguyen

On 17/04/15 22:21, yu.dai@intel.com wrote:
> 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  | 77 ++++++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_lrc.c | 76 ---------------------------------------
>  2 files changed, 77 insertions(+), 76 deletions(-)

This one's just a trivial reshuffle, so nothing can possibly go worng
here :)

Reviewed-by: Dave Gordon <david.s.gordon@intel.com>

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

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

* Re: [PATCH v3 05/15] drm/i915: Defer default hardware context initialisation until first open
  2015-04-17 21:21 ` [PATCH v3 05/15] drm/i915: Defer default hardware context initialisation until first open yu.dai
@ 2015-04-23 12:25   ` Dave Gordon
  0 siblings, 0 replies; 37+ messages in thread
From: Dave Gordon @ 2015-04-23 12:25 UTC (permalink / raw)
  To: yu.dai, intel-gfx

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

On 17/04/15 22:21, 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.
> 
> 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 | 25 +++++++++++++++++++++--
>  5 files changed, 63 insertions(+), 9 deletions(-)

Hi Alex,

the code is fine :) but I'd rather that this functionality went in ahead
of the GuC loader - it's actually a useful generic standalone that could
provide recovery from other early initialisation issues, even before we
consider GuC submission (there's a reason that EIO was already
considered nonfatal during startup).

The other reason I don't like this being added after the GuC loader is
because it changes the interface to intel_guc_load_ucode() which was
only just added in the patch before. If we swap the order then the
interface is defined the same way from day one, and no-one need consider
the half-baked state inbetween.

So I suggest this patch should be moved to the beginning of the series
(or even submitted independently), and include only the change to
i915_drv.h, the second block of changes to i915_gem.c, and all the
changes to i915_gem_context.c EXCEPT the three lines around the call to
intel_guc_load_ucode() [see attachment for clarification and a new
commit message].

Then the other changes -- which are all GuC-specific --  can be added
back in the *later* patch that adds the GuC loader.

> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 235fc08..d128ac4 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1760,6 +1760,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 44154fe..b7bd288 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -4888,8 +4888,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 */
> +

Don't include these five lines in this patch

>  	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 e4c57a3..3795df2 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -447,23 +447,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);

Don't include these four either
> +
> +	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)

Then fold everything else into the patch(es) that create intel_guc.h and
intel_guc_loader.c ...

I think that will provide a simpler and more logical split between
generic and GuC-specific code :)

.Dave.

[-- Attachment #2: 0001-drm-i915-Defer-default-hardware-context-initialisati.patch --]
[-- Type: text/x-patch, Size: 3588 bytes --]

>From 160d40ab80d982aff479e3524a0442bb92f78b3d Mon Sep 17 00:00:00 2001
From: Dave Gordon <david.s.gordon@intel.com>
Date: Fri, 17 Apr 2015 22:21:10 +0100
Subject: [PATCH 01/15] drm/i915: Defer default hardware context
 initialisation until first open

To fully initialise the default contexts in i915_gem_context_enable(),
we have to execute batchbuffer commands on the GPU engines. But that
might not succeed during early initialisation, so we already treat a
return of EIO as nonfatal in gem_init_hw(), allowing the driver to load
despite not (yet) being able to submit batch commands.

This commit adds a flag to record whether the default contexts have
successfully been initialised; if they haven't, then we retry the
call to i915_gem_context_enable() when the device is first opened,
which should be late enough for all required resources to have become
available and any setup helper code to have run.

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         |    4 +++-
 drivers/gpu/drm/i915/i915_gem_context.c |   31 ++++++++++++++++++++++++++-----
 3 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 79da7f3..0e88ef2 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1751,6 +1751,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 89d9ebe..1fef0bb 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4889,7 +4889,9 @@ i915_gem_init_hw(struct drm_device *dev)
 	}
 
 	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 e4c57a3..92baba0 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -447,23 +447,44 @@ 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;
+
+	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)
-- 
1.7.9.5


[-- Attachment #3: 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 related	[flat|nested] 37+ messages in thread

* Re: [PATCH v3 03/15] drm/i915: Unified firmware loading mechanism
  2015-04-17 21:21 ` [PATCH v3 03/15] drm/i915: Unified firmware loading mechanism yu.dai
@ 2015-04-23 17:12   ` Dave Gordon
  0 siblings, 0 replies; 37+ messages in thread
From: Dave Gordon @ 2015-04-23 17:12 UTC (permalink / raw)
  To: yu.dai, intel-gfx

On 17/04/15 22:21, yu.dai@intel.com wrote:
> 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 | 244 +++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_uc_loader.h |  78 +++++++++++
>  3 files changed, 325 insertions(+)
>  create mode 100644 drivers/gpu/drm/i915/intel_uc_loader.c
>  create mode 100644 drivers/gpu/drm/i915/intel_uc_loader.h

In general, yes; but I noticed that the firmware image blob isn't
released in the 'success' path, which means we're keeping both the raw
image and the GEM copy around forever. It would be better to release the
raw image and only keep the GEM object (which is swappable).

Unfortunately, that wouldn't work with the current version of the GuC
loader because of the way it needs the data reorganised for DMA, and
therefore accesses the blob on each reload :(

So I think the way to go here is to upgrade the uc_fw_check() callback
to allow it to override the way the data is saved, if the default (GEM
object is just a copy of the firmware image) doesn't match the specific
uC requirements.

The GuC callback can then shuffle the data during this one-off copy, and
the subsequent DMA transfer will be much more straightforward.

I'll post a new suggestion for this file soon, probably tomorrow ...

.Dave.

> diff --git a/drivers/gpu/drm/i915/intel_uc_loader.c b/drivers/gpu/drm/i915/intel_uc_loader.c

> +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;
> +	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;
> +	}
> +
> +	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;

We ought to be able to release_firmware() here.

> +	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;
> +	uc_fw->uc_fw_blob = NULL;
> +	release_firmware(fw);		/* OK even if fw is NULL */
> +}

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

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

* Re: [PATCH v3 04/15] drm/i915: GuC firmware loader
  2015-04-17 21:21 ` [PATCH v3 04/15] drm/i915: GuC firmware loader yu.dai
@ 2015-04-23 17:48   ` Dave Gordon
  2015-04-28 15:12     ` Dave Gordon
  0 siblings, 1 reply; 37+ messages in thread
From: Dave Gordon @ 2015-04-23 17:48 UTC (permalink / raw)
  To: yu.dai, intel-gfx

On 17/04/15 22:21, yu.dai@intel.com wrote:
> 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         |   7 +
>  drivers/gpu/drm/i915/i915_gem_stolen.c  |  10 +
>  drivers/gpu/drm/i915/i915_reg.h         |   4 +-
>  drivers/gpu/drm/i915/intel_guc.h        | 103 ++++++++++
>  drivers/gpu/drm/i915/intel_guc_loader.c | 348 ++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_uc_loader.c  |   3 +
>  drivers/gpu/drm/i915/intel_uc_loader.h  |   4 +
>  9 files changed, 486 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/intel_guc.h
>  create mode 100644 drivers/gpu/drm/i915/intel_guc_loader.c

Hi Alex,

some comments interspersed below ...

> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index e44116f..5d50b5b 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);
> @@ -861,6 +862,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);

Can we put this any earlier? We might as well get the async fetch
started as early as possible ...

> +
>  	ret = i915_gem_gtt_init(dev);
>  	if (ret)
>  		goto out_regs;
> @@ -1108,6 +1113,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_context_fini(dev);
>  	mutex_unlock(&dev->struct_mutex);
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 6e8d106..235fc08 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:
>   */
> @@ -1581,6 +1582,8 @@ struct drm_i915_private {
>  
>  	struct intel_gmbus gmbus[GMBUS_NUM_PINS];
>  
> +	struct intel_guc guc;
> +
>  	/** gmbus_mutex protects against concurrent usage of the single hw gmbus
>  	 * controller on different i2c buses. */
>  	struct mutex gmbus_mutex;
> @@ -2430,6 +2433,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))
> +#define HAS_GUC_SCHED(dev)	(IS_GEN9(dev))
> +
>  #define INTEL_PCH_DEVICE_ID_MASK		0xff00
>  #define INTEL_PCH_IBX_DEVICE_ID_TYPE		0x3b00
>  #define INTEL_PCH_CPT_DEVICE_ID_TYPE		0x1c00
> @@ -3008,6 +3014,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);

See below ...

>  
>  /* 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 348ed5a..fbf7667 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);
> +	}
> +}

I don't understand why this function has been added to this file;
it doesn't appear to relate to anything else here, nor does anything
else in this file relate to the GuC.

If it went into i915_dma.c instead, it could be static.

> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h

> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h

> 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..a999044
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c

[snip]

> +/* Transfers the firmware image to RAM for execution by the microcontroller.
> +
> + * GuC Firmware layout:
> + * +-------------------------------+  ----
> + * |          CSS header           |  128B
> + * +-------------------------------+  ----
> + * |         RSA signature         |  256B
> + * +-------------------------------+  ----
> + * |         RSA public Key        |  256B
> + * +-------------------------------+  ----
> + * |       Public key modulus      |    4B
> + * +-------------------------------+  ----
> + * |             uCode             |
> + * +-------------------------------+  ----
> + *
> + * 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.
> + *
> + * Be note that GuC need the CSS header plus uKernel code to be copied as one
> + * chunk of data. RSA sig data is loaded via MMIO.
> + */
> +static int ucode_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;
> +	unsigned long offset;
> +	struct sg_table *sg = fw_obj->pages;
> +	u32 status, ucode_size, *blob;
> +	int i, ret = 0;
> +
> +	/* Copy RSA signature from the fw image to HW for verification */
> +	blob = (uint32_t *)(dev_priv->guc.guc_fw.uc_fw_blob->data
> +			+ UOS_RSA_SIG_OFFSET);
> +	for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(uint32_t); i++)
> +		I915_WRITE(UOS_RSA_SCRATCH_0 + i * sizeof(uint32_t), blob[i]);
> +
> +	/* Re-arrange data per GuC request (CSS header + uCode) */
> +
> +	/* Copy CSS header  */
> +	blob = (uint32_t *)(dev_priv->guc.guc_fw.uc_fw_blob->data
> +			+ UOS_CSS_HEADER_OFFSET);
> +	sg_copy_from_buffer(sg->sgl, sg->nents, blob, UOS_CSS_HEADER_SIZE);
> +
> +	/* Copy ucode */
> +	blob = (uint32_t *)(dev_priv->guc.guc_fw.uc_fw_blob->data
> +			+ UOS_UCODE_OFFSET);
> +	ucode_size = guc_fw->uc_fw_size - UOS_UCODE_OFFSET;
> +	sg_pcopy_from_buffer(sg->sgl, sg->nents, blob,
> +			ucode_size, UOS_CSS_HEADER_SIZE);

I hadn't realised before that the GuC didn't accept the data in the same
format as it comes from the firmware image. And that this code therefore
copies the data from the blob to the GEM object each time the GuC is
reloaded :(

I intended that the raw firmware image should be released once the data
had been copied, so as mentioned in my last email, I think we should
rework the generic firmware loader to let the uC-specific part save the
data in its own preferred format, if that isn't just a copy of the blob.

[snip]

> diff --git a/drivers/gpu/drm/i915/intel_uc_loader.c b/drivers/gpu/drm/i915/intel_uc_loader.c
> index bc499f4..65031ff 100644
> --- a/drivers/gpu/drm/i915/intel_uc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_uc_loader.c
> @@ -77,6 +77,9 @@ static void uc_fw_finish(struct drm_device *dev, struct intel_uc_fw *uc_fw)
>  		uc_fw->uc_fw_blob = fw;
>  	}
>  
> +	if (uc_fw->uc_fw_check && !uc_fw->uc_fw_check(uc_fw))
> +		goto fail;
> +

I'll fold this into the base version of the generic code.

> diff --git a/drivers/gpu/drm/i915/intel_uc_loader.h b/drivers/gpu/drm/i915/intel_uc_loader.h
> index 0994f98..4ed6e94 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);
>  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);

This last function doesn't exist (and isn't needed).

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

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

* Re: [PATCH v3 04/15] drm/i915: GuC firmware loader
  2015-04-23 17:48   ` Dave Gordon
@ 2015-04-28 15:12     ` Dave Gordon
  2015-04-28 15:18       ` Yu Dai
  0 siblings, 1 reply; 37+ messages in thread
From: Dave Gordon @ 2015-04-28 15:12 UTC (permalink / raw)
  To: yu.dai, intel-gfx

On 23/04/15 18:48, Dave Gordon wrote:
> On 17/04/15 22:21, yu.dai@intel.com wrote:
>> 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         |   7 +
>>  drivers/gpu/drm/i915/i915_gem_stolen.c  |  10 +
>>  drivers/gpu/drm/i915/i915_reg.h         |   4 +-
>>  drivers/gpu/drm/i915/intel_guc.h        | 103 ++++++++++
>>  drivers/gpu/drm/i915/intel_guc_loader.c | 348 ++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/i915/intel_uc_loader.c  |   3 +
>>  drivers/gpu/drm/i915/intel_uc_loader.h  |   4 +
>>  9 files changed, 486 insertions(+), 2 deletions(-)
>>  create mode 100644 drivers/gpu/drm/i915/intel_guc.h
>>  create mode 100644 drivers/gpu/drm/i915/intel_guc_loader.c
> 
> Hi Alex,
> 
> some comments interspersed below ...
>
>> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
>> index e44116f..5d50b5b 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);
>> @@ -861,6 +862,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);
> 
> Can we put this any earlier? We might as well get the async fetch
> started as early as possible ...

Also, does intel_wopcm_init() meed to be called only once, during driver
load? Or should it be called after a reset as well? Maybe it should be
called from intel_guc_load_ucode() ? In which case it could live in one
of the GuC-specific files and be static :)

Possibly it belongs near the gem-guc-object allocator, since the setting
of this register and the selection of GuC-accessible offsets within the
GTT are related ...

.Dave.

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

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

* Re: [PATCH v3 04/15] drm/i915: GuC firmware loader
  2015-04-28 15:12     ` Dave Gordon
@ 2015-04-28 15:18       ` Yu Dai
  0 siblings, 0 replies; 37+ messages in thread
From: Yu Dai @ 2015-04-28 15:18 UTC (permalink / raw)
  To: Dave Gordon, intel-gfx



On 04/28/2015 08:12 AM, Dave Gordon wrote:
> On 23/04/15 18:48, Dave Gordon wrote:
> > On 17/04/15 22:21, yu.dai@intel.com wrote:
> >> 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         |   7 +
> >>  drivers/gpu/drm/i915/i915_gem_stolen.c  |  10 +
> >>  drivers/gpu/drm/i915/i915_reg.h         |   4 +-
> >>  drivers/gpu/drm/i915/intel_guc.h        | 103 ++++++++++
> >>  drivers/gpu/drm/i915/intel_guc_loader.c | 348 ++++++++++++++++++++++++++++++++
> >>  drivers/gpu/drm/i915/intel_uc_loader.c  |   3 +
> >>  drivers/gpu/drm/i915/intel_uc_loader.h  |   4 +
> >>  9 files changed, 486 insertions(+), 2 deletions(-)
> >>  create mode 100644 drivers/gpu/drm/i915/intel_guc.h
> >>  create mode 100644 drivers/gpu/drm/i915/intel_guc_loader.c
> >
> > Hi Alex,
> >
> > some comments interspersed below ...
> >
> >> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> >> index e44116f..5d50b5b 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);
> >> @@ -861,6 +862,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);
> >
> > Can we put this any earlier? We might as well get the async fetch
> > started as early as possible ...
>
> Also, does intel_wopcm_init() meed to be called only once, during driver
> load? Or should it be called after a reset as well? Maybe it should be
> called from intel_guc_load_ucode() ? In which case it could live in one
> of the GuC-specific files and be static :)
>
> Possibly it belongs near the gem-guc-object allocator, since the setting
> of this register and the selection of GuC-accessible offsets within the
> GTT are related ...
>
>
In my local tree, this has been moved to right before load firmware. 
This wopcm_init() was introduced for huc firmware loading. We must load 
huc before guc. Since we don't have plan to upsteam huc frimware yet, as 
you suggested, we can move this wopcm_init() to guc_load_ucode() make 
code clean. In case we upstream huc firmware in future, we can put it 
before huc loading.

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

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

* Re: [PATCH v3 14/15] drm/i915: Taking forcewake during GuC load.
  2015-04-17 21:21 ` [PATCH v3 14/15] drm/i915: Taking forcewake during GuC load yu.dai
@ 2015-04-28 15:22   ` Dave Gordon
  0 siblings, 0 replies; 37+ messages in thread
From: Dave Gordon @ 2015-04-28 15:22 UTC (permalink / raw)
  To: yu.dai, intel-gfx

On 17/04/15 22:21, yu.dai@intel.com wrote:
> From: Sagar Kamble <sagar.a.kamble@intel.com>
> 
> The firmware loader will use GuC DMA engine to move data from
> ggtt to WOPCM. 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 d1fd11e..f19eb90 100644
> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> @@ -340,6 +340,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)
> @@ -388,6 +389,8 @@ out:
>  	if (pinned)
>  		i915_gem_object_ggtt_unpin(guc_fw->uc_fw_obj);
>  
> +	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
> +
>  	return ret;
>  }

This doesn't need to be a separate patch; it can be squashed into the
initial creation of the GuC loader, so we don't (even temporarily)  have
a broken version in the codebase.

We keep the authorship, of course :) And maybe turn the commit message
into a code comment in the affected function?

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

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

end of thread, other threads:[~2015-04-28 15:22 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-17 21:21 [PATCH v3 00/15] *** Command submission via GuC for SKL *** yu.dai
2015-04-17 21:21 ` [PATCH v3 01/15] drm/i915: Add guc firmware interface headers yu.dai
2015-04-17 21:21 ` [PATCH v3 02/15] drm/i915: Add i915_gem_object_write() to i915_gem.c yu.dai
2015-04-21 18:41   ` Dave Gordon
2015-04-21 18:46     ` Dave Gordon
2015-04-17 21:21 ` [PATCH v3 03/15] drm/i915: Unified firmware loading mechanism yu.dai
2015-04-23 17:12   ` Dave Gordon
2015-04-17 21:21 ` [PATCH v3 04/15] drm/i915: GuC firmware loader yu.dai
2015-04-23 17:48   ` Dave Gordon
2015-04-28 15:12     ` Dave Gordon
2015-04-28 15:18       ` Yu Dai
2015-04-17 21:21 ` [PATCH v3 05/15] drm/i915: Defer default hardware context initialisation until first open yu.dai
2015-04-23 12:25   ` Dave Gordon
2015-04-17 21:21 ` [PATCH v3 06/15] drm/i915: Move execlists defines from .c to .h yu.dai
2015-04-22 14:02   ` Dave Gordon
2015-04-17 21:21 ` [PATCH v3 07/15] drm/i915: Add functions to allocate / release gem obj for GuC yu.dai
2015-04-18 13:47   ` Chris Wilson
2015-04-20 16:02     ` Yu Dai
2015-04-20 19:52       ` Chris Wilson
2015-04-20 20:09         ` Yu Dai
2015-04-20 20:33           ` Chris Wilson
2015-04-21 17:23             ` Dave Gordon
2015-04-21 20:41               ` Chris Wilson
2015-04-17 21:21 ` [PATCH v3 08/15] drm/i915: Functions to support command submission via GuC yu.dai
2015-04-18 13:48   ` Chris Wilson
2015-04-20 16:07     ` Yu Dai
2015-04-20 19:43       ` Chris Wilson
2015-04-20 20:01         ` Yu Dai
2015-04-17 21:21 ` [PATCH v3 09/15] drm/i915: Integration of GuC client yu.dai
2015-04-17 21:21 ` [PATCH v3 10/15] drm/i915: Interrupt routing for GuC scheduler yu.dai
2015-04-17 21:21 ` [PATCH v3 11/15] drm/i915: Enable commands submission via GuC yu.dai
2015-04-17 21:21 ` [PATCH v3 12/15] drm/i915: debugfs of GuC status yu.dai
2015-04-17 21:21 ` [PATCH v3 13/15] drm/i915: Enable GuC firmware log yu.dai
2015-04-17 21:21 ` [PATCH v3 14/15] drm/i915: Taking forcewake during GuC load yu.dai
2015-04-28 15:22   ` Dave Gordon
2015-04-17 21:21 ` [PATCH v3 15/15] Documentation/drm: kerneldoc for GuC yu.dai
2015-04-18  1:13   ` shuang.he

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.