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

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

v2:
1. Add kernel-doc patch. All comments here have been moved into source code.
2. Change the way to load fw because a signed firmware has different layout.
3. 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 (13):
  drm/i915: Add guc firmware interface headers
  drm/i915: GuC firmware loader
  drm/i915: Add firmware version check
  drm/i915: Make several execlist helper functions external
  drm/i915: Add functions to allocate / release gem obj for GuC
  drm/i915: Functions to support command submission via GuC
  drm/i915: Integration of GuC client
  drm/i915: Interrupt routing for GuC scheduler
  drm/i915: Enable commands submission via GuC
  drm/i915: debugfs of GuC status
  drm/i915: Enable GuC firmware log
  drm/i915: Ring Context allocating for GuC
  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        | 102 +++++
 drivers/gpu/drm/i915/i915_dma.c            |   6 +
 drivers/gpu/drm/i915/i915_drv.h            |  17 +
 drivers/gpu/drm/i915/i915_gem.c            |  39 +-
 drivers/gpu/drm/i915/i915_gem_context.c    |  35 +-
 drivers/gpu/drm/i915/i915_gem_stolen.c     |  10 +
 drivers/gpu/drm/i915/i915_params.c         |   9 +
 drivers/gpu/drm/i915/i915_reg.h            |  83 +++-
 drivers/gpu/drm/i915/intel_guc.h           | 192 +++++++++
 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    | 537 ++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_scheduler.c | 164 ++++++++
 drivers/gpu/drm/i915/intel_lrc.c           | 112 ++---
 drivers/gpu/drm/i915/intel_lrc.h           |   3 +
 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, 2432 insertions(+), 97 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/intel_guc.h
 create mode 100644 drivers/gpu/drm/i915/intel_guc_api.h
 create mode 100644 drivers/gpu/drm/i915/intel_guc_client.c
 create mode 100644 drivers/gpu/drm/i915/intel_guc_loader.c
 create mode 100644 drivers/gpu/drm/i915/intel_guc_scheduler.c
 create mode 100644 drivers/gpu/drm/i915/intel_uc_loader.c
 create mode 100644 drivers/gpu/drm/i915/intel_uc_loader.h

-- 
1.9.1

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

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

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

* [PATCH v2 02/18] drm/i915: Add i915_gem_object_write() to i915_gem.c
  2015-04-03 18:08 [PATCH v2 00/18] *** Command submission via GuC for SKL *** yu.dai
  2015-04-03 18:08 ` [PATCH v2 01/18] drm/i915: Add guc firmware interface headers yu.dai
@ 2015-04-03 18:08 ` yu.dai
  2015-04-03 18:08 ` [PATCH v2 03/18] drm/i915: Unified firmware loading mechanism yu.dai
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: yu.dai @ 2015-04-03 18:08 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 b13c552..f3b3788 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2632,6 +2632,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 267fdf0..446e958 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -5234,3 +5234,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] 21+ messages in thread

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

* [PATCH v2 04/18] drm/i915: GuC firmware loader
  2015-04-03 18:08 [PATCH v2 00/18] *** Command submission via GuC for SKL *** yu.dai
                   ` (2 preceding siblings ...)
  2015-04-03 18:08 ` [PATCH v2 03/18] drm/i915: Unified firmware loading mechanism yu.dai
@ 2015-04-03 18:08 ` yu.dai
  2015-04-03 18:08 ` [PATCH v2 05/18] drm/i915: Add firmware version check yu.dai
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: yu.dai @ 2015-04-03 18:08 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        | 101 +++++++++++
 drivers/gpu/drm/i915/intel_guc_loader.c | 301 ++++++++++++++++++++++++++++++++
 7 files changed, 430 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 ec661fe..44ca6c1 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);
@@ -832,6 +833,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;
@@ -1075,6 +1080,7 @@ int i915_driver_unload(struct drm_device *dev)
 	flush_workqueue(dev_priv->wq);
 
 	mutex_lock(&dev->struct_mutex);
+	intel_guc_ucode_fini(dev);
 	i915_gem_cleanup_ringbuffer(dev);
 	i915_gem_batch_pool_fini(&dev_priv->mm.batch_pool);
 	i915_gem_context_fini(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f3b3788..694e736 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -50,6 +50,7 @@
 #include <linux/intel-iommu.h>
 #include <linux/kref.h>
 #include <linux/pm_qos.h>
+#include "intel_guc.h"
 
 /* General customization:
  */
@@ -1576,6 +1577,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;
@@ -2424,6 +2427,9 @@ struct drm_i915_cmd_table {
 #define HAS_RC6(dev)		(INTEL_INFO(dev)->gen >= 6)
 #define HAS_RC6p(dev)		(INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev))
 
+#define HAS_GUC_UCODE(dev)	(IS_GEN9(dev) || IS_GEN8(dev))
+#define HAS_GUC_SCHED(dev)	(IS_GEN9(dev) || IS_BROADWELL(dev))
+
 #define INTEL_PCH_DEVICE_ID_MASK		0xff00
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE		0x3b00
 #define INTEL_PCH_CPT_DEVICE_ID_TYPE		0x1c00
@@ -2978,6 +2984,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 b134fa3..f3c1919 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -6292,7 +6292,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..64cfc20
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -0,0 +1,101 @@
+/*
+ * 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_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..950170c
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -0,0 +1,301 @@
+/*
+ * 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.
+ *
+ */
+
+#define I915_GUC_UCODE_GEN8 "i915/guc_gen8.bin"
+#define I915_GUC_UCODE_GEN9 "i915/guc_gen9.bin"
+MODULE_FIRMWARE(I915_GUC_UCODE_GEN8);
+MODULE_FIRMWARE(I915_GUC_UCODE_GEN9);
+
+/* 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;
+}
+
+/**
+ * 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))
+		return;
+
+	if (IS_GEN8(dev))
+		path = I915_GUC_UCODE_GEN8;
+	else if (IS_GEN9(dev))
+		path = I915_GUC_UCODE_GEN9;
+
+	intel_uc_fw_init(dev, guc_fw, "GuC", path);
+}
+
+/**
+ * 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);
+}
-- 
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] 21+ messages in thread

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

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

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

Currently the GuC fw version is 1.0.

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

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 64cfc20..4fafcec 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -50,6 +50,8 @@ struct intel_guc {
 
 #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
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 950170c..8d141ba 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -33,6 +33,13 @@
  * 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_GUC_UCODE_GEN8 "i915/guc_gen8.bin"
@@ -269,6 +276,35 @@ 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
  */
@@ -281,10 +317,17 @@ void intel_guc_ucode_init(struct drm_device *dev)
 	if (!HAS_GUC_UCODE(dev))
 		return;
 
-	if (IS_GEN8(dev))
+	if (IS_GEN8(dev)) {
 		path = I915_GUC_UCODE_GEN8;
-	else if (IS_GEN9(dev))
+		guc_fw->uc_fw_ver_major = 1;
+		guc_fw->uc_fw_ver_minor = 0;
+		guc_fw->uc_fw_check = intel_guc_ucode_check;
+	} else if (IS_GEN9(dev)) {
 		path = I915_GUC_UCODE_GEN9;
+		guc_fw->uc_fw_ver_major = 1;
+		guc_fw->uc_fw_ver_minor = 0;
+		guc_fw->uc_fw_check = intel_guc_ucode_check;
+	}
 
 	intel_uc_fw_init(dev, guc_fw, "GuC", path);
 }
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] 21+ messages in thread

* [PATCH v2 06/18] drm/i915: Defer default hardware context initialisation until first open
  2015-04-03 18:08 [PATCH v2 00/18] *** Command submission via GuC for SKL *** yu.dai
                   ` (4 preceding siblings ...)
  2015-04-03 18:08 ` [PATCH v2 05/18] drm/i915: Add firmware version check yu.dai
@ 2015-04-03 18:08 ` yu.dai
  2015-04-03 18:08 ` [PATCH v2 07/18] drm/i915: Move execlists defines from .c to .h yu.dai
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: yu.dai @ 2015-04-03 18:08 UTC (permalink / raw)
  To: intel-gfx

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

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

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

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

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 694e736..a31a5f9 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1755,6 +1755,7 @@ struct drm_i915_private {
 	/* hda/i915 audio component */
 	bool audio_component_registered;
 
+	bool contexts_ready;
 	uint32_t hw_context_size;
 	struct list_head context_list;
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 446e958..d504f21 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4864,8 +4864,15 @@ i915_gem_init_hw(struct drm_device *dev)
 		i915_gem_cleanup_ringbuffer(dev);
 	}
 
+	/* We can't enable contexts until all firmware is loaded */
+	ret = intel_guc_load_ucode(dev, false);
+	if (ret == -EAGAIN)
+		return 0;		/* too early */
+
 	ret = i915_gem_context_enable(dev_priv);
-	if (ret && ret != -EIO) {
+	if (ret == 0) {
+		dev_priv->contexts_ready = true;
+	} else if (ret && ret != -EIO) {
 		DRM_ERROR("Context enable failed %d\n", ret);
 		i915_gem_cleanup_ringbuffer(dev);
 
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index f3e84c4..2353d8f 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -445,23 +445,48 @@ static int context_idr_cleanup(int id, void *p, void *data)
 	return 0;
 }
 
+/* Complete any late initialisation here */
+static int i915_gem_context_first_open(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	/* We can't enable contexts until all firmware is loaded */
+	ret = intel_guc_load_ucode(dev, true);
+	WARN_ON(ret == -EAGAIN);
+
+	ret = i915_gem_context_enable(dev_priv);
+	if (ret == 0)
+		dev_priv->contexts_ready = true;
+	return ret;
+}
+
 int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_file_private *file_priv = file->driver_priv;
 	struct intel_context *ctx;
+	int ret = 0;
 
 	idr_init(&file_priv->context_idr);
 
 	mutex_lock(&dev->struct_mutex);
-	ctx = i915_gem_create_context(dev, file_priv);
+
+	if (!dev_priv->contexts_ready)
+		ret = i915_gem_context_first_open(dev);
+
+	if (ret == 0) {
+		ctx = i915_gem_create_context(dev, file_priv);
+		if (IS_ERR(ctx))
+			ret = PTR_ERR(ctx);
+	}
+
 	mutex_unlock(&dev->struct_mutex);
 
-	if (IS_ERR(ctx)) {
+	if (ret)
 		idr_destroy(&file_priv->context_idr);
-		return PTR_ERR(ctx);
-	}
 
-	return 0;
+	return ret;
 }
 
 void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 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 8d141ba..45d099f 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -246,24 +246,42 @@ 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;
 
+	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] 21+ messages in thread

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

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

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

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

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

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

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

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

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

These functions will be used by GuC scheduler.

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

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 0797d26..d4011b4 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;
@@ -1740,7 +1740,7 @@ void intel_lr_context_free(struct intel_context *ctx)
 	}
 }
 
-static uint32_t get_lr_context_size(struct intel_engine_cs *ring)
+uint32_t get_lr_context_size(struct intel_engine_cs *ring)
 {
 	int ret = 0;
 
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 04d3a6d..6b19409 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -67,6 +67,7 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf,
 }
 
 /* Logical Ring Contexts */
+uint32_t get_lr_context_size(struct intel_engine_cs *ring);
 void intel_lr_context_free(struct intel_context *ctx);
 int intel_lr_context_deferred_create(struct intel_context *ctx,
 				     struct intel_engine_cs *ring);
@@ -85,6 +86,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] 21+ messages in thread

* [PATCH v2 09/18] drm/i915: Add functions to allocate / release gem obj for GuC
  2015-04-03 18:08 [PATCH v2 00/18] *** Command submission via GuC for SKL *** yu.dai
                   ` (7 preceding siblings ...)
  2015-04-03 18:08 ` [PATCH v2 08/18] drm/i915: Make several execlist helper functions external yu.dai
@ 2015-04-03 18:08 ` yu.dai
  2015-04-03 18:08 ` [PATCH v2 10/18] drm/i915: Functions to support command submission via GuC yu.dai
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: yu.dai @ 2015-04-03 18:08 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 45d099f..d37fa42 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_GUC_UCODE_GEN8 "i915/guc_gen8.bin"
@@ -47,6 +53,55 @@
 MODULE_FIRMWARE(I915_GUC_UCODE_GEN8);
 MODULE_FIRMWARE(I915_GUC_UCODE_GEN9);
 
+/**
+ * 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] 21+ messages in thread

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

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

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

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

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 6188302..50b2057 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -37,7 +37,8 @@ i915-y += i915_cmd_parser.o \
 	  i915_trace_points.o \
 	  intel_lrc.o \
 	  intel_ringbuffer.o \
-	  intel_uncore.o
+	  intel_uncore.o \
+	  intel_guc_scheduler.o
 
 # ancilliary microcontroller support
 i915-y += intel_uc_loader.o \
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a31a5f9..48f56d9 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2492,6 +2492,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..c7f3ed6 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,11 @@ struct drm_i915_gem_object *
 intel_guc_allocate_gem_obj(struct drm_device *dev, u32 size);
 void intel_guc_release_gem_obj(struct drm_i915_gem_object *obj);
 
+/* intel_guc_scheduler.c */
+int guc_scheduler_init(struct drm_device *dev);
+void guc_scheduler_fini(struct drm_device *dev);
+int guc_scheduler_enable(struct drm_device *dev);
+void guc_scheduler_disable(struct drm_device *dev);
+bool sanitize_enable_guc_scheduling(struct drm_device *dev);
+
 #endif
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index d37fa42..44dc0b3 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -236,6 +236,34 @@ static void set_guc_init_params(struct drm_i915_private *dev_priv)
 
 	/* XXX: Set up log buffer */
 
+	/* If GuC scheduling is enabled, setup params here. */
+	if (i915.enable_guc_scheduling) {
+		u32 pgs = i915_gem_obj_ggtt_offset(dev_priv->guc.ctx_pool_obj);
+		u32 ctx_in_16 = MAX_GUC_GPU_CONTEXTS / 16;
+
+		pgs >>= PAGE_SHIFT;
+		params[GUC_CTL_CTXINFO] = (pgs << GUC_CTL_BASE_ADDR_SHIFT) |
+			(ctx_in_16 << GUC_CTL_CTXNUM_IN16_SHIFT);
+
+		/* The shared data is one page following the Ring Context.
+		 * So the offset is the page number of LRC */
+		pgs = get_lr_context_size(&dev_priv->ring[RCS]) >> PAGE_SHIFT;
+		params[GUC_CTL_OFFSET] |= pgs << GUC_CTL_SHARED_DATA_SHIFT;
+
+		/* This must be non-zero for scheduler to initialize even the
+		 * firmware doesn't use it. Be note that we use separated obj
+		 * for actual ring buffer, while firmware may treat this as an
+		 * offset from Ring Context base. We must take care of this if
+		 * firmware starts using this field.
+		 */
+		params[GUC_CTL_OFFSET] |= 1 << GUC_CTL_RING_BUFFER_SHIFT;
+
+		params[GUC_CTL_FEATURE] |= GUC_CTL_KERNEL_SUBMISSIONS;
+
+		/* Unmask this bit to enable GuC scheduler */
+		params[GUC_CTL_FEATURE] &= ~GUC_CTL_DISABLE_SCHEDULER;
+	}
+
 	I915_WRITE(SOFT_SCRATCH(0), 0);
 
 	for (i = 0; i < GUC_CTL_MAX_DWORDS; i++)
@@ -322,6 +350,8 @@ int intel_guc_load_ucode(struct drm_device *dev, bool wait)
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 	int err;
 
+	i915.enable_guc_scheduling = sanitize_enable_guc_scheduling(dev);
+
 	DRM_DEBUG_DRIVER("GuC: wait %d, fetch status %d, load status %d\n",
 		wait, guc_fw->uc_fw_fetch_status, guc_fw->uc_fw_load_status);
 
@@ -336,15 +366,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;
 }
@@ -413,5 +460,7 @@ void intel_guc_ucode_fini(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 
+	guc_scheduler_fini(dev);
+
 	intel_uc_fw_fini(dev, guc_fw);
 }
diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
new file mode 100644
index 0000000..ed744fb
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#include <linux/firmware.h>
+#include "i915_drv.h"
+#include "intel_guc.h"
+
+void guc_scheduler_fini(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+	struct drm_i915_gem_object *ctx_pool = guc->ctx_pool_obj;
+
+	guc_scheduler_disable(dev);
+
+	if (ctx_pool) {
+		intel_guc_release_gem_obj(ctx_pool);
+		guc->ctx_pool_obj = NULL;
+	}
+}
+
+/* Set up the resources needed by the firmware scheduler. Currently this only
+ * requires one object that can be mapped through the GGTT.
+ */
+int guc_scheduler_init(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	const size_t ctxsize = sizeof(struct guc_context_desc);
+	const size_t poolsize = MAX_GUC_GPU_CONTEXTS * ctxsize;
+	const size_t gemsize = round_up(poolsize, PAGE_SIZE);
+	struct intel_guc *guc = &dev_priv->guc;
+
+	if (!i915.enable_guc_scheduling)
+		return 0; /* not enabled  */
+
+	if (guc->ctx_pool_obj)
+		return 0; /* already allocated */
+
+	guc->ctx_pool_obj = intel_guc_allocate_gem_obj(dev_priv->dev, gemsize);
+	if (!guc->ctx_pool_obj)
+		return -ENOMEM;
+
+	return 0;
+}
+
+int guc_scheduler_enable(struct drm_device *dev)
+{
+	if (!i915.enable_guc_scheduling)
+		return 0;
+
+	/* TODO: placeholder for guc scheduler enabling */
+	return 0;
+}
+
+void guc_scheduler_disable(struct drm_device *dev)
+{
+	/* TODO: placeholder for guc scheduler disabling */
+}
+
+bool sanitize_enable_guc_scheduling(struct drm_device *dev)
+{
+	if (!HAS_GUC_UCODE(dev) || !HAS_GUC_SCHED(dev))
+		return false;
+
+	return i915.enable_guc_scheduling;
+}
+
-- 
1.9.1

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

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

* [PATCH v2 11/18] drm/i915: Integration of GuC client
  2015-04-03 18:08 [PATCH v2 00/18] *** Command submission via GuC for SKL *** yu.dai
                   ` (9 preceding siblings ...)
  2015-04-03 18:08 ` [PATCH v2 10/18] drm/i915: Functions to support command submission via GuC yu.dai
@ 2015-04-03 18:08 ` yu.dai
  2015-04-03 18:08 ` [PATCH v2 12/18] drm/i915: Interrupt routing for GuC scheduler yu.dai
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: yu.dai @ 2015-04-03 18:08 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    | 446 +++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_guc_loader.c    |   7 +
 drivers/gpu/drm/i915/intel_guc_scheduler.c |  29 +-
 6 files changed, 539 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 48f56d9..28a448a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1847,6 +1847,11 @@ static inline struct drm_i915_private *dev_to_i915(struct device *dev)
 	return to_i915(dev_get_drvdata(dev));
 }
 
+static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
+{
+	return container_of(guc, struct drm_i915_private, guc);
+}
+
 /* Iterate over initialised rings */
 #define for_each_ring(ring__, dev_priv__, i__) \
 	for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index c7f3ed6..96d9dcb 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);
@@ -113,4 +156,13 @@ int guc_scheduler_enable(struct drm_device *dev);
 void guc_scheduler_disable(struct drm_device *dev);
 bool sanitize_enable_guc_scheduling(struct drm_device *dev);
 
+/* intel_guc_client.c */
+struct i915_guc_client*
+i915_guc_client_alloc(struct drm_device *dev, u32 priority);
+void i915_guc_client_free(struct drm_device *dev,
+			  struct i915_guc_client *client);
+int i915_guc_client_submit(struct i915_guc_client *client,
+			   struct intel_context *ctx,
+			   struct intel_engine_cs *ring);
+
 #endif
diff --git a/drivers/gpu/drm/i915/intel_guc_client.c b/drivers/gpu/drm/i915/intel_guc_client.c
new file mode 100644
index 0000000..ae6323a
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_client.c
@@ -0,0 +1,446 @@
+/*
+ * 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_ctx_desc(struct intel_guc *guc, uint32_t id)
+{
+	spin_lock(&guc->host2guc_lock);
+	ida_simple_remove(&guc->ctx_ids, id);
+	spin_unlock(&guc->host2guc_lock);
+}
+
+static uint32_t guc_assign_ctx_desc(struct intel_guc *guc)
+{
+	int id;
+
+	spin_lock(&guc->host2guc_lock);
+	id = ida_simple_get(&guc->ctx_ids, 0,
+			    MAX_GUC_GPU_CONTEXTS, GFP_KERNEL);
+	spin_unlock(&guc->host2guc_lock);
+
+	return (id < 0) ? INVALID_CTX_ID : (uint32_t)id;
+}
+
+static void guc_release_doorbell(struct intel_guc *guc, uint16_t id)
+{
+	spin_lock(&guc->host2guc_lock);
+	bitmap_clear(guc->doorbell_bitmap, id, 1);
+	spin_unlock(&guc->host2guc_lock);
+}
+
+static uint16_t guc_assign_doorbell(struct intel_guc *guc, u32 priority)
+{
+	const uint16_t size = I915_MAX_DOORBELLS;
+	uint16_t id;
+
+	spin_lock(&guc->host2guc_lock);
+
+	/* The bitmap is split into two halves - high and normal priority. */
+	if (priority <= GUC_CTX_PRIORITY_HIGH) {
+		id = find_next_zero_bit(guc->doorbell_bitmap, size, size / 2);
+		if (id == size)
+			id = INVALID_DOORBELL_ID;
+	} else {
+		id = find_next_zero_bit(guc->doorbell_bitmap, size / 2, 0);
+		if (id == size / 2)
+			id = INVALID_DOORBELL_ID;
+	}
+
+	if (id != INVALID_DOORBELL_ID)
+		bitmap_set(guc->doorbell_bitmap, id, 1);
+
+	spin_unlock(&guc->host2guc_lock);
+
+	return id;
+}
+
+static off_t guc_select_doorbell_cacheline(struct intel_guc *guc)
+{
+	const int cacheline_size = boot_cpu_data.x86_clflush_size;
+	const int cacheline_per_page = PAGE_SIZE / cacheline_size;
+	off_t offset;
+
+	spin_lock(&guc->host2guc_lock);
+
+	/* Doorbell uses single cache line */
+	offset = cacheline_size * guc->db_cacheline;
+
+	/* Moving to next cache line to reduce contention */
+	guc->db_cacheline = (guc->db_cacheline + 1) % cacheline_per_page;
+
+	spin_unlock(&guc->host2guc_lock);
+
+	return offset;
+}
+
+static void init_ctx_desc(struct intel_guc *guc,
+			  struct i915_guc_client *client)
+{
+	struct guc_context_desc desc;
+	struct sg_table *sg;
+
+	memset(&desc, 0, sizeof(desc));
+
+	desc.attribute = GUC_CTX_DESC_ATTR_ACTIVE | GUC_CTX_DESC_ATTR_KERNEL;
+	desc.context_id = client->ctx_index;
+	desc.priority = client->priority;
+	desc.engines_used = (1 << RCS) | (1 << VCS) | (1 << BCS) |
+			    (1 << VECS) | (1 << VCS2); /* all engines */
+	desc.db_id = client->doorbell_id;
+
+	/*
+	 * The CPU address is only needed at certain points, so kmap_atomic on
+	 * demand instead of storing it in the ctx descriptor.
+	 * XXX: May make debug easier to have it mapped
+	 */
+	desc.db_trigger_cpu = 0;
+	desc.db_trigger_uk = client->doorbell_offset +
+		i915_gem_obj_ggtt_offset(client->client_obj);
+	desc.db_trigger_phy = client->doorbell_offset +
+		sg_dma_address(client->client_obj->pages->sgl);
+
+	desc.process_desc = client->proc_desc_offset +
+		i915_gem_obj_ggtt_offset(client->client_obj);
+
+	desc.wq_addr = client->wq_offset +
+		i915_gem_obj_ggtt_offset(client->client_obj);
+
+	desc.wq_size = client->wq_size;
+
+	/*
+	 * XXX: Take LRCs from an existing intel_context if this is not an
+	 * IsKMDCreatedContext client
+	 */
+	desc.desc_private = (uintptr_t)client;
+
+	/* Pool context is pinned already */
+	sg = guc->ctx_pool_obj->pages;
+	sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
+			     sizeof(desc) * client->ctx_index);
+}
+
+static void fini_ctx_desc(struct intel_guc *guc,
+			  struct i915_guc_client *client)
+{
+	struct guc_context_desc desc;
+	struct sg_table *sg;
+
+	memset(&desc, 0, sizeof(desc));
+
+	sg = guc->ctx_pool_obj->pages;
+	sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
+			     sizeof(desc) * client->ctx_index);
+}
+
+static void init_proc_desc(struct intel_guc *guc,
+			   struct i915_guc_client *client)
+{
+	struct guc_process_desc *desc;
+	void *base;
+
+	base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
+	desc = base + client->proc_desc_offset;
+
+	memset(desc, 0, sizeof(*desc));
+
+	/*
+	 * XXX: pDoorbell and WQVBaseAddress are pointers in process address
+	 * space for ring3 clients (set them as in mmap_ioctl) or kernel
+	 * space for kernel clients (map on demand instead? May make debug
+	 * easier to have it mapped).
+	 */
+	desc->wq_base_addr = 0;
+	desc->db_base_addr = 0;
+
+	desc->context_id = client->ctx_index;
+	desc->wq_size_bytes = client->wq_size;
+	desc->wq_status = WQ_STATUS_ACTIVE;
+	desc->priority = client->priority;
+
+	kunmap_atomic(base);
+}
+
+static int host2guc_allocate_doorbell(struct intel_guc *guc,
+				      struct i915_guc_client *client)
+{
+	u32 data[2];
+
+	data[0] = HOST2GUC_ACTION_ALLOCATE_DOORBELL;
+	data[1] = client->ctx_index;
+
+	return intel_guc_action(guc, data, 2);
+}
+
+static int host2guc_release_doorbell(struct intel_guc *guc,
+				     struct i915_guc_client *client)
+{
+	u32 data[2];
+
+	data[0] = HOST2GUC_ACTION_DEALLOCATE_DOORBELL;
+	data[1] = client->ctx_index;
+
+	return intel_guc_action(guc, data, 2);
+}
+
+static void init_doorbell(struct intel_guc *guc,
+			  struct i915_guc_client *client)
+{
+	struct guc_doorbell_info *doorbell;
+	void *base;
+
+	base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
+	doorbell = base + client->doorbell_offset;
+
+	doorbell->db_status = 1;
+	doorbell->cookie = 0;
+
+	kunmap_atomic(base);
+}
+
+static void disable_doorbell(struct intel_guc *guc,
+			     struct i915_guc_client *client)
+{
+	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	struct guc_doorbell_info *doorbell;
+	void *base;
+	int drbreg = GEN8_DRBREGL(client->doorbell_id);
+	int value;
+
+	base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
+	doorbell = base + client->doorbell_offset;
+
+	doorbell->db_status = 0;
+
+	kunmap_atomic(base);
+
+	I915_WRITE(drbreg, I915_READ(drbreg) & ~GEN8_DRB_VALID);
+
+	value = I915_READ(drbreg);
+	WARN_ON((value & GEN8_DRB_VALID) != 0);
+
+	I915_WRITE(GEN8_DRBREGU(client->doorbell_id), 0);
+	I915_WRITE(drbreg, 0);
+
+	/* XXX: wait for any interrupts */
+	/* XXX: wait for workqueue to drain */
+}
+
+void i915_guc_client_free(struct drm_device *dev,
+			  struct i915_guc_client *client)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+
+	if (!client)
+		return;
+
+	if (client->doorbell_id != INVALID_DOORBELL_ID) {
+		disable_doorbell(guc, client);
+		host2guc_release_doorbell(guc, client);
+		guc_release_doorbell(guc, client->doorbell_id);
+	}
+
+	/*
+	 * XXX: wait for any outstanding submissions before freeing memory.
+	 * Be sure to drop any locks
+	 */
+
+	intel_guc_release_gem_obj(client->client_obj);
+
+	if (client->ctx_index != INVALID_CTX_ID) {
+		fini_ctx_desc(guc, client);
+		guc_release_ctx_desc(guc, client->ctx_index);
+	}
+
+	kfree(client);
+}
+
+/**
+ * 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 = guc_assign_ctx_desc(guc);
+	if (client->ctx_index == INVALID_CTX_ID)
+		goto err;
+
+	/* The first page is doorbell/proc_desc. Two followed pages are wq. */
+	obj = intel_guc_allocate_gem_obj(dev, GUC_DB_SIZE + GUC_WQ_SIZE);
+	if (!obj)
+		goto err;
+
+	client->client_obj = obj;
+	client->wq_offset = GUC_DB_SIZE;
+	client->wq_size = GUC_WQ_SIZE;
+
+	client->doorbell_offset = guc_select_doorbell_cacheline(guc);
+
+	/*
+	 * Since the doorbell only requires a single cacheline, we can save
+	 * space by putting the application process descriptor in the same
+	 * page. Use the half of the page that doesn't include the doorbell.
+	 */
+	if (client->doorbell_offset >= (GUC_DB_SIZE / 2))
+		client->proc_desc_offset = 0;
+	else
+		client->proc_desc_offset = (GUC_DB_SIZE / 2);
+
+	client->doorbell_id = guc_assign_doorbell(guc, client->priority);
+	if (client->doorbell_id == INVALID_DOORBELL_ID)
+		/* XXX: evict a doorbell instead */
+		goto err;
+
+	init_ctx_desc(guc, client);
+	init_proc_desc(guc, client);
+	init_doorbell(guc, client);
+
+	/* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
+	I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+
+	/* XXX: Any cache flushes needed? General domain mgmt calls? */
+
+	if (host2guc_allocate_doorbell(guc, client))
+		goto err;
+
+	return client;
+
+err:
+	i915_guc_client_free(dev, client);
+	return NULL;
+}
+
+/**
+ * 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 44dc0b3..dafab32 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -292,12 +292,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 ed744fb..a78b4b3 100644
--- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -36,6 +36,8 @@ void guc_scheduler_fini(struct drm_device *dev)
 	if (ctx_pool) {
 		intel_guc_release_gem_obj(ctx_pool);
 		guc->ctx_pool_obj = NULL;
+
+		ida_destroy(&guc->ctx_ids);
 	}
 }
 
@@ -60,21 +62,44 @@ int guc_scheduler_init(struct drm_device *dev)
 	if (!guc->ctx_pool_obj)
 		return -ENOMEM;
 
+	spin_lock_init(&dev_priv->guc.host2guc_lock);
+
+	ida_init(&guc->ctx_ids);
+
+	memset(guc->doorbell_bitmap, 0, sizeof(guc->doorbell_bitmap));
+	guc->db_cacheline = 0;
+
 	return 0;
 }
 
 int guc_scheduler_enable(struct drm_device *dev)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+
 	if (!i915.enable_guc_scheduling)
 		return 0;
 
-	/* TODO: placeholder for guc scheduler enabling */
+	/* client for execbuf submission */
+	guc->execbuf_client =
+			i915_guc_client_alloc(dev, GUC_CTX_PRIORITY_NORMAL);
+	if (!guc->execbuf_client) {
+		DRM_ERROR("Failed to create execbuf guc_client\n");
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
 void guc_scheduler_disable(struct drm_device *dev)
 {
-	/* TODO: placeholder for guc scheduler disabling */
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+
+	if (guc->execbuf_client) {
+		i915_guc_client_free(dev, guc->execbuf_client);
+		guc->execbuf_client = NULL;
+	}
 }
 
 bool sanitize_enable_guc_scheduling(struct drm_device *dev)
-- 
1.9.1

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

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

* [PATCH v2 12/18] drm/i915: Interrupt routing for GuC scheduler
  2015-04-03 18:08 [PATCH v2 00/18] *** Command submission via GuC for SKL *** yu.dai
                   ` (10 preceding siblings ...)
  2015-04-03 18:08 ` [PATCH v2 11/18] drm/i915: Integration of GuC client yu.dai
@ 2015-04-03 18:08 ` yu.dai
  2015-04-03 18:08 ` [PATCH v2 13/18] drm/i915: Enable commands submission via GuC yu.dai
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: yu.dai @ 2015-04-03 18:08 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 ac2919f..551f702 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1372,12 +1372,18 @@ enum skl_disp_power_wells {
 #define GFX_MODE_GEN7	0x0229c
 #define RING_MODE_GEN7(ring)	((ring)->mmio_base+0x29c)
 #define   GFX_RUN_LIST_ENABLE		(1<<15)
+#define   GFX_INTERRUPT_STEERING	(1<<14)
 #define   GFX_TLB_INVALIDATE_EXPLICIT	(1<<13)
 #define   GFX_SURFACE_FAULT_ENABLE	(1<<12)
 #define   GFX_REPLAY_MODE		(1<<11)
 #define   GFX_PSMI_GRANULARITY		(1<<10)
 #define   GFX_PPGTT_ENABLE		(1<<9)
 
+#define   GFX_FORWARD_VBLANK_MASK	(3<<5)
+#define   GFX_FORWARD_VBLANK_NEVER	(0<<5)
+#define   GFX_FORWARD_VBLANK_ALWAYS	(1<<5)
+#define   GFX_FORWARD_VBLANK_COND	(2<<5)
+
 #define VLV_DISPLAY_BASE 0x180000
 #define VLV_MIPI_BASE VLV_DISPLAY_BASE
 
@@ -5196,11 +5202,12 @@ enum skl_disp_power_wells {
 #define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
 #define GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
 
-#define GEN8_BCS_IRQ_SHIFT 16
 #define GEN8_RCS_IRQ_SHIFT 0
-#define GEN8_VCS2_IRQ_SHIFT 16
+#define GEN8_BCS_IRQ_SHIFT 16
 #define GEN8_VCS1_IRQ_SHIFT 0
+#define GEN8_VCS2_IRQ_SHIFT 16
 #define GEN8_VECS_IRQ_SHIFT 0
+#define GEN8_WD_IRQ_SHIFT 16
 
 #define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe)))
 #define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe)))
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 96d9dcb..4d9fb34 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 a78b4b3..008f74c 100644
--- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -25,6 +25,53 @@
 #include "i915_drv.h"
 #include "intel_guc.h"
 
+static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
+{
+	struct intel_engine_cs *ring;
+	int i, irqs;
+
+	/* tell all command streamers to forward interrupts and vblank to GuC */
+	irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_ALWAYS);
+	irqs |= _MASKED_BIT_ENABLE(GFX_INTERRUPT_STEERING);
+	for_each_ring(ring, dev_priv, i)
+		I915_WRITE(RING_MODE_GEN7(ring), irqs);
+
+	/* tell DE to send (all) flip_done to GuC */
+	irqs = DERRMR_PIPEA_PRI_FLIP_DONE | DERRMR_PIPEA_SPR_FLIP_DONE |
+	       DERRMR_PIPEB_PRI_FLIP_DONE | DERRMR_PIPEB_SPR_FLIP_DONE |
+	       DERRMR_PIPEC_PRI_FLIP_DONE | DERRMR_PIPEC_SPR_FLIP_DONE;
+	/* Unmasked bits will cause GuC response message to be sent */
+	I915_WRITE(DE_GUCRMR, ~irqs);
+
+	/* route USER_INTERRUPT to Host, all others are sent to GuC. */
+	irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+	       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+	/* These three registers have the same bit definitions */
+	I915_WRITE(GUC_BCS_RCS_IER, ~irqs);
+	I915_WRITE(GUC_VCS2_VCS1_IER, ~irqs);
+	I915_WRITE(GUC_WD_VECS_IER, ~irqs);
+}
+
+static void direct_interrupts_to_host(struct drm_i915_private *dev_priv)
+{
+	struct intel_engine_cs *ring;
+	int i, irqs;
+
+	/* tell all command streamers NOT to forward interrupts and vblank to GuC */
+	irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_NEVER);
+	irqs |= _MASKED_BIT_DISABLE(GFX_INTERRUPT_STEERING);
+	for_each_ring(ring, dev_priv, i)
+		I915_WRITE(RING_MODE_GEN7(ring), irqs);
+
+	/* tell DE to send nothing to GuC */
+	I915_WRITE(DE_GUCRMR, ~0);
+
+	/* route all GT interrupts to the host */
+	I915_WRITE(GUC_BCS_RCS_IER, 0);
+	I915_WRITE(GUC_VCS2_VCS1_IER, 0);
+	I915_WRITE(GUC_WD_VECS_IER, 0);
+}
+
 void guc_scheduler_fini(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -77,8 +124,10 @@ int guc_scheduler_enable(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_guc *guc = &dev_priv->guc;
 
-	if (!i915.enable_guc_scheduling)
+	if (!i915.enable_guc_scheduling) {
+		direct_interrupts_to_host(dev_priv);
 		return 0;
+	}
 
 	/* client for execbuf submission */
 	guc->execbuf_client =
@@ -88,6 +137,8 @@ int guc_scheduler_enable(struct drm_device *dev)
 		return -ENOMEM;
 	}
 
+	direct_interrupts_to_guc(dev_priv);
+
 	return 0;
 }
 
@@ -96,6 +147,8 @@ void guc_scheduler_disable(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_guc *guc = &dev_priv->guc;
 
+	direct_interrupts_to_host(dev_priv);
+
 	if (guc->execbuf_client) {
 		i915_guc_client_free(dev, guc->execbuf_client);
 		guc->execbuf_client = NULL;
-- 
1.9.1

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

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

* [PATCH v2 13/18] drm/i915: Enable commands submission via GuC
  2015-04-03 18:08 [PATCH v2 00/18] *** Command submission via GuC for SKL *** yu.dai
                   ` (11 preceding siblings ...)
  2015-04-03 18:08 ` [PATCH v2 12/18] drm/i915: Interrupt routing for GuC scheduler yu.dai
@ 2015-04-03 18:08 ` yu.dai
  2015-04-03 18:08 ` [PATCH v2 14/18] drm/i915: debugfs of GuC status yu.dai
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: yu.dai @ 2015-04-03 18:08 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    | 182 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_guc_scheduler.c |   2 +-
 drivers/gpu/drm/i915/intel_lrc.c           |  16 ++-
 4 files changed, 200 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 4d9fb34..c44b3c0 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 ae6323a..d64cad6 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()
+ *
  */
 
 /*
@@ -411,6 +420,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);
@@ -430,6 +441,167 @@ err:
 	return NULL;
 }
 
+/* Get valid workqueue item and return it back to offset */
+static int get_workqueue_space(struct i915_guc_client *gc, u32 *offset)
+{
+	struct guc_process_desc *desc;
+	void *base;
+	u32 size = sizeof(struct guc_wq_item);
+	int ret = 0, timeout_counter = 200;
+	unsigned long flags;
+
+	base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, 0));
+	desc = base + gc->proc_desc_offset;
+
+	while (timeout_counter-- > 0) {
+		spin_lock_irqsave(&gc->wq_lock, flags);
+
+		ret = wait_for(CIRC_SPACE(gc->wq_tail, desc->head,
+			       gc->wq_size) >= size, 1);
+
+		if (!ret) {
+			*offset = gc->wq_tail;
+
+			/* advance the tail for next workqueue item */
+			gc->wq_tail += size;
+			gc->wq_tail &= gc->wq_size - 1;
+
+			/* this will break the loop */
+			timeout_counter = 0;
+		}
+
+		spin_unlock_irqrestore(&gc->wq_lock, flags);
+	};
+
+	kunmap_atomic(base);
+
+	return ret;
+}
+
+
+static int add_workqueue_item(struct i915_guc_client *gc,
+			      struct intel_context *ctx,
+			      struct intel_engine_cs *ring)
+{
+	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+	struct drm_i915_gem_object *ctx_obj;
+	struct guc_wq_item *wqi;
+	void *base;
+	struct page *page;
+	u32 wq_off = 0, tail = ringbuf->tail, wq_len;
+	int ret;
+
+	ctx_obj = ctx->engine[ring->id].state;
+
+	WARN_ON(!i915_gem_obj_is_pinned(ctx_obj));
+	WARN_ON(!i915_gem_obj_is_pinned(ringbuf->obj));
+
+	/* Need this because of the deferred pin ctx and ring */
+	/* Shall we move this right after ring is pinned? */
+	page = i915_gem_object_get_page(ctx_obj, 1);
+	base = kmap_atomic(page);
+
+	*((u32 *)base + CTX_RING_BUFFER_START + 1) =
+		i915_gem_obj_ggtt_offset(ringbuf->obj);
+
+	kunmap_atomic(base);
+
+	ret = get_workqueue_space(gc, &wq_off);
+	if (ret)
+		return ret;
+
+	/* For now workqueue item is 4 DWs; workqueue buffer is 2 pages. So we
+	 * should not have the case where structure wqi is across page, neither
+	 * wrapped to the beginning. This simplifies the implementation below.
+	 *
+	 * XXX: if not the case, we need save data to a temp wqi and copy it to
+	 * workqueue buffer dw by dw.
+	 */
+	WARN_ON(sizeof(struct guc_wq_item) != 16);
+	WARN_ON(wq_off & 3);
+
+	/* wq starts from the page after doorbell / process_desc */
+	base = kmap_atomic(i915_gem_object_get_page(gc->client_obj,
+			(wq_off + GUC_DB_SIZE) >> PAGE_SHIFT));
+	wq_off &= PAGE_SIZE - 1;
+	wqi = (struct guc_wq_item *)((char *)base + wq_off);
+
+	/* len does not include the header */
+	wq_len = sizeof(struct guc_wq_item) / sizeof(u32) - 1;
+	wqi->header = WQ_TYPE_INORDER |
+			(wq_len << WQ_LEN_SHIFT) |
+			(ring->id << WQ_TARGET_SHIFT) |
+			WQ_NO_WCFLUSH_WAIT;
+
+	wqi->context_desc = (u32)execlists_ctx_descriptor(ring, ctx_obj);
+	/* tail index is in qw */
+	tail >>= 3;
+	wqi->ring_tail = tail << WQ_RING_TAIL_SHIFT;
+	wqi->fence_id = 0; /*XXX: what fence to be here */
+
+	kunmap_atomic(base);
+
+	return 0;
+}
+
+static int ring_doorbell(struct i915_guc_client *gc)
+{
+	struct guc_process_desc *desc;
+	union guc_doorbell_qw db_cmp, db_exc, db_ret;
+	union guc_doorbell_qw *db;
+	void *base;
+	int attempt = 2, ret = -EAGAIN;
+
+	base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, 0));
+	desc = base + gc->proc_desc_offset;
+
+	/* Update the tail so it is visible to GuC */
+	desc->tail = gc->wq_tail;
+
+	/* current cookie */
+	db_cmp.db_status = GUC_DOORBELL_ENABLED;
+	db_cmp.cookie = gc->cookie;
+
+	/* cookie to be updated */
+	db_exc.db_status = GUC_DOORBELL_ENABLED;
+	db_exc.cookie = gc->cookie + 1;
+	if (db_exc.cookie == 0)
+		db_exc.cookie = 1;
+
+	/* pointer of current doorbell cacheline */
+	db = base + gc->doorbell_offset;
+
+	while (attempt--) {
+		/* lets ring the doorbell */
+		db_ret.value_qw = atomic64_cmpxchg((atomic64_t *)db,
+			db_cmp.value_qw, db_exc.value_qw);
+
+		/* if the exchange was successfully executed */
+		if (db_ret.value_qw == db_cmp.value_qw) {
+			/* db was successfully rung */
+			gc->cookie = db_exc.cookie;
+			ret = 0;
+			break;
+		}
+
+		/* XXX: doorbell was lost and need to acquire it again */
+		if (db_ret.db_status == GUC_DOORBELL_DISABLED)
+			break;
+
+		DRM_ERROR("Cookie mismatch. Expected %d, returned %d\n",
+			  db_cmp.cookie, db_ret.cookie);
+
+		/* update the cookie to newly read cookie from GuC */
+		db_cmp.cookie = db_ret.cookie;
+		db_exc.cookie = db_ret.cookie + 1;
+		if (db_exc.cookie == 0)
+			db_exc.cookie = 1;
+	}
+
+	kunmap_atomic(base);
+	return ret;
+}
+
 /**
  * i915_guc_client_submit() - Submit commands through GuC
  * @client:	the guc client where commands will go through
@@ -442,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_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
index 008f74c..c0b7231 100644
--- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -160,6 +160,6 @@ bool sanitize_enable_guc_scheduling(struct drm_device *dev)
 	if (!HAS_GUC_UCODE(dev) || !HAS_GUC_SCHED(dev))
 		return false;
 
-	return i915.enable_guc_scheduling;
+	return i915.enable_execlists && i915.enable_guc_scheduling;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index d4011b4..cb5a617 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -618,13 +618,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_wait_for_space(struct intel_ringbuffer *ringbuf,
@@ -941,6 +945,7 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,
 {
 	struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state;
 	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	int ret = 0;
 
 	WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));
@@ -953,6 +958,10 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,
 		ret = intel_pin_and_map_ringbuffer_obj(ring->dev, ringbuf);
 		if (ret)
 			goto unpin_ctx_obj;
+
+		/* Invalidate GuC TLB. */
+		if (i915.enable_guc_scheduling)
+			I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
 	}
 
 	return ret;
@@ -1284,8 +1293,13 @@ out:
 static int gen8_init_rcs_context(struct intel_engine_cs *ring,
 		       struct intel_context *ctx)
 {
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	int ret;
 
+	/* Invalidate GuC TLB. */
+	if (i915.enable_guc_scheduling)
+		I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+
 	ret = intel_logical_ring_workarounds_emit(ring, ctx);
 	if (ret)
 		return ret;
-- 
1.9.1

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

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

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

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

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

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

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 91c945b..ec10ca0 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2252,6 +2252,77 @@ static int i915_llc(struct seq_file *m, void *data)
 	return 0;
 }
 
+static void i915_uc_load_status_info(struct seq_file *m, struct intel_uc_fw *uc_fw)
+{
+	seq_printf(m, "%s firmware status:\n\tpath: <%s>\n\tfetch: %d\n\tload: %d\n",
+			uc_fw->uc_name,
+			uc_fw->uc_fw_path,
+			uc_fw->uc_fw_fetch_status,
+			uc_fw->uc_fw_load_status);
+}
+
+static int i915_guc_load_status_info(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = m->private;
+	struct drm_i915_private *dev_priv = node->minor->dev->dev_private;
+	u32 tmp, i;
+
+	i915_uc_load_status_info(m, &dev_priv->guc.guc_fw);
+
+	tmp = I915_READ(GUC_STATUS);
+
+	seq_puts(m, "\nResponse from GuC:\n");
+	seq_printf(m, "\tBootrom status = 0x%x\n",
+		(tmp & GS_BOOTROM_MASK) >> GS_BOOTROM_SHIFT);
+	seq_printf(m, "\tuKernel status = 0x%x\n",
+		(tmp & GS_UKERNEL_MASK) >> GS_UKERNEL_SHIFT);
+	seq_printf(m, "\tMIA Core status = 0x%x\n",
+		(tmp & GS_MIA_MASK) >> GS_MIA_SHIFT);
+	seq_puts(m, "Scratch registers value:\n");
+	for (i = 0; i < 16; i++)
+		seq_printf(m, "\t%2d: \t0x%x\n", i, I915_READ(SOFT_SCRATCH(i)));
+
+	return 0;
+}
+
+static int i915_guc_info(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_guc guc;
+	struct i915_guc_client client;
+
+	memset(&client, 0, sizeof(struct i915_guc_client));
+
+	/* Take a local copy of the GuC data, so we can dump it at leisure */
+	spin_lock(&dev_priv->guc.host2guc_lock);
+	guc = dev_priv->guc;
+	if (guc.execbuf_client) {
+		spin_lock(&guc.execbuf_client->wq_lock);
+		client = *guc.execbuf_client;
+		spin_unlock(&guc.execbuf_client->wq_lock);
+	}
+	spin_unlock(&dev_priv->guc.host2guc_lock);
+
+	seq_printf(m, "GuC total action count: %llu\n", guc.action_count);
+	seq_printf(m, "GuC last action command: 0x%x\n", guc.action_cmd);
+	seq_printf(m, "GuC last action status: 0x%x\n", guc.action_status);
+
+	seq_printf(m, "GuC action failure count: %u\n", guc.action_fail);
+	seq_printf(m, "GuC last action error code: %d\n", guc.action_err);
+
+	seq_printf(m, "GuC execbuf client @ %p:\n", guc.execbuf_client);
+	seq_printf(m, "\tTotal submissions: %llu\n", client.submissions);
+	seq_printf(m, "\tFailed to queue: %u\n", client.q_fail);
+	seq_printf(m, "\tFailed doorbell: %u\n", client.b_fail);
+	seq_printf(m, "\tLast submission result: %d\n", client.retcode);
+
+	/* Add more as required ... */
+
+	return 0;
+}
+
 static int i915_edp_psr_status(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = m->private;
@@ -4674,6 +4745,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 c44b3c0..4ed2d6a 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 d64cad6..e1f67d4 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] 21+ messages in thread

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

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

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

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

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index ec10ca0..1618410 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2323,6 +2323,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;
@@ -4747,6 +4775,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 28a448a..c2d88d9 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 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 4ed2d6a..e47e648 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;
 
@@ -177,7 +178,7 @@ int guc_scheduler_init(struct drm_device *dev);
 void guc_scheduler_fini(struct drm_device *dev);
 int guc_scheduler_enable(struct drm_device *dev);
 void guc_scheduler_disable(struct drm_device *dev);
-bool sanitize_enable_guc_scheduling(struct drm_device *dev);
+void sanitize_enable_guc_scheduling(struct drm_device *dev);
 
 /* intel_guc_client.c */
 struct i915_guc_client*
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index dafab32..3a33618 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_GUC_UCODE_GEN8 "i915/guc_gen8.bin"
@@ -53,6 +59,10 @@
 MODULE_FIRMWARE(I915_GUC_UCODE_GEN8);
 MODULE_FIRMWARE(I915_GUC_UCODE_GEN9);
 
+#define GUC_LOG_DPC_PAGES	3
+#define GUC_LOG_ISR_PAGES	3
+#define GUC_LOG_CRASH_PAGES	1
+
 /**
  * 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) {
@@ -357,7 +414,7 @@ int intel_guc_load_ucode(struct drm_device *dev, bool wait)
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 	int err;
 
-	i915.enable_guc_scheduling = sanitize_enable_guc_scheduling(dev);
+	sanitize_enable_guc_scheduling(dev);
 
 	DRM_DEBUG_DRIVER("GuC: wait %d, fetch status %d, load status %d\n",
 		wait, guc_fw->uc_fw_fetch_status, guc_fw->uc_fw_load_status);
@@ -467,6 +524,11 @@ void intel_guc_ucode_fini(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
 
+	if (dev_priv->guc.log_obj) {
+		intel_guc_release_gem_obj(dev_priv->guc.log_obj);
+		dev_priv->guc.log_obj = NULL;
+	}
+
 	guc_scheduler_fini(dev);
 
 	intel_uc_fw_fini(dev, guc_fw);
diff --git a/drivers/gpu/drm/i915/intel_guc_scheduler.c b/drivers/gpu/drm/i915/intel_guc_scheduler.c
index c0b7231..ea1ff28 100644
--- a/drivers/gpu/drm/i915/intel_guc_scheduler.c
+++ b/drivers/gpu/drm/i915/intel_guc_scheduler.c
@@ -155,11 +155,10 @@ void guc_scheduler_disable(struct drm_device *dev)
 	}
 }
 
-bool sanitize_enable_guc_scheduling(struct drm_device *dev)
+void sanitize_enable_guc_scheduling(struct drm_device *dev)
 {
-	if (!HAS_GUC_UCODE(dev) || !HAS_GUC_SCHED(dev))
-		return false;
-
-	return i915.enable_execlists && i915.enable_guc_scheduling;
+	if (!HAS_GUC_UCODE(dev) || !HAS_GUC_SCHED(dev) ||
+	    !i915.enable_execlists)
+		i915.enable_guc_scheduling = false;
 }
 
-- 
1.9.1

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

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

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

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

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

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

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

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index cb5a617..1948de8 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -1760,20 +1760,10 @@ uint32_t get_lr_context_size(struct intel_engine_cs *ring)
 
 	WARN_ON(INTEL_INFO(ring->dev)->gen < 8);
 
-	switch (ring->id) {
-	case RCS:
-		if (INTEL_INFO(ring->dev)->gen >= 9)
-			ret = GEN9_LR_CONTEXT_RENDER_SIZE;
-		else
-			ret = GEN8_LR_CONTEXT_RENDER_SIZE;
-		break;
-	case VCS:
-	case BCS:
-	case VECS:
-	case VCS2:
-		ret = GEN8_LR_CONTEXT_OTHER_SIZE;
-		break;
-	}
+	if (INTEL_INFO(ring->dev)->gen >= 9)
+		ret = GEN9_LR_CONTEXT_RENDER_SIZE;
+	else
+		ret = GEN8_LR_CONTEXT_RENDER_SIZE;
 
 	return ret;
 }
@@ -1822,6 +1812,9 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 	WARN_ON(ctx->engine[ring->id].state);
 
 	context_size = round_up(get_lr_context_size(ring), 4096);
+	/* One extra page as the sharing data between driver and GuC */
+	if (i915.enable_guc_scheduling)
+		context_size += PAGE_SIZE;
 
 	ctx_obj = i915_gem_alloc_context_obj(dev, context_size);
 	if (IS_ERR(ctx_obj)) {
@@ -1850,7 +1843,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 44c7b99..a3873f9 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1980,7 +1980,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
 	INIT_LIST_HEAD(&ring->active_list);
 	INIT_LIST_HEAD(&ring->request_list);
 	INIT_LIST_HEAD(&ring->execlist_queue);
-	ringbuf->size = 32 * PAGE_SIZE;
+	ringbuf->size = 4 * PAGE_SIZE;
 	ringbuf->ring = ring;
 	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
 
-- 
1.9.1

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

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

* [PATCH v2 17/18] drm/i915: Taking forcewake during GuC load.
  2015-04-03 18:08 [PATCH v2 00/18] *** Command submission via GuC for SKL *** yu.dai
                   ` (15 preceding siblings ...)
  2015-04-03 18:08 ` [PATCH v2 16/18] drm/i915: Ring Context allocating for GuC yu.dai
@ 2015-04-03 18:08 ` yu.dai
  2015-04-03 18:08 ` [PATCH v2 18/18] Documentation/drm: kerneldoc for GuC yu.dai
  17 siblings, 0 replies; 21+ messages in thread
From: yu.dai @ 2015-04-03 18:08 UTC (permalink / raw)
  To: intel-gfx; +Cc: Sagar Kamble

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 3a33618..2edf329 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -338,6 +338,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)
@@ -386,6 +387,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] 21+ messages in thread

* [PATCH v2 18/18] Documentation/drm: kerneldoc for GuC
  2015-04-03 18:08 [PATCH v2 00/18] *** Command submission via GuC for SKL *** yu.dai
                   ` (16 preceding siblings ...)
  2015-04-03 18:08 ` [PATCH v2 17/18] drm/i915: Taking forcewake during GuC load yu.dai
@ 2015-04-03 18:08 ` yu.dai
  2015-04-09 13:24   ` shuang.he
  17 siblings, 1 reply; 21+ messages in thread
From: yu.dai @ 2015-04-03 18:08 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 f4976cd..cd226e4 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] 21+ messages in thread

* Re: [PATCH v2 18/18] Documentation/drm: kerneldoc for GuC
  2015-04-03 18:08 ` [PATCH v2 18/18] Documentation/drm: kerneldoc for GuC yu.dai
@ 2015-04-09 13:24   ` shuang.he
  2015-04-09 13:28     ` Daniel Vetter
  0 siblings, 1 reply; 21+ messages in thread
From: shuang.he @ 2015-04-09 13:24 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: 6129
-------------------------------------Summary-------------------------------------
Platform          Delta          drm-intel-nightly          Series Applied
PNV                 -1              276/276              275/276
ILK                 -2              302/302              300/302
SNB                 -1              313/313              312/313
IVB                 -1              337/337              336/337
BYT                 -1              286/286              285/286
HSW                 -1              395/395              394/395
BDW                 -3              321/321              318/321
-------------------------------------Detailed-------------------------------------
Platform  Test                                drm-intel-nightly          Series Applied
*PNV  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*ILK  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*ILK  igt@gem_fenced_exec_thrash@no-spare-fences-busy      PASS(3)      DMESG_WARN(1)
(dmesg patch applied)drm:i915_hangcheck_elapsed[i915]]*ERROR*Hangcheck_timer_elapsed...bsd_ring_idle@Hangcheck timer elapsed... bsd ring idle
*SNB  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*IVB  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*BYT  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*HSW  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
(dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
*BDW  igt@drm_vma_limiter      PASS(3)      DMESG_WARN(1)
(dmesg patch applied)INFO:possible_circular_locking_dependency_detected@INFO: possible circular locking dependency detected
*BDW  igt@gem_dummy_reloc_loop@render      PASS(3)      DMESG_WARN(1)
(dmesg patch applied)drm:i915_hangcheck_elapsed[i915]]*ERROR*Hangcheck_timer_elapsed...render_ring_idle@Hangcheck timer elapsed... render ring idle
*BDW  igt@gem_exec_faulting_reloc@no-prefault      PASS(3)      DMESG_WARN(1)
(dmesg patch applied)INFO:possible_circular_locking_dependency_detected@INFO: possible circular locking dependency detected
Note: You need to pay more attention to line start with '*'
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v2 18/18] Documentation/drm: kerneldoc for GuC
  2015-04-09 13:24   ` shuang.he
@ 2015-04-09 13:28     ` Daniel Vetter
  0 siblings, 0 replies; 21+ messages in thread
From: Daniel Vetter @ 2015-04-09 13:28 UTC (permalink / raw)
  To: shuang.he; +Cc: intel-gfx

On Thu, Apr 09, 2015 at 06:24:01AM -0700, shuang.he@intel.com wrote:
> Tested-By: Intel Graphics QA PRTS (Patch Regression Test System Contact: shuang.he@intel.com)
> Task id: 6129
> -------------------------------------Summary-------------------------------------
> Platform          Delta          drm-intel-nightly          Series Applied
> PNV                 -1              276/276              275/276
> ILK                 -2              302/302              300/302
> SNB                 -1              313/313              312/313
> IVB                 -1              337/337              336/337
> BYT                 -1              286/286              285/286
> HSW                 -1              395/395              394/395
> BDW                 -3              321/321              318/321
> -------------------------------------Detailed-------------------------------------
> Platform  Test                                drm-intel-nightly          Series Applied
> *PNV  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
> (dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
> *ILK  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
> (dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
> *ILK  igt@gem_fenced_exec_thrash@no-spare-fences-busy      PASS(3)      DMESG_WARN(1)
> (dmesg patch applied)drm:i915_hangcheck_elapsed[i915]]*ERROR*Hangcheck_timer_elapsed...bsd_ring_idle@Hangcheck timer elapsed... bsd ring idle
> *SNB  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
> (dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
> *IVB  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
> (dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
> *BYT  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
> (dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
> *HSW  igt@drv_debugfs_reader      PASS(3)      DMESG_WARN(1)
> (dmesg patch applied)INFO:trying_to_register_non-static_key@INFO: trying to register non-static key.
> *BDW  igt@drm_vma_limiter      PASS(3)      DMESG_WARN(1)
> (dmesg patch applied)INFO:possible_circular_locking_dependency_detected@INFO: possible circular locking dependency detected
> *BDW  igt@gem_dummy_reloc_loop@render      PASS(3)      DMESG_WARN(1)
> (dmesg patch applied)drm:i915_hangcheck_elapsed[i915]]*ERROR*Hangcheck_timer_elapsed...render_ring_idle@Hangcheck timer elapsed... render ring idle
> *BDW  igt@gem_exec_faulting_reloc@no-prefault      PASS(3)      DMESG_WARN(1)
> (dmesg patch applied)INFO:possible_circular_locking_dependency_detected@INFO: possible circular locking dependency detected
> Note: You need to pay more attention to line start with '*'

Sounds like this patch series breaks lockdep pretty badly. Please retest
with CONFIG_PROVE_LOCKING (and all the other debug options while you're at
it) and fixup the fallout.

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

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

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

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-03 18:08 [PATCH v2 00/18] *** Command submission via GuC for SKL *** yu.dai
2015-04-03 18:08 ` [PATCH v2 01/18] drm/i915: Add guc firmware interface headers yu.dai
2015-04-03 18:08 ` [PATCH v2 02/18] drm/i915: Add i915_gem_object_write() to i915_gem.c yu.dai
2015-04-03 18:08 ` [PATCH v2 03/18] drm/i915: Unified firmware loading mechanism yu.dai
2015-04-03 18:08 ` [PATCH v2 04/18] drm/i915: GuC firmware loader yu.dai
2015-04-03 18:08 ` [PATCH v2 05/18] drm/i915: Add firmware version check yu.dai
2015-04-03 18:08 ` [PATCH v2 06/18] drm/i915: Defer default hardware context initialisation until first open yu.dai
2015-04-03 18:08 ` [PATCH v2 07/18] drm/i915: Move execlists defines from .c to .h yu.dai
2015-04-03 18:08 ` [PATCH v2 08/18] drm/i915: Make several execlist helper functions external yu.dai
2015-04-03 18:08 ` [PATCH v2 09/18] drm/i915: Add functions to allocate / release gem obj for GuC yu.dai
2015-04-03 18:08 ` [PATCH v2 10/18] drm/i915: Functions to support command submission via GuC yu.dai
2015-04-03 18:08 ` [PATCH v2 11/18] drm/i915: Integration of GuC client yu.dai
2015-04-03 18:08 ` [PATCH v2 12/18] drm/i915: Interrupt routing for GuC scheduler yu.dai
2015-04-03 18:08 ` [PATCH v2 13/18] drm/i915: Enable commands submission via GuC yu.dai
2015-04-03 18:08 ` [PATCH v2 14/18] drm/i915: debugfs of GuC status yu.dai
2015-04-03 18:08 ` [PATCH v2 15/18] drm/i915: Enable GuC firmware log yu.dai
2015-04-03 18:08 ` [PATCH v2 16/18] drm/i915: Ring Context allocating for GuC yu.dai
2015-04-03 18:08 ` [PATCH v2 17/18] drm/i915: Taking forcewake during GuC load yu.dai
2015-04-03 18:08 ` [PATCH v2 18/18] Documentation/drm: kerneldoc for GuC yu.dai
2015-04-09 13:24   ` shuang.he
2015-04-09 13:28     ` Daniel Vetter

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