From: Tom O'Rourke <Tom.O'Rourke@xxxxxxxxx> SLPC shared data is used to pass information to/from SLPC firmware. For Skylake, platform sku type and slice count are identified from device id and fuse values. Support for other platforms needs to be added. v2: Update for SLPC interface version 2015.2.4 intel_slpc_active() returns 1 if slpc initialized (Paulo) Signed-off-by: Tom O'Rourke <Tom.O'Rourke@xxxxxxxxx> --- drivers/gpu/drm/i915/intel_drv.h | 9 ++++- drivers/gpu/drm/i915/intel_guc.h | 2 + drivers/gpu/drm/i915/intel_slpc.c | 84 ++++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_slpc.h | 75 ++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 11e7d66..724c482 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1589,9 +1589,16 @@ bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy, static inline int intel_slpc_active(struct drm_device *dev) { - return 0; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret = 0; + + if (dev_priv->guc.slpc.shared_data_obj) + ret = 1; + + return ret; } + /* intel_pm.c */ void intel_init_clock_gating(struct drm_device *dev); void intel_suspend_hw(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 417cc82..62075db 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -109,6 +109,8 @@ struct intel_guc { uint64_t submissions[GUC_MAX_ENGINES_NUM]; uint32_t last_seqno[GUC_MAX_ENGINES_NUM]; + + struct intel_slpc slpc; }; static inline int intel_slpc_enabled(void) diff --git a/drivers/gpu/drm/i915/intel_slpc.c b/drivers/gpu/drm/i915/intel_slpc.c index 474fac0..4689e70 100644 --- a/drivers/gpu/drm/i915/intel_slpc.c +++ b/drivers/gpu/drm/i915/intel_slpc.c @@ -22,17 +22,97 @@ * */ #include <linux/firmware.h> +#include <asm/msr-index.h> #include "i915_drv.h" #include "intel_guc.h" +static u8 slpc_get_platform_sku(struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = obj->base.dev; + enum slpc_platform_sku platform_sku; + + if (IS_SKL_ULX(dev)) + platform_sku = SLPC_PLATFORM_SKU_ULX; + else if (IS_SKL_ULT(dev)) + platform_sku = SLPC_PLATFORM_SKU_ULT; + else + platform_sku = SLPC_PLATFORM_SKU_DT; + + return (u8) platform_sku; +} + +static u8 slpc_get_slice_count(struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = obj->base.dev; + u8 slice_count = 1; + + if (IS_SKYLAKE(dev)) + slice_count = INTEL_INFO(dev)->slice_total; + + return slice_count; +} + +static void slpc_shared_data_init(struct drm_i915_gem_object *obj) +{ + struct page *page; + struct slpc_shared_data *data; + u64 msr_value; + + page = i915_gem_object_get_page(obj, 0); + if (page) { + data = kmap_atomic(page); + memset(data, 0, sizeof(struct slpc_shared_data)); + + data->slpc_version = SLPC_VERSION; + data->shared_data_size = sizeof(struct slpc_shared_data); + data->global_state = (u32) SLPC_GLOBAL_STATE_NOT_RUNNING; + data->platform_info.platform_sku = slpc_get_platform_sku(obj); + data->platform_info.slice_count = slpc_get_slice_count(obj); + data->platform_info.host_os = (u8) SLPC_HOST_OS_UNDEFINED; + data->platform_info.power_plan_source = + (u8) SLPC_POWER_PLAN_SOURCE(SLPC_POWER_PLAN_BALANCED, + SLPC_POWER_SOURCE_AC); + rdmsrl(MSR_TURBO_RATIO_LIMIT, msr_value); + data->platform_info.P0_freq = (u8) msr_value; + rdmsrl(MSR_PLATFORM_INFO, msr_value); + data->platform_info.P1_freq = (u8) (msr_value >> 8); + data->platform_info.Pe_freq = (u8) (msr_value >> 40); + data->platform_info.Pn_freq = (u8) (msr_value >> 48); + rdmsrl(MSR_PKG_POWER_LIMIT, msr_value); + data->platform_info.package_rapl_limit_high = + (u32) (msr_value >> 32); + data->platform_info.package_rapl_limit_low = (u32) msr_value; + + kunmap_atomic(data); + } +} + void intel_slpc_init(struct drm_device *dev) { - return; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + + /* Allocate shared data structure */ + obj = dev_priv->guc.slpc.shared_data_obj; + if (!obj) { + obj = gem_allocate_guc_obj(dev_priv->dev, + PAGE_ALIGN(sizeof(struct slpc_shared_data))); + dev_priv->guc.slpc.shared_data_obj = obj; + } + + if (!obj) + DRM_ERROR("slpc_shared_data allocation failed\n"); + else + slpc_shared_data_init(obj); } void intel_slpc_cleanup(struct drm_device *dev) { - return; + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Release shared data sturcutre */ + gem_release_guc_obj(dev_priv->guc.slpc.shared_data_obj); + dev_priv->guc.slpc.shared_data_obj = NULL; } void intel_slpc_suspend(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_slpc.h b/drivers/gpu/drm/i915/intel_slpc.h index 6cfadb3..94cd2f4 100644 --- a/drivers/gpu/drm/i915/intel_slpc.h +++ b/drivers/gpu/drm/i915/intel_slpc.h @@ -24,6 +24,81 @@ #ifndef _INTEL_SLPC_H_ #define _INTEL_SLPC_H_ +#define SLPC_MAJOR_VER 2 +#define SLPC_MINOR_VER 4 +#define SLPC_VERSION ((2015 << 16) | (SLPC_MAJOR_VER << 8) | (SLPC_MINOR_VER)) + +enum slpc_global_state { + SLPC_GLOBAL_STATE_NOT_RUNNING = 0, + SLPC_GLOBAL_STATE_INITIALIZING = 1, + SLPC_GLOBAL_STATE_RESETING = 2, + SLPC_GLOBAL_STATE_RUNNING = 3, + SLPC_GLOBAL_STATE_SHUTTING_DOWN = 4, + SLPC_GLOBAL_STATE_ERROR = 5 +}; + +enum slpc_host_os { + SLPC_HOST_OS_UNDEFINED = 0, + SLPC_HOST_OS_WINDOWS_8 = 1, +}; + +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)) + +struct slpc_platform_info { + u8 platform_sku; + u8 slice_count; + u8 host_os; + u8 power_plan_source; + u8 P0_freq; + u8 P1_freq; + u8 Pe_freq; + u8 Pn_freq; + u32 package_rapl_limit_high; + u32 package_rapl_limit_low; +} __packed; + +#define SLPC_MAX_OVERRIDE_PARAMETERS 192 +#define SLPC_OVERRIDE_BITFIELD_SIZE ((SLPC_MAX_OVERRIDE_PARAMETERS + 31) / 32) + +struct slpc_shared_data { + u32 slpc_version; + u32 shared_data_size; + u32 global_state; + struct slpc_platform_info platform_info; + u32 task_state_data; + u32 override_parameters_set_bits[SLPC_OVERRIDE_BITFIELD_SIZE]; + u32 override_parameters_values[SLPC_MAX_OVERRIDE_PARAMETERS]; +} __packed; + +struct intel_slpc { + struct drm_i915_gem_object *shared_data_obj; +}; + /* intel_slpc.c */ void intel_slpc_init(struct drm_device *dev); void intel_slpc_cleanup(struct drm_device *dev); -- 1.9.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx