Commit 27aec396 authored by Daniel Vetter's avatar Daniel Vetter

Merge tag 'drm-xe-next-2024-07-02' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-next

Driver Changes:
- Fix in migration code (Auld)
- Simplification in HWMon related code (Karthik)
- Fix in forcewake logic (Nirmoy)
- Fix engine utilization information (umesh)
- Clean up on MOCS related code (Roper)
- Fix on multicast register (Roper)
- Fix TLB invalidation timeout (Nirmoy)
- More SRIOV preparation (Michal)
- Fix out-of-bounds array access (Lucas)
- Fixes around some mutex utilization (Ashutosh, Vinay)
- Expand LNL workaround to BMG (Vinay)
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/ZoROvquFrTFhk3Pb@intel.com
parents fb625bf6 aaa08078
......@@ -31,9 +31,9 @@ static int live_mocs_init(struct live_mocs *arg, struct xe_gt *gt)
kunit_info(test, "gt %d", gt->info.id);
kunit_info(test, "gt type %d", gt->info.type);
kunit_info(test, "table size %d", arg->table.size);
kunit_info(test, "table size %d", arg->table.table_size);
kunit_info(test, "table uc_index %d", arg->table.uc_index);
kunit_info(test, "table n_entries %d", arg->table.n_entries);
kunit_info(test, "table num_mocs_regs %d", arg->table.num_mocs_regs);
return flags;
}
......@@ -50,7 +50,7 @@ static void read_l3cc_table(struct xe_gt *gt,
ret = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
KUNIT_ASSERT_EQ_MSG(test, ret, 0, "Forcewake Failed.\n");
for (i = 0; i < info->n_entries; i++) {
for (i = 0; i < info->num_mocs_regs; i++) {
if (!(i & 1)) {
if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_LNCFCMOCS(i >> 1));
......@@ -90,7 +90,7 @@ static void read_mocs_table(struct xe_gt *gt,
ret = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
KUNIT_ASSERT_EQ_MSG(test, ret, 0, "Forcewake Failed.\n");
for (i = 0; i < info->n_entries; i++) {
for (i = 0; i < info->num_mocs_regs; i++) {
if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i));
else
......
......@@ -260,13 +260,20 @@ static void show_run_ticks(struct drm_printer *p, struct drm_file *file)
/* Get the total GPU cycles */
for_each_gt(gt, xe, gt_id) {
enum xe_force_wake_domains fw;
hwe = xe_gt_any_hw_engine(gt);
if (!hwe)
continue;
xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
fw = xe_hw_engine_to_fw_domain(hwe);
if (xe_force_wake_get(gt_to_fw(gt), fw)) {
hwe = NULL;
break;
}
gpu_timestamp = xe_hw_engine_read_timestamp(hwe);
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), fw));
break;
}
......
......@@ -74,6 +74,9 @@ static unsigned int probe_gsm_size(struct pci_dev *pdev)
static void ggtt_update_access_counter(struct xe_ggtt *ggtt)
{
struct xe_gt *gt = XE_WA(ggtt->tile->primary_gt, 22019338487) ? ggtt->tile->primary_gt :
ggtt->tile->media_gt;
u32 max_gtt_writes = XE_WA(ggtt->tile->primary_gt, 22019338487) ? 1100 : 63;
/*
* Wa_22019338487: GMD_ID is a RO register, a dummy write forces gunit
* to wait for completion of prior GTT writes before letting this through.
......@@ -81,8 +84,8 @@ static void ggtt_update_access_counter(struct xe_ggtt *ggtt)
*/
lockdep_assert_held(&ggtt->lock);
if ((++ggtt->access_count % 63) == 0) {
xe_mmio_write32(ggtt->tile->media_gt, GMD_ID, 0x0);
if ((++ggtt->access_count % max_gtt_writes) == 0) {
xe_mmio_write32(gt, GMD_ID, 0x0);
ggtt->access_count = 0;
}
}
......@@ -218,7 +221,9 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt)
ggtt->size = GUC_GGTT_TOP;
if (GRAPHICS_VERx100(xe) >= 1270)
ggtt->pt_ops = ggtt->tile->media_gt && XE_WA(ggtt->tile->media_gt, 22019338487) ?
ggtt->pt_ops = (ggtt->tile->media_gt &&
XE_WA(ggtt->tile->media_gt, 22019338487)) ||
XE_WA(ggtt->tile->primary_gt, 22019338487) ?
&xelpg_pt_wa_ops : &xelpg_pt_ops;
else
ggtt->pt_ops = &xelp_pt_ops;
......
......@@ -683,6 +683,9 @@ static int do_gt_restart(struct xe_gt *gt)
/* Restore GT freq to expected values */
xe_gt_sanitize_freq(gt);
if (IS_SRIOV_PF(gt_to_xe(gt)))
xe_gt_sriov_pf_restart(gt);
return 0;
}
......@@ -818,8 +821,7 @@ int xe_gt_sanitize_freq(struct xe_gt *gt)
int ret = 0;
if ((!xe_uc_fw_is_available(&gt->uc.gsc.fw) ||
xe_uc_fw_is_loaded(&gt->uc.gsc.fw)) &&
XE_WA(gt, 22019338487))
xe_uc_fw_is_loaded(&gt->uc.gsc.fw)) && XE_WA(gt, 22019338487))
ret = xe_guc_pc_restore_stashed_freq(&gt->uc.guc.pc);
return ret;
......
......@@ -342,7 +342,7 @@ static void init_steering_oaddrm(struct xe_gt *gt)
else
gt->steering[OADDRM].group_target = 1;
gt->steering[DSS].instance_target = 0; /* unused */
gt->steering[OADDRM].instance_target = 0; /* unused */
}
static void init_steering_sqidi_psmi(struct xe_gt *gt)
......@@ -357,8 +357,8 @@ static void init_steering_sqidi_psmi(struct xe_gt *gt)
static void init_steering_inst0(struct xe_gt *gt)
{
gt->steering[DSS].group_target = 0; /* unused */
gt->steering[DSS].instance_target = 0; /* unused */
gt->steering[INSTANCE0].group_target = 0; /* unused */
gt->steering[INSTANCE0].instance_target = 0; /* unused */
}
static const struct {
......
......@@ -8,6 +8,7 @@
#include "regs/xe_sriov_regs.h"
#include "xe_gt_sriov_pf.h"
#include "xe_gt_sriov_pf_config.h"
#include "xe_gt_sriov_pf_helpers.h"
#include "xe_gt_sriov_pf_service.h"
#include "xe_mmio.h"
......@@ -82,3 +83,14 @@ void xe_gt_sriov_pf_init_hw(struct xe_gt *gt)
xe_gt_sriov_pf_service_update(gt);
}
/**
* xe_gt_sriov_pf_restart - Restart SR-IOV support after a GT reset.
* @gt: the &xe_gt
*
* This function can only be called on PF.
*/
void xe_gt_sriov_pf_restart(struct xe_gt *gt)
{
xe_gt_sriov_pf_config_restart(gt);
}
......@@ -11,6 +11,7 @@ struct xe_gt;
#ifdef CONFIG_PCI_IOV
int xe_gt_sriov_pf_init_early(struct xe_gt *gt);
void xe_gt_sriov_pf_init_hw(struct xe_gt *gt);
void xe_gt_sriov_pf_restart(struct xe_gt *gt);
#else
static inline int xe_gt_sriov_pf_init_early(struct xe_gt *gt)
{
......@@ -20,6 +21,10 @@ static inline int xe_gt_sriov_pf_init_early(struct xe_gt *gt)
static inline void xe_gt_sriov_pf_init_hw(struct xe_gt *gt)
{
}
static inline void xe_gt_sriov_pf_restart(struct xe_gt *gt)
{
}
#endif
#endif
......@@ -1922,6 +1922,84 @@ int xe_gt_sriov_pf_config_push(struct xe_gt *gt, unsigned int vfid, bool refresh
return err;
}
static int pf_validate_vf_config(struct xe_gt *gt, unsigned int vfid)
{
struct xe_gt *primary_gt = gt_to_tile(gt)->primary_gt;
struct xe_device *xe = gt_to_xe(gt);
bool valid_ggtt, valid_ctxs, valid_dbs;
bool valid_any, valid_all;
valid_ggtt = pf_get_vf_config_ggtt(primary_gt, vfid);
valid_ctxs = pf_get_vf_config_ctxs(gt, vfid);
valid_dbs = pf_get_vf_config_dbs(gt, vfid);
/* note that GuC doorbells are optional */
valid_any = valid_ggtt || valid_ctxs || valid_dbs;
valid_all = valid_ggtt && valid_ctxs;
if (IS_DGFX(xe)) {
bool valid_lmem = pf_get_vf_config_ggtt(primary_gt, vfid);
valid_any = valid_any || valid_lmem;
valid_all = valid_all && valid_lmem;
}
return valid_all ? 1 : valid_any ? -ENOKEY : -ENODATA;
}
/**
* xe_gt_sriov_pf_config_is_empty - Check VF's configuration.
* @gt: the &xe_gt
* @vfid: the VF identifier (can't be PF)
*
* This function can only be called on PF.
*
* Return: true if VF mandatory configuration (GGTT, LMEM, ...) is empty.
*/
bool xe_gt_sriov_pf_config_is_empty(struct xe_gt *gt, unsigned int vfid)
{
bool empty;
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
xe_gt_assert(gt, vfid);
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
empty = pf_validate_vf_config(gt, vfid) == -ENODATA;
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
return empty;
}
/**
* xe_gt_sriov_pf_config_restart - Restart SR-IOV configurations after a GT reset.
* @gt: the &xe_gt
*
* Any prior configurations pushed to GuC are lost when the GT is reset.
* Push again all non-empty VF configurations to the GuC.
*
* This function can only be called on PF.
*/
void xe_gt_sriov_pf_config_restart(struct xe_gt *gt)
{
unsigned int n, total_vfs = xe_sriov_pf_get_totalvfs(gt_to_xe(gt));
unsigned int fail = 0, skip = 0;
for (n = 1; n <= total_vfs; n++) {
if (xe_gt_sriov_pf_config_is_empty(gt, n))
skip++;
else if (xe_gt_sriov_pf_config_push(gt, n, false))
fail++;
}
if (fail)
xe_gt_sriov_notice(gt, "Failed to push %u of %u VF%s configurations\n",
fail, total_vfs - skip, str_plural(total_vfs));
if (fail != total_vfs)
xe_gt_sriov_dbg(gt, "pushed %u skip %u of %u VF%s configurations\n",
total_vfs - skip - fail, skip, total_vfs, str_plural(total_vfs));
}
/**
* xe_gt_sriov_pf_config_print_ggtt - Print GGTT configurations.
* @gt: the &xe_gt
......
......@@ -53,6 +53,10 @@ int xe_gt_sriov_pf_config_set_fair(struct xe_gt *gt, unsigned int vfid, unsigned
int xe_gt_sriov_pf_config_release(struct xe_gt *gt, unsigned int vfid, bool force);
int xe_gt_sriov_pf_config_push(struct xe_gt *gt, unsigned int vfid, bool refresh);
bool xe_gt_sriov_pf_config_is_empty(struct xe_gt *gt, unsigned int vfid);
void xe_gt_sriov_pf_config_restart(struct xe_gt *gt);
int xe_gt_sriov_pf_config_print_ggtt(struct xe_gt *gt, struct drm_printer *p);
int xe_gt_sriov_pf_config_print_ctxs(struct xe_gt *gt, struct drm_printer *p);
int xe_gt_sriov_pf_config_print_dbs(struct xe_gt *gt, struct drm_printer *p);
......
......@@ -17,7 +17,22 @@
#include "xe_trace.h"
#include "regs/xe_guc_regs.h"
#define TLB_TIMEOUT (HZ / 4)
/*
* TLB inval depends on pending commands in the CT queue and then the real
* invalidation time. Double up the time to process full CT queue
* just to be on the safe side.
*/
static long tlb_timeout_jiffies(struct xe_gt *gt)
{
/* this reflects what HW/GuC needs to process TLB inv request */
const long hw_tlb_timeout = HZ / 4;
/* this estimates actual delay caused by the CTB transport */
long delay = xe_guc_ct_queue_proc_time_jiffies(&gt->uc.guc.ct);
return hw_tlb_timeout + 2 * delay;
}
static void xe_gt_tlb_fence_timeout(struct work_struct *work)
{
......@@ -32,7 +47,7 @@ static void xe_gt_tlb_fence_timeout(struct work_struct *work)
s64 since_inval_ms = ktime_ms_delta(ktime_get(),
fence->invalidation_time);
if (msecs_to_jiffies(since_inval_ms) < TLB_TIMEOUT)
if (msecs_to_jiffies(since_inval_ms) < tlb_timeout_jiffies(gt))
break;
trace_xe_gt_tlb_invalidation_fence_timeout(xe, fence);
......@@ -47,7 +62,7 @@ static void xe_gt_tlb_fence_timeout(struct work_struct *work)
if (!list_empty(&gt->tlb_invalidation.pending_fences))
queue_delayed_work(system_wq,
&gt->tlb_invalidation.fence_tdr,
TLB_TIMEOUT);
tlb_timeout_jiffies(gt));
spin_unlock_irq(&gt->tlb_invalidation.pending_lock);
}
......@@ -183,7 +198,7 @@ static int send_tlb_invalidation(struct xe_guc *guc,
if (list_is_singular(&gt->tlb_invalidation.pending_fences))
queue_delayed_work(system_wq,
&gt->tlb_invalidation.fence_tdr,
TLB_TIMEOUT);
tlb_timeout_jiffies(gt));
}
spin_unlock_irq(&gt->tlb_invalidation.pending_lock);
} else if (ret < 0 && fence) {
......@@ -390,8 +405,7 @@ int xe_gt_tlb_invalidation_vma(struct xe_gt *gt,
* @gt: graphics tile
* @seqno: seqno to wait which was returned from xe_gt_tlb_invalidation
*
* Wait for 200ms for a TLB invalidation to complete, in practice we always
* should receive the TLB invalidation within 200ms.
* Wait for tlb_timeout_jiffies() for a TLB invalidation to complete.
*
* Return: 0 on success, -ETIME on TLB invalidation timeout
*/
......@@ -410,7 +424,7 @@ int xe_gt_tlb_invalidation_wait(struct xe_gt *gt, int seqno)
*/
ret = wait_event_timeout(guc->ct.wq,
tlb_invalidation_seqno_past(gt, seqno),
TLB_TIMEOUT);
tlb_timeout_jiffies(gt));
if (!ret) {
struct drm_printer p = xe_gt_err_printer(gt);
......@@ -486,7 +500,7 @@ int xe_guc_tlb_invalidation_done_handler(struct xe_guc *guc, u32 *msg, u32 len)
if (!list_empty(&gt->tlb_invalidation.pending_fences))
mod_delayed_work(system_wq,
&gt->tlb_invalidation.fence_tdr,
TLB_TIMEOUT);
tlb_timeout_jiffies(gt));
else
cancel_delayed_work(&gt->tlb_invalidation.fence_tdr);
......
......@@ -112,6 +112,23 @@ ct_to_xe(struct xe_guc_ct *ct)
#define CTB_G2H_BUFFER_SIZE (4 * CTB_H2G_BUFFER_SIZE)
#define G2H_ROOM_BUFFER_SIZE (CTB_G2H_BUFFER_SIZE / 4)
/**
* xe_guc_ct_queue_proc_time_jiffies - Return maximum time to process a full
* CT command queue
* @ct: the &xe_guc_ct. Unused at this moment but will be used in the future.
*
* Observation is that a 4KiB buffer full of commands takes a little over a
* second to process. Use that to calculate maximum time to process a full CT
* command queue.
*
* Return: Maximum time to process a full CT queue in jiffies.
*/
long xe_guc_ct_queue_proc_time_jiffies(struct xe_guc_ct *ct)
{
BUILD_BUG_ON(!IS_ALIGNED(CTB_H2G_BUFFER_SIZE, SZ_4));
return (CTB_H2G_BUFFER_SIZE / SZ_4K) * HZ;
}
static size_t guc_ct_size(void)
{
return 2 * CTB_DESC_SIZE + CTB_H2G_BUFFER_SIZE +
......
......@@ -64,4 +64,6 @@ xe_guc_ct_send_block_no_fail(struct xe_guc_ct *ct, const u32 *action, u32 len)
return xe_guc_ct_send_recv_no_fail(ct, action, len, NULL);
}
long xe_guc_ct_queue_proc_time_jiffies(struct xe_guc_ct *ct);
#endif
......@@ -26,6 +26,7 @@
#include "xe_mmio.h"
#include "xe_pcode.h"
#include "xe_pm.h"
#include "xe_sriov.h"
#include "xe_wa.h"
#define MCHBAR_MIRROR_BASE_SNB 0x140000
......@@ -45,6 +46,7 @@
#define GT_FREQUENCY_SCALER 3
#define LNL_MERT_FREQ_CAP 800
#define BMG_MERT_FREQ_CAP 2133
/**
* DOC: GuC Power Conservation (PC)
......@@ -703,10 +705,14 @@ static u32 pc_max_freq_cap(struct xe_guc_pc *pc)
{
struct xe_gt *gt = pc_to_gt(pc);
if (XE_WA(gt, 22019338487))
if (XE_WA(gt, 22019338487)) {
if (xe_gt_is_media_type(gt))
return min(LNL_MERT_FREQ_CAP, pc->rp0_freq);
else
return min(BMG_MERT_FREQ_CAP, pc->rp0_freq);
} else {
return pc->rp0_freq;
}
}
/**
......@@ -825,6 +831,9 @@ int xe_guc_pc_restore_stashed_freq(struct xe_guc_pc *pc)
{
int ret = 0;
if (IS_SRIOV_VF(pc_to_xe(pc)) || pc_to_xe(pc)->info.skip_guc_pc)
return 0;
mutex_lock(&pc->freq_lock);
ret = pc_set_max_freq(pc, pc->stashed_max_freq);
if (!ret)
......
......@@ -1130,3 +1130,8 @@ u64 xe_hw_engine_read_timestamp(struct xe_hw_engine *hwe)
{
return xe_mmio_read64_2x32(hwe->gt, RING_TIMESTAMP(hwe->mmio_base));
}
enum xe_force_wake_domains xe_hw_engine_to_fw_domain(struct xe_hw_engine *hwe)
{
return engine_infos[hwe->engine_id].domain;
}
......@@ -69,5 +69,6 @@ static inline bool xe_hw_engine_is_valid(struct xe_hw_engine *hwe)
const char *xe_hw_engine_class_to_str(enum xe_engine_class class);
u64 xe_hw_engine_read_timestamp(struct xe_hw_engine *hwe);
enum xe_force_wake_domains xe_hw_engine_to_fw_domain(struct xe_hw_engine *hwe);
#endif
......@@ -137,34 +137,6 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg
return XE_REG(0);
}
static void xe_hwmon_process_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg hwmon_reg,
enum xe_hwmon_reg_operation operation, u64 *value,
u32 clr, u32 set, int channel)
{
struct xe_reg reg;
reg = xe_hwmon_get_reg(hwmon, hwmon_reg, channel);
if (!xe_reg_is_valid(reg))
return;
switch (operation) {
case REG_READ32:
*value = xe_mmio_read32(hwmon->gt, reg);
break;
case REG_RMW32:
*value = xe_mmio_rmw32(hwmon->gt, reg, clr, set);
break;
case REG_READ64:
*value = xe_mmio_read64_2x32(hwmon->gt, reg);
break;
default:
drm_warn(&gt_to_xe(hwmon->gt)->drm, "Invalid xe hwmon reg operation: %d\n",
operation);
break;
}
}
#define PL1_DISABLE 0
/*
......@@ -176,10 +148,25 @@ static void xe_hwmon_process_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg hwmon
static void xe_hwmon_power_max_read(struct xe_hwmon *hwmon, int channel, long *value)
{
u64 reg_val, min, max;
struct xe_device *xe = gt_to_xe(hwmon->gt);
struct xe_reg rapl_limit, pkg_power_sku;
rapl_limit = xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel);
pkg_power_sku = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel);
/*
* Valid check of REG_PKG_RAPL_LIMIT is already done in xe_hwmon_power_is_visible.
* So not checking it again here.
*/
if (!xe_reg_is_valid(pkg_power_sku)) {
drm_warn(&xe->drm, "pkg_power_sku invalid\n");
*value = 0;
return;
}
mutex_lock(&hwmon->hwmon_lock);
xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, REG_READ32, &reg_val, 0, 0, channel);
reg_val = xe_mmio_read32(hwmon->gt, rapl_limit);
/* Check if PL1 limit is disabled */
if (!(reg_val & PKG_PWR_LIM_1_EN)) {
*value = PL1_DISABLE;
......@@ -189,7 +176,7 @@ static void xe_hwmon_power_max_read(struct xe_hwmon *hwmon, int channel, long *v
reg_val = REG_FIELD_GET(PKG_PWR_LIM_1, reg_val);
*value = mul_u64_u32_shr(reg_val, SF_POWER, hwmon->scl_shift_power);
xe_hwmon_process_reg(hwmon, REG_PKG_POWER_SKU, REG_READ64, &reg_val, 0, 0, channel);
reg_val = xe_mmio_read64_2x32(hwmon->gt, pkg_power_sku);
min = REG_FIELD_GET(PKG_MIN_PWR, reg_val);
min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power);
max = REG_FIELD_GET(PKG_MAX_PWR, reg_val);
......@@ -205,16 +192,16 @@ static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, int channel, long va
{
int ret = 0;
u64 reg_val;
struct xe_reg rapl_limit;
rapl_limit = xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel);
mutex_lock(&hwmon->hwmon_lock);
/* Disable PL1 limit and verify, as limit cannot be disabled on all platforms */
if (value == PL1_DISABLE) {
xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, REG_RMW32, &reg_val,
PKG_PWR_LIM_1_EN, 0, channel);
xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, REG_READ32, &reg_val,
PKG_PWR_LIM_1_EN, 0, channel);
reg_val = xe_mmio_rmw32(hwmon->gt, rapl_limit, PKG_PWR_LIM_1_EN, 0);
reg_val = xe_mmio_read32(hwmon->gt, rapl_limit);
if (reg_val & PKG_PWR_LIM_1_EN) {
ret = -EOPNOTSUPP;
goto unlock;
......@@ -224,9 +211,8 @@ static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, int channel, long va
/* Computation in 64-bits to avoid overflow. Round to nearest. */
reg_val = DIV_ROUND_CLOSEST_ULL((u64)value << hwmon->scl_shift_power, SF_POWER);
reg_val = PKG_PWR_LIM_1_EN | REG_FIELD_PREP(PKG_PWR_LIM_1, reg_val);
reg_val = xe_mmio_rmw32(hwmon->gt, rapl_limit, PKG_PWR_LIM_1_EN | PKG_PWR_LIM_1, reg_val);
xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, REG_RMW32, &reg_val,
PKG_PWR_LIM_1_EN | PKG_PWR_LIM_1, reg_val, channel);
unlock:
mutex_unlock(&hwmon->hwmon_lock);
return ret;
......@@ -234,9 +220,15 @@ static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, int channel, long va
static void xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, int channel, long *value)
{
struct xe_reg reg = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel);
u64 reg_val;
xe_hwmon_process_reg(hwmon, REG_PKG_POWER_SKU, REG_READ32, &reg_val, 0, 0, channel);
/*
* This sysfs file won't be visible if REG_PKG_POWER_SKU is invalid, so valid check
* for this register can be skipped.
* See xe_hwmon_power_is_visible.
*/
reg_val = xe_mmio_read32(hwmon->gt, reg);
reg_val = REG_FIELD_GET(PKG_TDP, reg_val);
*value = mul_u64_u32_shr(reg_val, SF_POWER, hwmon->scl_shift_power);
}
......@@ -267,8 +259,8 @@ xe_hwmon_energy_get(struct xe_hwmon *hwmon, int channel, long *energy)
struct xe_hwmon_energy_info *ei = &hwmon->ei[channel];
u64 reg_val;
xe_hwmon_process_reg(hwmon, REG_PKG_ENERGY_STATUS, REG_READ32,
&reg_val, 0, 0, channel);
reg_val = xe_mmio_read32(hwmon->gt, xe_hwmon_get_reg(hwmon, REG_PKG_ENERGY_STATUS,
channel));
if (reg_val >= ei->reg_val_prev)
ei->accum_energy += reg_val - ei->reg_val_prev;
......@@ -294,8 +286,7 @@ xe_hwmon_power_max_interval_show(struct device *dev, struct device_attribute *at
mutex_lock(&hwmon->hwmon_lock);
xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT,
REG_READ32, &r, 0, 0, sensor_index);
r = xe_mmio_read32(hwmon->gt, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, sensor_index));
mutex_unlock(&hwmon->hwmon_lock);
......@@ -383,8 +374,8 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a
mutex_lock(&hwmon->hwmon_lock);
xe_hwmon_process_reg(hwmon, REG_PKG_RAPL_LIMIT, REG_RMW32, (u64 *)&r,
PKG_PWR_LIM_1_TIME, rxy, sensor_index);
r = xe_mmio_rmw32(hwmon->gt, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, sensor_index),
PKG_PWR_LIM_1_TIME, rxy);
mutex_unlock(&hwmon->hwmon_lock);
......@@ -499,8 +490,7 @@ static void xe_hwmon_get_voltage(struct xe_hwmon *hwmon, int channel, long *valu
{
u64 reg_val;
xe_hwmon_process_reg(hwmon, REG_GT_PERF_STATUS,
REG_READ32, &reg_val, 0, 0, channel);
reg_val = xe_mmio_read32(hwmon->gt, xe_hwmon_get_reg(hwmon, REG_GT_PERF_STATUS, channel));
/* HW register value in units of 2.5 millivolt */
*value = DIV_ROUND_CLOSEST(REG_FIELD_GET(VOLTAGE_MASK, reg_val) * 2500, SF_VOLTAGE);
}
......@@ -784,14 +774,15 @@ xe_hwmon_get_preregistration_info(struct xe_device *xe)
long energy;
u64 val_sku_unit = 0;
int channel;
struct xe_reg pkg_power_sku_unit;
/*
* The contents of register PKG_POWER_SKU_UNIT do not change,
* so read it once and store the shift values.
*/
if (xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU_UNIT, 0))) {
xe_hwmon_process_reg(hwmon, REG_PKG_POWER_SKU_UNIT,
REG_READ32, &val_sku_unit, 0, 0, 0);
pkg_power_sku_unit = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU_UNIT, 0);
if (xe_reg_is_valid(pkg_power_sku_unit)) {
val_sku_unit = xe_mmio_read32(hwmon->gt, pkg_power_sku_unit);
hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit);
hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit);
hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit);
......
......@@ -1358,7 +1358,7 @@ xe_migrate_update_pgtables(struct xe_migrate *m,
GFP_KERNEL, true, 0);
if (IS_ERR(sa_bo)) {
err = PTR_ERR(sa_bo);
goto err;
goto err_bb;
}
ppgtt_ofs = NUM_KERNEL_PDE +
......@@ -1406,7 +1406,7 @@ xe_migrate_update_pgtables(struct xe_migrate *m,
update_idx);
if (IS_ERR(job)) {
err = PTR_ERR(job);
goto err_bb;
goto err_sa;
}
/* Wait on BO move */
......@@ -1458,10 +1458,10 @@ xe_migrate_update_pgtables(struct xe_migrate *m,
err_job:
xe_sched_job_put(job);
err_sa:
drm_suballoc_free(sa_bo, NULL);
err_bb:
xe_bb_free(bb, NULL);
err:
drm_suballoc_free(sa_bo, NULL);
return ERR_PTR(err);
}
......
......@@ -47,8 +47,16 @@ struct xe_mocs_ops {
};
struct xe_mocs_info {
unsigned int size;
unsigned int n_entries;
/*
* Size of the spec's suggested MOCS programming table. The list of
* table entries from the spec can potentially be smaller than the
* number of hardware registers used to program the MOCS table; in such
* cases the registers for the remaining indices will be programmed to
* match unused_entries_index.
*/
unsigned int table_size;
/* Number of MOCS entries supported by the hardware */
unsigned int num_mocs_regs;
const struct xe_mocs_entry *table;
const struct xe_mocs_ops *ops;
u8 uc_index;
......@@ -266,7 +274,7 @@ static void xelp_lncf_dump(struct xe_mocs_info *info, struct xe_gt *gt, struct d
drm_printf(p, "LNCFCMOCS[idx] = [ESC, SCC, L3CC] (value)\n\n");
for (i = 0, j = 0; i < (info->n_entries + 1) / 2; i++, j++) {
for (i = 0, j = 0; i < (info->num_mocs_regs + 1) / 2; i++, j++) {
if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_LNCFCMOCS(i));
else
......@@ -298,7 +306,7 @@ static void xelp_mocs_dump(struct xe_mocs_info *info, unsigned int flags,
drm_printf(p, "Global mocs table configuration:\n");
drm_printf(p, "GLOB_MOCS[idx] = [LeCC, TC, LRUM, AOM, RSC, SCC, PFM, SCF, CoS, SSE] (value)\n\n");
for (i = 0; i < info->n_entries; i++) {
for (i = 0; i < info->num_mocs_regs; i++) {
if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i));
else
......@@ -371,7 +379,7 @@ static void xehp_lncf_dump(struct xe_mocs_info *info, unsigned int flags,
drm_printf(p, "LNCFCMOCS[idx] = [UCL3LOOKUP, GLBGO, L3CC] (value)\n\n");
for (i = 0, j = 0; i < (info->n_entries + 1) / 2; i++, j++) {
for (i = 0, j = 0; i < (info->num_mocs_regs + 1) / 2; i++, j++) {
if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_LNCFCMOCS(i));
else
......@@ -416,7 +424,7 @@ static void pvc_mocs_dump(struct xe_mocs_info *info, unsigned int flags, struct
drm_printf(p, "LNCFCMOCS[idx] = [ L3CC ] (value)\n\n");
for (i = 0, j = 0; i < (info->n_entries + 1) / 2; i++, j++) {
for (i = 0, j = 0; i < (info->num_mocs_regs + 1) / 2; i++, j++) {
if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_LNCFCMOCS(i));
else
......@@ -498,7 +506,7 @@ static void mtl_mocs_dump(struct xe_mocs_info *info, unsigned int flags,
drm_printf(p, "Global mocs table configuration:\n");
drm_printf(p, "GLOB_MOCS[idx] = [IG_PAT, L4_CACHE_POLICY] (value)\n\n");
for (i = 0; i < info->n_entries; i++) {
for (i = 0; i < info->num_mocs_regs; i++) {
if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i));
else
......@@ -541,7 +549,7 @@ static void xe2_mocs_dump(struct xe_mocs_info *info, unsigned int flags,
drm_printf(p, "Global mocs table configuration:\n");
drm_printf(p, "GLOB_MOCS[idx] = [IG_PAT, L3_CLOS, L3_CACHE_POLICY, L4_CACHE_POLICY] (value)\n\n");
for (i = 0; i < info->n_entries; i++) {
for (i = 0; i < info->num_mocs_regs; i++) {
if (regs_are_mcr(gt))
reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i));
else
......@@ -571,48 +579,48 @@ static unsigned int get_mocs_settings(struct xe_device *xe,
case XE_LUNARLAKE:
case XE_BATTLEMAGE:
info->ops = &xe2_mocs_ops;
info->size = ARRAY_SIZE(xe2_mocs_table);
info->table_size = ARRAY_SIZE(xe2_mocs_table);
info->table = xe2_mocs_table;
info->n_entries = XE2_NUM_MOCS_ENTRIES;
info->num_mocs_regs = XE2_NUM_MOCS_ENTRIES;
info->uc_index = 3;
info->wb_index = 4;
info->unused_entries_index = 4;
break;
case XE_PVC:
info->ops = &pvc_mocs_ops;
info->size = ARRAY_SIZE(pvc_mocs_desc);
info->table_size = ARRAY_SIZE(pvc_mocs_desc);
info->table = pvc_mocs_desc;
info->n_entries = PVC_NUM_MOCS_ENTRIES;
info->num_mocs_regs = PVC_NUM_MOCS_ENTRIES;
info->uc_index = 1;
info->wb_index = 2;
info->unused_entries_index = 2;
break;
case XE_METEORLAKE:
info->ops = &mtl_mocs_ops;
info->size = ARRAY_SIZE(mtl_mocs_desc);
info->table_size = ARRAY_SIZE(mtl_mocs_desc);
info->table = mtl_mocs_desc;
info->n_entries = MTL_NUM_MOCS_ENTRIES;
info->num_mocs_regs = MTL_NUM_MOCS_ENTRIES;
info->uc_index = 9;
info->unused_entries_index = 1;
break;
case XE_DG2:
info->ops = &xehp_mocs_ops;
info->size = ARRAY_SIZE(dg2_mocs_desc);
info->table_size = ARRAY_SIZE(dg2_mocs_desc);
info->table = dg2_mocs_desc;
info->uc_index = 1;
/*
* Last entry is RO on hardware, don't bother with what was
* written when checking later
*/
info->n_entries = XELP_NUM_MOCS_ENTRIES - 1;
info->num_mocs_regs = XELP_NUM_MOCS_ENTRIES - 1;
info->unused_entries_index = 3;
break;
case XE_DG1:
info->ops = &xelp_mocs_ops;
info->size = ARRAY_SIZE(dg1_mocs_desc);
info->table_size = ARRAY_SIZE(dg1_mocs_desc);
info->table = dg1_mocs_desc;
info->uc_index = 1;
info->n_entries = XELP_NUM_MOCS_ENTRIES;
info->num_mocs_regs = XELP_NUM_MOCS_ENTRIES;
info->unused_entries_index = 5;
break;
case XE_TIGERLAKE:
......@@ -621,9 +629,9 @@ static unsigned int get_mocs_settings(struct xe_device *xe,
case XE_ALDERLAKE_P:
case XE_ALDERLAKE_N:
info->ops = &xelp_mocs_ops;
info->size = ARRAY_SIZE(gen12_mocs_desc);
info->table_size = ARRAY_SIZE(gen12_mocs_desc);
info->table = gen12_mocs_desc;
info->n_entries = XELP_NUM_MOCS_ENTRIES;
info->num_mocs_regs = XELP_NUM_MOCS_ENTRIES;
info->uc_index = 3;
info->unused_entries_index = 2;
break;
......@@ -642,12 +650,8 @@ static unsigned int get_mocs_settings(struct xe_device *xe,
*/
xe_assert(xe, info->unused_entries_index != 0);
xe_assert(xe, !info->ops || info->ops->dump);
if (XE_WARN_ON(info->size > info->n_entries)) {
info->table = NULL;
return 0;
}
xe_assert(xe, info->ops && info->ops->dump);
xe_assert(xe, info->table_size <= info->num_mocs_regs);
if (!IS_DGFX(xe) || GRAPHICS_VER(xe) >= 20)
flags |= HAS_GLOBAL_MOCS;
......@@ -664,7 +668,7 @@ static unsigned int get_mocs_settings(struct xe_device *xe,
static u32 get_entry_control(const struct xe_mocs_info *info,
unsigned int index)
{
if (index < info->size && info->table[index].used)
if (index < info->table_size && info->table[index].used)
return info->table[index].control_value;
return info->table[info->unused_entries_index].control_value;
}
......@@ -675,12 +679,9 @@ static void __init_mocs_table(struct xe_gt *gt,
unsigned int i;
u32 mocs;
xe_gt_WARN_ONCE(gt, !info->unused_entries_index,
"Unused entries index should have been defined\n");
mocs_dbg(gt, "mocs entries: %d\n", info->n_entries);
mocs_dbg(gt, "mocs entries: %d\n", info->num_mocs_regs);
for (i = 0; i < info->n_entries; i++) {
for (i = 0; i < info->num_mocs_regs; i++) {
mocs = get_entry_control(info, i);
mocs_dbg(gt, "GLOB_MOCS[%d] 0x%x 0x%x\n", i,
......@@ -701,7 +702,7 @@ static void __init_mocs_table(struct xe_gt *gt,
static u16 get_entry_l3cc(const struct xe_mocs_info *info,
unsigned int index)
{
if (index < info->size && info->table[index].used)
if (index < info->table_size && info->table[index].used)
return info->table[index].l3cc_value;
return info->table[info->unused_entries_index].l3cc_value;
}
......@@ -717,9 +718,9 @@ static void init_l3cc_table(struct xe_gt *gt,
unsigned int i;
u32 l3cc;
mocs_dbg(gt, "l3cc entries: %d\n", info->n_entries);
mocs_dbg(gt, "l3cc entries: %d\n", info->num_mocs_regs);
for (i = 0; i < (info->n_entries + 1) / 2; i++) {
for (i = 0; i < (info->num_mocs_regs + 1) / 2; i++) {
l3cc = l3cc_combine(get_entry_l3cc(info, 2 * i),
get_entry_l3cc(info, 2 * i + 1));
......@@ -779,9 +780,6 @@ void xe_mocs_dump(struct xe_gt *gt, struct drm_printer *p)
flags = get_mocs_settings(xe, &table);
if (!table.ops->dump)
return;
xe_pm_runtime_get_noresume(xe);
ret = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
......
......@@ -824,6 +824,8 @@ static void xe_oa_stream_destroy(struct xe_oa_stream *stream)
WRITE_ONCE(u->exclusive_stream, NULL);
mutex_destroy(&stream->stream_lock);
xe_oa_disable_metric_set(stream);
xe_exec_queue_put(stream->k_exec_q);
......
......@@ -748,10 +748,8 @@ static void xe_pci_remove(struct pci_dev *pdev)
if (!xe) /* driver load aborted, nothing to cleanup */
return;
#ifdef CONFIG_PCI_IOV
if (IS_SRIOV_PF(xe))
xe_pci_sriov_configure(pdev, 0);
#endif
xe_device_remove(xe);
xe_pm_runtime_fini(xe);
......@@ -1009,9 +1007,7 @@ static struct pci_driver xe_pci_driver = {
.probe = xe_pci_probe,
.remove = xe_pci_remove,
.shutdown = xe_pci_shutdown,
#ifdef CONFIG_PCI_IOV
.sriov_configure = xe_pci_sriov_configure,
#endif
#ifdef CONFIG_PM_SLEEP
.driver.pm = &xe_pm_ops,
#endif
......
......@@ -13,6 +13,17 @@
#include "xe_sriov_pf_helpers.h"
#include "xe_sriov_printk.h"
static int pf_needs_provisioning(struct xe_gt *gt, unsigned int num_vfs)
{
unsigned int n;
for (n = 1; n <= num_vfs; n++)
if (!xe_gt_sriov_pf_config_is_empty(gt, n))
return false;
return true;
}
static int pf_provision_vfs(struct xe_device *xe, unsigned int num_vfs)
{
struct xe_gt *gt;
......@@ -20,6 +31,8 @@ static int pf_provision_vfs(struct xe_device *xe, unsigned int num_vfs)
int result = 0, err;
for_each_gt(gt, xe, id) {
if (!pf_needs_provisioning(gt, num_vfs))
continue;
err = xe_gt_sriov_pf_config_set_fair(gt, VFID(1), num_vfs);
result = result ?: err;
}
......
......@@ -8,6 +8,13 @@
struct pci_dev;
#ifdef CONFIG_PCI_IOV
int xe_pci_sriov_configure(struct pci_dev *pdev, int num_vfs);
#else
static inline int xe_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
return 0;
}
#endif
#endif
......@@ -121,7 +121,7 @@ static bool rule_matches(const struct xe_device *xe,
* Advance rules until we find XE_RTP_MATCH_OR to check
* if there's another set of conditions to check
*/
while (i < n_rules && rules[++i].match_type != XE_RTP_MATCH_OR)
while (++i < n_rules && rules[i].match_type != XE_RTP_MATCH_OR)
;
if (i >= n_rules)
......
......@@ -28,3 +28,4 @@
GRAPHICS_VERSION(2004)
13011645652 GRAPHICS_VERSION(2004)
22019338487 MEDIA_VERSION(2000)
GRAPHICS_VERSION(2001)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment