Skip to content

Commit

Permalink
drm/i915/guc: Add fetch of hwconfig blob
Browse files Browse the repository at this point in the history
Implement support for fetching the hardware description table from the
GuC. The call is made twice - once without a destination buffer to
query the size and then a second time to fill in the buffer.

The table is stored in the GT structure so that it can be fetched once
at driver load time. Keeping inside a GuC structure would mean it
would be release and reloaded on a GuC reset (part of a full GT
reset). However, the table does not change just because the GT has been
reset and the GuC reloaded. Also, dynamic memory allocations inside
the reset path are a problem.

Note that the table is only available on ADL-P and later platforms.

v2 (John's v2 patch):
 * Move to GT level to avoid memory allocation during reset path (and
   unnecessary re-read of the table on a reset).

v5 (of Jordan's posting):
 * Various changes made by Jordan and recommended by Michal
   - Makefile ordering
   - Adjust "struct intel_guc_hwconfig hwconfig" comment
   - Set Copyright year to 2022 in intel_guc_hwconfig.c/.h
   - Drop inline from hwconfig_to_guc()
   - Replace hwconfig param with guc in __guc_action_get_hwconfig()
   - Move zero size check into guc_hwconfig_discover_size()
   - Change comment to say zero size offset/size is needed to get size
   - Add has_guc_hwconfig to devinfo and drop has_table()
   - Change drm_err to notice in __uc_init_hw() and use %pe

v6 (of Jordan's posting):
 * Added a couple more small changes recommended by Michal
 * Merge in John's v2 patch, but note:
   - Using drm_notice as recommended by Michal
   - Reverted Michal's suggestion of using devinfo

v7 (of Jordan's posting):
 * Change back to drm_err as preferred by John

Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Acked-by: Jon Bloomfield <jon.bloomfield@intel.com>
Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220306232157.1174335-2-jordan.l.justen@intel.com
  • Loading branch information
John Harrison authored and John Harrison committed Mar 18, 2022
1 parent 7fe7c2a commit 8781f05
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ i915-y += gt/uc/intel_uc.o \
gt/uc/intel_guc_ct.o \
gt/uc/intel_guc_debugfs.o \
gt/uc/intel_guc_fw.o \
gt/uc/intel_guc_hwconfig.o \
gt/uc/intel_guc_log.o \
gt/uc/intel_guc_log_debugfs.o \
gt/uc/intel_guc_rc.o \
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/i915/gt/intel_gt.c
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,11 @@ int intel_gt_init(struct intel_gt *gt)
if (err)
goto err_uc_init;

err = intel_gt_init_hwconfig(gt);
if (err)
drm_err(&gt->i915->drm, "Failed to retrieve hwconfig table: %pe\n",
ERR_PTR(err));

err = __engines_record_defaults(gt);
if (err)
goto err_gt;
Expand Down Expand Up @@ -799,6 +804,7 @@ void intel_gt_driver_release(struct intel_gt *gt)
intel_gt_pm_fini(gt);
intel_gt_fini_scratch(gt);
intel_gt_fini_buffer_pool(gt);
intel_gt_fini_hwconfig(gt);
}

void intel_gt_driver_late_release(struct intel_gt *gt)
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/i915/gt/intel_gt_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "i915_vma.h"
#include "intel_engine_types.h"
#include "intel_gt_buffer_pool_types.h"
#include "intel_hwconfig.h"
#include "intel_llc_types.h"
#include "intel_reset_types.h"
#include "intel_rc6_types.h"
Expand Down Expand Up @@ -204,6 +205,9 @@ struct intel_gt {
struct sseu_dev_info sseu;

unsigned long mslice_mask;

/** @hwconfig: hardware configuration data */
struct intel_hwconfig hwconfig;
} info;

struct {
Expand Down
21 changes: 21 additions & 0 deletions drivers/gpu/drm/i915/gt/intel_hwconfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2022 Intel Corporation
*/

#ifndef _INTEL_HWCONFIG_H_
#define _INTEL_HWCONFIG_H_

#include <linux/types.h>

struct intel_gt;

struct intel_hwconfig {
u32 size;
void *ptr;
};

int intel_gt_init_hwconfig(struct intel_gt *gt);
void intel_gt_fini_hwconfig(struct intel_gt *gt);

#endif /* _INTEL_HWCONFIG_H_ */
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ enum intel_guc_action {
INTEL_GUC_ACTION_ENGINE_FAILURE_NOTIFICATION = 0x1009,
INTEL_GUC_ACTION_SETUP_PC_GUCRC = 0x3004,
INTEL_GUC_ACTION_AUTHENTICATE_HUC = 0x4000,
INTEL_GUC_ACTION_GET_HWCONFIG = 0x4100,
INTEL_GUC_ACTION_REGISTER_CONTEXT = 0x4502,
INTEL_GUC_ACTION_DEREGISTER_CONTEXT = 0x4503,
INTEL_GUC_ACTION_DEREGISTER_CONTEXT_DONE = 0x4600,
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/i915/gt/uc/abi/guc_errors_abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

enum intel_guc_response_status {
INTEL_GUC_RESPONSE_STATUS_SUCCESS = 0x0,
INTEL_GUC_RESPONSE_NOT_SUPPORTED = 0x20,
INTEL_GUC_RESPONSE_NO_ATTRIBUTE_TABLE = 0x201,
INTEL_GUC_RESPONSE_NO_DECRYPTION_KEY = 0x202,
INTEL_GUC_RESPONSE_DECRYPTION_FAILED = 0x204,
INTEL_GUC_RESPONSE_STATUS_GENERIC_FAIL = 0xF000,
};

Expand Down
162 changes: 162 additions & 0 deletions drivers/gpu/drm/i915/gt/uc/intel_guc_hwconfig.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2022 Intel Corporation
*/

#include "gt/intel_gt.h"
#include "gt/intel_hwconfig.h"
#include "i915_drv.h"
#include "i915_memcpy.h"

/*
* GuC has a blob containing hardware configuration information (HWConfig).
* This is formatted as a simple and flexible KLV (Key/Length/Value) table.
*
* For example, a minimal version could be:
* enum device_attr {
* ATTR_SOME_VALUE = 0,
* ATTR_SOME_MASK = 1,
* };
*
* static const u32 hwconfig[] = {
* ATTR_SOME_VALUE,
* 1, // Value Length in DWords
* 8, // Value
*
* ATTR_SOME_MASK,
* 3,
* 0x00FFFFFFFF, 0xFFFFFFFF, 0xFF000000,
* };
*
* The attribute ids are defined in a hardware spec.
*/

static int __guc_action_get_hwconfig(struct intel_guc *guc,
u32 ggtt_offset, u32 ggtt_size)
{
u32 action[] = {
INTEL_GUC_ACTION_GET_HWCONFIG,
lower_32_bits(ggtt_offset),
upper_32_bits(ggtt_offset),
ggtt_size,
};
int ret;

ret = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action), NULL, 0);
if (ret == -ENXIO)
return -ENOENT;

return ret;
}

static int guc_hwconfig_discover_size(struct intel_guc *guc, struct intel_hwconfig *hwconfig)
{
int ret;

/*
* Sending a query with zero offset and size will return the
* size of the blob.
*/
ret = __guc_action_get_hwconfig(guc, 0, 0);
if (ret < 0)
return ret;

if (ret == 0)
return -EINVAL;

hwconfig->size = ret;
return 0;
}

static int guc_hwconfig_fill_buffer(struct intel_guc *guc, struct intel_hwconfig *hwconfig)
{
struct i915_vma *vma;
u32 ggtt_offset;
void *vaddr;
int ret;

GEM_BUG_ON(!hwconfig->size);

ret = intel_guc_allocate_and_map_vma(guc, hwconfig->size, &vma, &vaddr);
if (ret)
return ret;

ggtt_offset = intel_guc_ggtt_offset(guc, vma);

ret = __guc_action_get_hwconfig(guc, ggtt_offset, hwconfig->size);
if (ret >= 0)
memcpy(hwconfig->ptr, vaddr, hwconfig->size);

i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP);

return ret;
}

static bool has_table(struct drm_i915_private *i915)
{
if (IS_ALDERLAKE_P(i915))
return true;

return false;
}

/**
* intel_guc_hwconfig_init - Initialize the HWConfig
*
* Retrieve the HWConfig table from the GuC and save it locally.
* It can then be queried on demand by other users later on.
*/
static int guc_hwconfig_init(struct intel_gt *gt)
{
struct intel_hwconfig *hwconfig = &gt->info.hwconfig;
struct intel_guc *guc = &gt->uc.guc;
int ret;

if (!has_table(gt->i915))
return 0;

ret = guc_hwconfig_discover_size(guc, hwconfig);
if (ret)
return ret;

hwconfig->ptr = kmalloc(hwconfig->size, GFP_KERNEL);
if (!hwconfig->ptr) {
hwconfig->size = 0;
return -ENOMEM;
}

ret = guc_hwconfig_fill_buffer(guc, hwconfig);
if (ret < 0) {
intel_gt_fini_hwconfig(gt);
return ret;
}

return 0;
}

/**
* intel_gt_init_hwconfig - Initialize the HWConfig if available
*
* Retrieve the HWConfig table if available on the current platform.
*/
int intel_gt_init_hwconfig(struct intel_gt *gt)
{
if (!intel_uc_uses_guc(&gt->uc))
return 0;

return guc_hwconfig_init(gt);
}

/**
* intel_gt_fini_hwconfig - Finalize the HWConfig
*
* Free up the memory allocation holding the table.
*/
void intel_gt_fini_hwconfig(struct intel_gt *gt)
{
struct intel_hwconfig *hwconfig = &gt->info.hwconfig;

kfree(hwconfig->ptr);
hwconfig->size = 0;
hwconfig->ptr = NULL;
}

0 comments on commit 8781f05

Please sign in to comment.