From adca3c434cc92ed273931a15d506c21dd900b6a1 Mon Sep 17 00:00:00 2001
From: Tony Ye <tony.ye@intel.com>
Date: Tue, 11 Dec 2018 07:16:30 +0800
Subject: [PATCH] Set subslice mask according to the per-context sseu value.
 Fixes #267.

---
 .../linux/common/os/i915/include/mos_bufmgr.h |  10 ++
 .../linux/common/os/i915/mos_bufmgr.c         | 118 ++++++++++++++++++
 .../linux/common/os/mos_os_specific.c         |  27 ++++
 3 files changed, 155 insertions(+)

diff --git a/media_driver/linux/common/os/i915/include/mos_bufmgr.h b/media_driver/linux/common/os/i915/include/mos_bufmgr.h
index 081522247f1..810e05ea09d 100644
--- a/media_driver/linux/common/os/i915/include/mos_bufmgr.h
+++ b/media_driver/linux/common/os/i915/include/mos_bufmgr.h
@@ -321,6 +321,16 @@ int mos_set_context_param(struct mos_linux_context *ctx,
 
 int mos_get_subslice_total(int fd, unsigned int *subslice_total);
 int mos_get_eu_total(int fd, unsigned int *eu_total);
+
+int mos_get_context_param_sseu(struct mos_linux_context *ctx,
+                struct drm_i915_gem_context_param_sseu *sseu);
+int mos_set_context_param_sseu(struct mos_linux_context *ctx,
+                struct drm_i915_gem_context_param_sseu sseu);
+int mos_get_subslice_mask(int fd, unsigned int *subslice_mask);
+int mos_get_slice_mask(int fd, unsigned int *slice_mask);
+uint8_t mos_switch_off_n_bits(uint8_t in_mask, int n);
+unsigned int mos_hweight8(uint8_t w);
+
 #if defined(__cplusplus)
 extern "C" {
 #endif
diff --git a/media_driver/linux/common/os/i915/mos_bufmgr.c b/media_driver/linux/common/os/i915/mos_bufmgr.c
index c6aeb8a13d4..f017aa8cb74 100644
--- a/media_driver/linux/common/os/i915/mos_bufmgr.c
+++ b/media_driver/linux/common/os/i915/mos_bufmgr.c
@@ -4180,6 +4180,124 @@ mos_get_reset_stats(struct mos_linux_context *ctx,
     return ret;
 }
 
+unsigned int mos_hweight8(uint8_t w)
+{
+    uint32_t i, weight = 0;
+
+    for (i=0; i<8; i++)
+    {
+        weight += !!((w) & (1UL << i));
+    }
+    return weight;
+}
+
+uint8_t mos_switch_off_n_bits(uint8_t in_mask, int n)
+{
+    int i,count;
+    uint8_t bi,out_mask;
+
+    assert (n>0 && n<=8);
+
+    out_mask = in_mask;
+    count = n;
+    for(i=0; i<8; i++)
+    {
+        bi = 1UL<<i;
+        if (bi & in_mask)
+        {
+            out_mask &= ~bi;
+            count--;
+        }
+        if (count==0)
+        {
+            break;
+        }
+    }
+    return out_mask;
+}
+
+int
+mos_get_context_param_sseu(struct mos_linux_context *ctx,
+                struct drm_i915_gem_context_param_sseu *sseu)
+{
+    struct mos_bufmgr_gem *bufmgr_gem;
+    struct drm_i915_gem_context_param context_param;
+    int ret;
+
+    if (ctx == nullptr)
+        return -EINVAL;
+
+    bufmgr_gem = (struct mos_bufmgr_gem *)ctx->bufmgr;
+    memset(&context_param, 0, sizeof(context_param));
+    context_param.ctx_id = ctx->ctx_id;
+    context_param.param = I915_CONTEXT_PARAM_SSEU;
+    context_param.value = (uint64_t) sseu;
+    context_param.size = sizeof(struct drm_i915_gem_context_param_sseu);
+
+    ret = drmIoctl(bufmgr_gem->fd,
+            DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM,
+            &context_param);
+
+    return ret;
+}
+
+int
+mos_set_context_param_sseu(struct mos_linux_context *ctx,
+                struct drm_i915_gem_context_param_sseu sseu)
+{
+    struct mos_bufmgr_gem *bufmgr_gem;
+    struct drm_i915_gem_context_param context_param;
+    int ret;
+
+    if (ctx == nullptr)
+        return -EINVAL;
+
+    bufmgr_gem = (struct mos_bufmgr_gem *)ctx->bufmgr;
+    memset(&context_param, 0, sizeof(context_param));
+    context_param.ctx_id = ctx->ctx_id;
+    context_param.param = I915_CONTEXT_PARAM_SSEU;
+    context_param.value = (uint64_t) &sseu;
+    context_param.size = sizeof(struct drm_i915_gem_context_param_sseu);
+
+    ret = drmIoctl(bufmgr_gem->fd,
+               DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM,
+               &context_param);
+
+    return ret;
+}
+
+int
+mos_get_subslice_mask(int fd, unsigned int *subslice_mask)
+{
+    drm_i915_getparam_t gp;
+    int ret;
+
+    memclear(gp);
+    gp.value = (int*)subslice_mask;
+    gp.param = I915_PARAM_SUBSLICE_MASK;
+    ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
+    if (ret)
+        return -errno;
+
+    return 0;
+}
+
+int
+mos_get_slice_mask(int fd, unsigned int *slice_mask)
+{
+    drm_i915_getparam_t gp;
+    int ret;
+
+    memclear(gp);
+    gp.value = (int*)slice_mask;
+    gp.param = I915_PARAM_SLICE_MASK;
+    ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
+    if (ret)
+        return -errno;
+
+    return 0;
+}
+
 int
 mos_get_context_param(struct mos_linux_context *ctx,
                 uint32_t size,
diff --git a/media_driver/linux/common/os/mos_os_specific.c b/media_driver/linux/common/os/mos_os_specific.c
index f07064c731c..d910c60675b 100644
--- a/media_driver/linux/common/os/mos_os_specific.c
+++ b/media_driver/linux/common/os/mos_os_specific.c
@@ -4062,6 +4062,33 @@ MOS_STATUS Mos_Specific_CreateGpuContext(
         auto cmdBufMgr = pOsContextSpecific->GetCmdBufMgr();
         MOS_OS_CHK_NULL_RETURN(cmdBufMgr);
 
+        MOS_OS_CHK_NULL_RETURN(createOption);
+        if (GpuNode == MOS_GPU_NODE_3D && createOption->SSEUValue != 0)
+        {
+            struct drm_i915_gem_context_param_sseu sseu;
+            MOS_ZeroMemory(&sseu, sizeof(sseu));
+            sseu.engine_class = I915_ENGINE_CLASS_RENDER;
+            sseu.engine_instance = 0;
+
+            if (mos_get_context_param_sseu(pOsInterface->pOsContext->intel_context, &sseu))
+            {
+                MOS_OS_ASSERTMESSAGE("Failed to get sseu configuration.");
+                return MOS_STATUS_UNKNOWN;
+            };
+
+            if (mos_hweight8(sseu.subslice_mask) > createOption->packed.SubSliceCount)
+            {
+                sseu.subslice_mask = mos_switch_off_n_bits(sseu.subslice_mask,
+                        mos_hweight8(sseu.subslice_mask)-createOption->packed.SubSliceCount);
+            }
+
+            if (mos_set_context_param_sseu(pOsInterface->pOsContext->intel_context, sseu))
+            {
+                MOS_OS_ASSERTMESSAGE("Failed to set sseu configuration.");
+                return MOS_STATUS_UNKNOWN;
+            };
+        }
+
         if (pOsContextSpecific->GetGpuContextHandle(mosGpuCxt) == MOS_GPU_CONTEXT_INVALID_HANDLE)
         {
             auto gpuContext = gpuContextMgr->CreateGpuContext(GpuNode, cmdBufMgr, mosGpuCxt);