1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
// SPDX-License-Identifier: MIT
/*
* Copyright © 2023-2024 Intel Corporation
*/
#include "abi/guc_actions_sriov_abi.h"
#include "abi/guc_messages_abi.h"
#include "xe_gt_sriov_pf_config.h"
#include "xe_gt_sriov_pf_helpers.h"
#include "xe_gt_sriov_pf_monitor.h"
#include "xe_gt_sriov_printk.h"
#include "xe_guc_klv_helpers.h"
#include "xe_guc_klv_thresholds_set.h"
/**
* xe_gt_sriov_pf_monitor_flr - Cleanup VF data after VF FLR.
* @gt: the &xe_gt
* @vfid: the VF identifier
*
* On FLR this function will reset all event data related to the VF.
* This function is for PF only.
*/
void xe_gt_sriov_pf_monitor_flr(struct xe_gt *gt, u32 vfid)
{
int e;
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
xe_gt_sriov_pf_assert_vfid(gt, vfid);
for (e = 0; e < XE_GUC_KLV_NUM_THRESHOLDS; e++)
gt->sriov.pf.vfs[vfid].monitor.guc.events[e] = 0;
}
static void pf_update_event_counter(struct xe_gt *gt, u32 vfid,
enum xe_guc_klv_threshold_index e)
{
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
xe_gt_assert(gt, e < XE_GUC_KLV_NUM_THRESHOLDS);
gt->sriov.pf.vfs[vfid].monitor.guc.events[e]++;
}
static int pf_handle_vf_threshold_event(struct xe_gt *gt, u32 vfid, u32 threshold)
{
char origin[8];
int e;
e = xe_guc_klv_threshold_key_to_index(threshold);
xe_sriov_function_name(vfid, origin, sizeof(origin));
/* was there a new KEY added that we missed? */
if (unlikely(e < 0)) {
xe_gt_sriov_notice(gt, "unknown threshold key %#x reported for %s\n",
threshold, origin);
return -ENOTCONN;
}
xe_gt_sriov_dbg(gt, "%s exceeded threshold %u %s\n",
origin, xe_gt_sriov_pf_config_get_threshold(gt, vfid, e),
xe_guc_klv_key_to_string(threshold));
pf_update_event_counter(gt, vfid, e);
return 0;
}
/**
* xe_gt_sriov_pf_monitor_process_guc2pf - Handle adverse event notification from the GuC.
* @gt: the &xe_gt
* @msg: G2H event message
* @len: length of the message
*
* This function is intended for PF only.
*
* Return: 0 on success or a negative error code on failure.
*/
int xe_gt_sriov_pf_monitor_process_guc2pf(struct xe_gt *gt, const u32 *msg, u32 len)
{
struct xe_device *xe = gt_to_xe(gt);
u32 vfid;
u32 threshold;
xe_gt_assert(gt, len >= GUC_HXG_MSG_MIN_LEN);
xe_gt_assert(gt, FIELD_GET(GUC_HXG_MSG_0_ORIGIN, msg[0]) == GUC_HXG_ORIGIN_GUC);
xe_gt_assert(gt, FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]) == GUC_HXG_TYPE_EVENT);
xe_gt_assert(gt, FIELD_GET(GUC_HXG_EVENT_MSG_0_ACTION, msg[0]) ==
GUC_ACTION_GUC2PF_ADVERSE_EVENT);
if (unlikely(!IS_SRIOV_PF(xe)))
return -EPROTO;
if (unlikely(FIELD_GET(GUC2PF_ADVERSE_EVENT_EVENT_MSG_0_MBZ, msg[0])))
return -EPFNOSUPPORT;
if (unlikely(len < GUC2PF_ADVERSE_EVENT_EVENT_MSG_LEN))
return -EPROTO;
vfid = FIELD_GET(GUC2PF_ADVERSE_EVENT_EVENT_MSG_1_VFID, msg[1]);
threshold = FIELD_GET(GUC2PF_ADVERSE_EVENT_EVENT_MSG_2_THRESHOLD, msg[2]);
if (unlikely(vfid > xe_gt_sriov_pf_get_totalvfs(gt)))
return -EINVAL;
return pf_handle_vf_threshold_event(gt, vfid, threshold);
}
/**
* xe_gt_sriov_pf_monitor_print_events - Print adverse events counters.
* @gt: the &xe_gt to print events from
* @p: the &drm_printer
*
* Print adverse events counters for all VFs.
* VFs with no events are not printed.
*
* This function can only be called on PF.
*/
void xe_gt_sriov_pf_monitor_print_events(struct xe_gt *gt, struct drm_printer *p)
{
unsigned int n, total_vfs = xe_gt_sriov_pf_get_totalvfs(gt);
const struct xe_gt_sriov_monitor *data;
int e;
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
for (n = 1; n <= total_vfs; n++) {
data = >->sriov.pf.vfs[n].monitor;
for (e = 0; e < XE_GUC_KLV_NUM_THRESHOLDS; e++)
if (data->guc.events[e])
break;
/* skip empty unless in debug mode */
if (e >= XE_GUC_KLV_NUM_THRESHOLDS &&
!IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV))
continue;
#define __format(...) "%s:%u "
#define __value(TAG, NAME, ...) , #NAME, data->guc.events[MAKE_XE_GUC_KLV_THRESHOLD_INDEX(TAG)]
drm_printf(p, "VF%u:\t" MAKE_XE_GUC_KLV_THRESHOLDS_SET(__format) "\n",
n MAKE_XE_GUC_KLV_THRESHOLDS_SET(__value));
#undef __format
#undef __value
}
}
|