Skip to content

Commit

Permalink
drm/i915/guc: Updates for GuC 32.0.3 firmware
Browse files Browse the repository at this point in the history
New GuC 32.0.3 firmware made many changes around its ABI that
require driver updates:

* FW release version numbering schema now includes patch number
* FW release version encoding in CSS header
* Boot parameters
* Suspend/resume protocol
* Sample-forcewake command
* Additional Data Structures (ADS)

This commit is a squash of patches 3-8 from series [1].
[1] https://patchwork.freedesktop.org/series/58760/

Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Anusha Srivatsa <anusha.srivatsa@intel.com>
Cc: Jeff Mcgee <jeff.mcgee@intel.com>
Cc: John Spotswood <john.a.spotswood@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Tomasz Lis <tomasz.lis@intel.com>
Acked-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> # numbering schema
Acked-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> # ccs heaser
Acked-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> # boot params
Acked-by: John Spotswood <john.a.spotswood@intel.com> # suspend/resume
Acked-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> # sample-forcewake
Acked-by: John Spotswood <john.a.spotswood@intel.com> # sample-forcewake
Acked-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> # ADS
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20190527183613.17076-4-michal.wajdeczko@intel.com
  • Loading branch information
Michal Wajdeczko authored and Chris Wilson committed May 28, 2019
1 parent a2904ad commit ffd5ce2
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 243 deletions.
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/gt/intel_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,8 @@ ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine);
struct i915_request *
intel_engine_find_active_request(struct intel_engine_cs *engine);

u32 intel_engine_context_size(struct drm_i915_private *i915, u8 class);

#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)

static inline bool inject_preempt_hang(struct intel_engine_execlists *execlists)
Expand Down
9 changes: 4 additions & 5 deletions drivers/gpu/drm/i915/gt/intel_engine_cs.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ static const struct engine_info intel_engines[] = {
};

/**
* ___intel_engine_context_size() - return the size of the context for an engine
* intel_engine_context_size() - return the size of the context for an engine
* @dev_priv: i915 device private
* @class: engine class
*
Expand All @@ -169,8 +169,7 @@ static const struct engine_info intel_engines[] = {
* in LRC mode, but does not include the "shared data page" used with
* GuC submission. The caller should account for this if using the GuC.
*/
static u32
__intel_engine_context_size(struct drm_i915_private *dev_priv, u8 class)
u32 intel_engine_context_size(struct drm_i915_private *dev_priv, u8 class)
{
u32 cxt_size;

Expand Down Expand Up @@ -327,8 +326,8 @@ intel_engine_setup(struct drm_i915_private *dev_priv,

engine->uabi_class = intel_engine_classes[info->class].uabi_class;

engine->context_size = __intel_engine_context_size(dev_priv,
engine->class);
engine->context_size = intel_engine_context_size(dev_priv,
engine->class);
if (WARN_ON(engine->context_size > BIT(20)))
engine->context_size = 0;
if (engine->context_size)
Expand Down
88 changes: 34 additions & 54 deletions drivers/gpu/drm/i915/intel_guc.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,7 @@ void intel_guc_fini(struct intel_guc *guc)
static u32 guc_ctl_debug_flags(struct intel_guc *guc)
{
u32 level = intel_guc_log_get_level(&guc->log);
u32 flags;
u32 ads;

ads = intel_guc_ggtt_offset(guc, guc->ads_vma) >> PAGE_SHIFT;
flags = ads << GUC_ADS_ADDR_SHIFT | GUC_ADS_ENABLED;

if (!GUC_LOG_LEVEL_IS_ENABLED(level))
flags |= GUC_LOG_DEFAULT_DISABLED;
u32 flags = 0;

if (!GUC_LOG_LEVEL_IS_VERBOSE(level))
flags |= GUC_LOG_DISABLED;
Expand All @@ -272,11 +265,7 @@ static u32 guc_ctl_feature_flags(struct intel_guc *guc)
{
u32 flags = 0;

flags |= GUC_CTL_VCS2_ENABLED;

if (USES_GUC_SUBMISSION(guc_to_i915(guc)))
flags |= GUC_CTL_KERNEL_SUBMISSIONS;
else
if (!USES_GUC_SUBMISSION(guc_to_i915(guc)))
flags |= GUC_CTL_DISABLE_SCHEDULER;

return flags;
Expand Down Expand Up @@ -340,6 +329,14 @@ static u32 guc_ctl_log_params_flags(struct intel_guc *guc)
return flags;
}

static u32 guc_ctl_ads_flags(struct intel_guc *guc)
{
u32 ads = intel_guc_ggtt_offset(guc, guc->ads_vma) >> PAGE_SHIFT;
u32 flags = ads << GUC_ADS_ADDR_SHIFT;

return flags;
}

/*
* Initialise the GuC parameter block before starting the firmware
* transfer. These parameters are read by the firmware on startup
Expand All @@ -353,20 +350,11 @@ void intel_guc_init_params(struct intel_guc *guc)

memset(params, 0, sizeof(params));

/*
* 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_CTXINFO] = guc_ctl_ctxinfo_flags(guc);
params[GUC_CTL_LOG_PARAMS] = guc_ctl_log_params_flags(guc);
params[GUC_CTL_FEATURE] = guc_ctl_feature_flags(guc);
params[GUC_CTL_LOG_PARAMS] = guc_ctl_log_params_flags(guc);
params[GUC_CTL_DEBUG] = guc_ctl_debug_flags(guc);
params[GUC_CTL_CTXINFO] = guc_ctl_ctxinfo_flags(guc);
params[GUC_CTL_ADS] = guc_ctl_ads_flags(guc);

for (i = 0; i < GUC_CTL_MAX_DWORDS; i++)
DRM_DEBUG_DRIVER("param[%2d] = %#x\n", i, params[i]);
Expand Down Expand Up @@ -550,25 +538,33 @@ int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset)
return intel_guc_send(guc, action, ARRAY_SIZE(action));
}

/*
* The ENTER/EXIT_S_STATE actions queue the save/restore operation in GuC FW and
* then return, so waiting on the H2G is not enough to guarantee GuC is done.
* When all the processing is done, GuC writes INTEL_GUC_SLEEP_STATE_SUCCESS to
* scratch register 14, so we can poll on that. Note that GuC does not ensure
* that the value in the register is different from
* INTEL_GUC_SLEEP_STATE_SUCCESS while the action is in progress so we need to
* take care of that ourselves as well.
/**
* intel_guc_suspend() - notify GuC entering suspend state
* @guc: the guc
*/
static int guc_sleep_state_action(struct intel_guc *guc,
const u32 *action, u32 len)
int intel_guc_suspend(struct intel_guc *guc)
{
struct drm_i915_private *dev_priv = guc_to_i915(guc);
int ret;
u32 status;
u32 action[] = {
INTEL_GUC_ACTION_ENTER_S_STATE,
GUC_POWER_D1, /* any value greater than GUC_POWER_D0 */
};

/*
* The ENTER_S_STATE action queues the save/restore operation in GuC FW
* and then returns, so waiting on the H2G is not enough to guarantee
* GuC is done. When all the processing is done, GuC writes
* INTEL_GUC_SLEEP_STATE_SUCCESS to scratch register 14, so we can poll
* on that. Note that GuC does not ensure that the value in the register
* is different from INTEL_GUC_SLEEP_STATE_SUCCESS while the action is
* in progress so we need to take care of that ourselves as well.
*/

I915_WRITE(SOFT_SCRATCH(14), INTEL_GUC_SLEEP_STATE_INVALID_MASK);

ret = intel_guc_send(guc, action, len);
ret = intel_guc_send(guc, action, ARRAY_SIZE(action));
if (ret)
return ret;

Expand All @@ -588,21 +584,6 @@ static int guc_sleep_state_action(struct intel_guc *guc,
return 0;
}

/**
* intel_guc_suspend() - notify GuC entering suspend state
* @guc: the guc
*/
int intel_guc_suspend(struct intel_guc *guc)
{
u32 data[] = {
INTEL_GUC_ACTION_ENTER_S_STATE,
GUC_POWER_D1, /* any value greater than GUC_POWER_D0 */
intel_guc_ggtt_offset(guc, guc->shared_data)
};

return guc_sleep_state_action(guc, data, ARRAY_SIZE(data));
}

/**
* intel_guc_reset_engine() - ask GuC to reset an engine
* @guc: intel_guc structure
Expand Down Expand Up @@ -632,13 +613,12 @@ int intel_guc_reset_engine(struct intel_guc *guc,
*/
int intel_guc_resume(struct intel_guc *guc)
{
u32 data[] = {
u32 action[] = {
INTEL_GUC_ACTION_EXIT_S_STATE,
GUC_POWER_D0,
intel_guc_ggtt_offset(guc, guc->shared_data)
};

return guc_sleep_state_action(guc, data, ARRAY_SIZE(data));
return intel_guc_send(guc, action, ARRAY_SIZE(action));
}

/**
Expand Down
95 changes: 59 additions & 36 deletions drivers/gpu/drm/i915/intel_guc_ads.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ static void guc_policies_init(struct guc_policies *policies)
policies->max_num_work_items = POLICY_MAX_NUM_WI;

for (p = 0; p < GUC_CLIENT_PRIORITY_NUM; p++) {
for (i = GUC_RENDER_ENGINE; i < GUC_MAX_ENGINES_NUM; i++) {
for (i = 0; i < GUC_MAX_ENGINE_CLASSES; i++) {
policy = &policies->policy[p][i];

guc_policy_init(policy);
Expand All @@ -61,6 +61,11 @@ static void guc_policies_init(struct guc_policies *policies)
policies->is_valid = 1;
}

static void guc_ct_pool_entries_init(struct guc_ct_pool_entry *pool, u32 num)
{
memset(pool, 0, num * sizeof(*pool));
}

/*
* The first 80 dwords of the register state context, containing the
* execlists and ppgtt registers.
Expand All @@ -75,20 +80,21 @@ static void guc_policies_init(struct guc_policies *policies)
int intel_guc_ads_create(struct intel_guc *guc)
{
struct drm_i915_private *dev_priv = guc_to_i915(guc);
struct i915_vma *vma, *kernel_ctx_vma;
struct page *page;
struct i915_vma *vma;
/* The ads obj includes the struct itself and buffers passed to GuC */
struct {
struct guc_ads ads;
struct guc_policies policies;
struct guc_mmio_reg_state reg_state;
struct guc_gt_system_info system_info;
struct guc_clients_info clients_info;
struct guc_ct_pool_entry ct_pool[GUC_CT_POOL_SIZE];
u8 reg_state_buffer[GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE];
} __packed *blob;
struct intel_engine_cs *engine;
enum intel_engine_id id;
const u32 skipped_offset = LRC_HEADER_PAGES * PAGE_SIZE;
const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE;
u32 base;
u8 engine_class;
int ret;

GEM_BUG_ON(guc->ads_vma);

Expand All @@ -98,51 +104,68 @@ int intel_guc_ads_create(struct intel_guc *guc)

guc->ads_vma = vma;

page = i915_vma_first_page(vma);
blob = kmap(page);
blob = i915_gem_object_pin_map(guc->ads_vma->obj, I915_MAP_WB);
if (IS_ERR(blob)) {
ret = PTR_ERR(blob);
goto err_vma;
}

/* GuC scheduling policies */
guc_policies_init(&blob->policies);

/* MMIO reg state */
for_each_engine(engine, dev_priv, id) {
blob->reg_state.white_list[engine->guc_id].mmio_start =
engine->mmio_base + GUC_MMIO_WHITE_LIST_START;

/* Nothing to be saved or restored for now. */
blob->reg_state.white_list[engine->guc_id].count = 0;
}

/*
* The GuC requires a "Golden Context" when it reinitialises
* engines after a reset. Here we use the Render ring default
* context, which must already exist and be pinned in the GGTT,
* so its address won't change after we've told the GuC where
* to find it. Note that we have to skip our header (1 page),
* because our GuC shared data is there.
* GuC expects a per-engine-class context image and size
* (minus hwsp and ring context). The context image will be
* used to reinitialize engines after a reset. It must exist
* and be pinned in the GGTT, so that the address won't change after
* we have told GuC where to find it. The context size will be used
* to validate that the LRC base + size fall within allowed GGTT.
*/
kernel_ctx_vma = dev_priv->engine[RCS0]->kernel_context->state;
blob->ads.golden_context_lrca =
intel_guc_ggtt_offset(guc, kernel_ctx_vma) + skipped_offset;
for (engine_class = 0; engine_class <= MAX_ENGINE_CLASS; ++engine_class) {
if (engine_class == OTHER_CLASS)
continue;
/*
* TODO: Set context pointer to default state to allow
* GuC to re-init guilty contexts after internal reset.
*/
blob->ads.golden_context_lrca[engine_class] = 0;
blob->ads.eng_state_size[engine_class] =
intel_engine_context_size(dev_priv, engine_class) -
skipped_size;
}

/*
* The GuC expects us to exclude the portion of the context image that
* it skips from the size it is to read. It starts reading from after
* the execlist context (so skipping the first page [PPHWSP] and 80
* dwords). Weird guc is weird.
*/
for_each_engine(engine, dev_priv, id)
blob->ads.eng_state_size[engine->guc_id] =
engine->context_size - skipped_size;
/* System info */
blob->system_info.slice_enabled = hweight8(RUNTIME_INFO(dev_priv)->sseu.slice_mask);
blob->system_info.rcs_enabled = 1;
blob->system_info.bcs_enabled = 1;

blob->system_info.vdbox_enable_mask = VDBOX_MASK(dev_priv);
blob->system_info.vebox_enable_mask = VEBOX_MASK(dev_priv);
blob->system_info.vdbox_sfc_support_mask = RUNTIME_INFO(dev_priv)->vdbox_sfc_access;

base = intel_guc_ggtt_offset(guc, vma);

/* Clients info */
guc_ct_pool_entries_init(blob->ct_pool, ARRAY_SIZE(blob->ct_pool));

blob->clients_info.clients_num = 1;
blob->clients_info.ct_pool_addr = base + ptr_offset(blob, ct_pool);
blob->clients_info.ct_pool_count = ARRAY_SIZE(blob->ct_pool);

/* ADS */
blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
blob->ads.reg_state_buffer = base + ptr_offset(blob, reg_state_buffer);
blob->ads.reg_state_addr = base + ptr_offset(blob, reg_state);
blob->ads.gt_system_info = base + ptr_offset(blob, system_info);
blob->ads.clients_info = base + ptr_offset(blob, clients_info);

kunmap(page);
i915_gem_object_unpin_map(guc->ads_vma->obj);

return 0;

err_vma:
i915_vma_unpin_and_release(&guc->ads_vma, 0);
return ret;
}

void intel_guc_ads_destroy(struct intel_guc *guc)
Expand Down
Loading

0 comments on commit ffd5ce2

Please sign in to comment.