@@ -22,15 +22,98 @@
*
*/
#include <linux/firmware.h>
+#include <asm/msr-index.h>
#include "i915_drv.h"
#include "intel_guc.h"
+static unsigned int slpc_get_platform_sku(struct drm_i915_private *dev_priv)
+{
+ enum slpc_platform_sku platform_sku;
+
+ if (IS_SKL_ULX(dev_priv))
+ platform_sku = SLPC_PLATFORM_SKU_ULX;
+ else if (IS_SKL_ULT(dev_priv))
+ platform_sku = SLPC_PLATFORM_SKU_ULT;
+ else
+ platform_sku = SLPC_PLATFORM_SKU_DT;
+
+ WARN_ON(platform_sku > 0xFF);
+
+ return platform_sku;
+}
+
+static unsigned int slpc_get_slice_count(struct drm_i915_private *dev_priv)
+{
+ unsigned int slice_count = 1;
+
+ if (IS_SKYLAKE(dev_priv))
+ slice_count = hweight8(INTEL_INFO(dev_priv)->sseu.slice_mask);
+
+ return slice_count;
+}
+
+static void slpc_shared_data_init(struct drm_i915_private *dev_priv)
+{
+ struct page *page;
+ struct slpc_shared_data *data;
+ u64 msr_value;
+
+ page = i915_vma_first_page(dev_priv->guc.slpc.vma);
+ data = kmap_atomic(page);
+
+ memset(data, 0, sizeof(struct slpc_shared_data));
+
+ data->shared_data_size = sizeof(struct slpc_shared_data);
+ data->global_state = SLPC_GLOBAL_STATE_NOT_RUNNING;
+ data->platform_info.platform_sku =
+ slpc_get_platform_sku(dev_priv);
+ data->platform_info.slice_count =
+ slpc_get_slice_count(dev_priv);
+ data->platform_info.power_plan_source =
+ SLPC_POWER_PLAN_SOURCE(SLPC_POWER_PLAN_BALANCED,
+ SLPC_POWER_SOURCE_AC);
+ rdmsrl(MSR_TURBO_RATIO_LIMIT, msr_value);
+ data->platform_info.P0_freq = msr_value;
+ rdmsrl(MSR_PLATFORM_INFO, msr_value);
+ data->platform_info.P1_freq = msr_value >> 8;
+ data->platform_info.Pe_freq = msr_value >> 40;
+ data->platform_info.Pn_freq = msr_value >> 48;
+
+ kunmap_atomic(data);
+}
+
void intel_slpc_init(struct drm_i915_private *dev_priv)
{
+ struct intel_guc *guc = &dev_priv->guc;
+ struct i915_vma *vma;
+
+ dev_priv->guc.slpc.active = false;
+
+ /* Allocate shared data structure */
+ vma = dev_priv->guc.slpc.vma;
+ if (!vma) {
+ vma = guc_allocate_vma(guc,
+ PAGE_ALIGN(sizeof(struct slpc_shared_data)));
+ if (IS_ERR(vma)) {
+ DRM_ERROR("slpc_shared_data allocation failed\n");
+ i915.enable_slpc = 0;
+ return;
+ }
+
+ dev_priv->guc.slpc.vma = vma;
+ }
+
+ slpc_shared_data_init(dev_priv);
}
void intel_slpc_cleanup(struct drm_i915_private *dev_priv)
{
+ struct intel_guc *guc = &dev_priv->guc;
+
+ /* Release shared data structure */
+ mutex_lock(&dev_priv->drm.struct_mutex);
+ i915_vma_unpin_and_release(&guc->slpc.vma);
+ mutex_unlock(&dev_priv->drm.struct_mutex);
}
void intel_slpc_suspend(struct drm_i915_private *dev_priv)
@@ -24,8 +24,103 @@
#ifndef _INTEL_SLPC_H_
#define _INTEL_SLPC_H_
+enum slpc_global_state {
+ SLPC_GLOBAL_STATE_NOT_RUNNING = 0,
+ SLPC_GLOBAL_STATE_INITIALIZING = 1,
+ SLPC_GLOBAL_STATE_RESETTING = 2,
+ SLPC_GLOBAL_STATE_RUNNING = 3,
+ SLPC_GLOBAL_STATE_SHUTTING_DOWN = 4,
+ SLPC_GLOBAL_STATE_ERROR = 5
+};
+
+enum slpc_platform_sku {
+ SLPC_PLATFORM_SKU_UNDEFINED = 0,
+ SLPC_PLATFORM_SKU_ULX = 1,
+ SLPC_PLATFORM_SKU_ULT = 2,
+ SLPC_PLATFORM_SKU_T = 3,
+ SLPC_PLATFORM_SKU_MOBL = 4,
+ SLPC_PLATFORM_SKU_DT = 5,
+ SLPC_PLATFORM_SKU_UNKNOWN = 6,
+};
+
+enum slpc_power_plan {
+ SLPC_POWER_PLAN_UNDEFINED = 0,
+ SLPC_POWER_PLAN_BATTERY_SAVER = 1,
+ SLPC_POWER_PLAN_BALANCED = 2,
+ SLPC_POWER_PLAN_PERFORMANCE = 3,
+ SLPC_POWER_PLAN_UNKNOWN = 4,
+};
+
+enum slpc_power_source {
+ SLPC_POWER_SOURCE_UNDEFINED = 0,
+ SLPC_POWER_SOURCE_AC = 1,
+ SLPC_POWER_SOURCE_DC = 2,
+ SLPC_POWER_SOURCE_UNKNOWN = 3,
+};
+
+#define SLPC_POWER_PLAN_SOURCE(plan, source) ((plan) | ((source) << 6))
+#define SLPC_POWER_PLAN(plan_source) ((plan_source) & 0x3F)
+#define SLPC_POWER_SOURCE(plan_source) ((plan_source) >> 6)
+
+struct slpc_platform_info {
+ u8 platform_sku;
+ u8 slice_count;
+ u8 reserved;
+ u8 power_plan_source;
+ u8 P0_freq;
+ u8 P1_freq;
+ u8 Pe_freq;
+ u8 Pn_freq;
+ u32 reserved1;
+ u32 reserved2;
+} __packed;
+
+struct slpc_task_state_data {
+ union {
+ u32 bitfield1;
+ struct {
+ u32 gtperf_task_active:1;
+ u32 gtperf_stall_possible:1;
+ u32 gtperf_gaming_mode:1;
+ u32 gtperf_target_fps:8;
+ u32 dcc_task_active:1;
+ u32 in_dcc:1;
+ u32 in_dct:1;
+ u32 freq_switch_active:1;
+ u32 ibc_enabled:1;
+ u32 ibc_active:1;
+ u32 pg1_enabled:1;
+ u32 pg1_active:1;
+ u32 reserved:13;
+ };
+ };
+ union {
+ u32 bitfield2;
+ struct {
+ u32 max_unslice_freq:8;
+ u32 min_unslice_freq:8;
+ u32 max_slice_freq:8;
+ u32 min_slice_freq:8;
+ };
+ };
+} __packed;
+
+#define SLPC_MAX_OVERRIDE_PARAMETERS 192
+#define SLPC_OVERRIDE_BITFIELD_SIZE ((SLPC_MAX_OVERRIDE_PARAMETERS + 31) / 32)
+
+struct slpc_shared_data {
+ u32 reserved;
+ u32 shared_data_size;
+ u32 global_state;
+ struct slpc_platform_info platform_info;
+ struct slpc_task_state_data task_state_data;
+ u32 override_parameters_set_bits[SLPC_OVERRIDE_BITFIELD_SIZE];
+ u32 override_parameters_values[SLPC_MAX_OVERRIDE_PARAMETERS];
+} __packed;
+
struct intel_slpc {
bool active;
+ struct i915_vma *vma;
};
/* intel_slpc.c */