@@ -8,6 +8,9 @@
#include "intel_bw.h"
#include "intel_display_types.h"
#include "intel_sideband.h"
+#include "intel_atomic.h"
+#include "intel_pm.h"
+
/* Parameters for Qclk Geyserville (QGV) */
struct intel_qgv_point {
@@ -113,6 +116,26 @@ static int icl_pcode_read_qgv_point_info(struct drm_i915_private *dev_priv,
return 0;
}
+int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv,
+ u32 points_mask)
+{
+ int ret;
+
+ /* bspec says to keep retrying for at least 1 ms */
+ ret = skl_pcode_request(dev_priv, ICL_PCODE_SAGV_DE_MEM_SS_CONFIG,
+ points_mask,
+ GEN11_PCODE_POINTS_RESTRICTED_MASK,
+ GEN11_PCODE_POINTS_RESTRICTED,
+ 1);
+
+ if (ret < 0) {
+ DRM_ERROR("Failed to disable qgv points (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int icl_get_qgv_points(struct drm_i915_private *dev_priv,
struct intel_qgv_info *qi)
{
@@ -236,6 +259,16 @@ static int icl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel
break;
}
+ /*
+ * In case if SAGV is disabled in BIOS, we always get 1
+ * SAGV point, but we can't send PCode commands to restrict it
+ * as it will fail and pointless anyway.
+ */
+ if (qi.num_points == 1)
+ dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED;
+ else
+ dev_priv->sagv_status = I915_SAGV_ENABLED;
+
return 0;
}
@@ -273,34 +306,6 @@ void intel_bw_init_hw(struct drm_i915_private *dev_priv)
icl_get_bw_info(dev_priv, &icl_sa_info);
}
-static unsigned int intel_max_data_rate(struct drm_i915_private *dev_priv,
- int num_planes)
-{
- if (INTEL_GEN(dev_priv) >= 11) {
- /*
- * Any bw group has same amount of QGV points
- */
- const struct intel_bw_info *bi =
- &dev_priv->max_bw[0];
- unsigned int min_bw = UINT_MAX;
- int i;
-
- /*
- * FIXME with SAGV disabled maybe we can assume
- * point 1 will always be used? Seems to match
- * the behaviour observed in the wild.
- */
- for (i = 0; i < bi->num_qgv_points; i++) {
- unsigned int bw = icl_max_bw(dev_priv, num_planes, i);
-
- min_bw = min(bw, min_bw);
- }
- return min_bw;
- } else {
- return UINT_MAX;
- }
-}
-
static unsigned int intel_bw_crtc_num_active_planes(const struct intel_crtc_state *crtc_state)
{
/*
@@ -392,7 +397,11 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
unsigned int data_rate, max_data_rate;
unsigned int num_active_planes;
struct intel_crtc *crtc;
- int i;
+ int i, ret;
+ u32 allowed_points = 0;
+ unsigned int max_bw_point = 0, max_bw = 0;
+ unsigned int num_qgv_points = dev_priv->max_bw[0].num_qgv_points;
+ u32 mask = (1 << num_qgv_points) - 1;
/* FIXME earlier gens need some checks too */
if (INTEL_GEN(dev_priv) < 11)
@@ -436,16 +445,83 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
data_rate = intel_bw_data_rate(dev_priv, bw_state);
num_active_planes = intel_bw_num_active_planes(dev_priv, bw_state);
- max_data_rate = intel_max_data_rate(dev_priv, num_active_planes);
-
data_rate = DIV_ROUND_UP(data_rate, 1000);
- if (data_rate > max_data_rate) {
- DRM_DEBUG_KMS("Bandwidth %u MB/s exceeds max available %d MB/s (%d active planes)\n",
- data_rate, max_data_rate, num_active_planes);
+ for (i = 0; i < num_qgv_points; i++) {
+ max_data_rate = icl_max_bw(dev_priv, num_active_planes, i);
+ /*
+ * We need to know which qgv point gives us
+ * maximum bandwidth in order to disable SAGV
+ * if we find that we exceed SAGV block time
+ * with watermarks. By that moment we already
+ * have those, as it is calculated earlier in
+ * intel_atomic_check,
+ */
+ if (max_data_rate > max_bw) {
+ max_bw_point = i;
+ max_bw = max_data_rate;
+ }
+ if (max_data_rate >= data_rate)
+ allowed_points |= BIT(i);
+ DRM_DEBUG_KMS("QGV point %d: max bw %d required %d\n",
+ i, max_data_rate, data_rate);
+ }
+
+ /*
+ * BSpec states that we always should have at least one allowed point
+ * left, so if we couldn't - simply reject the configuration for obvious
+ * reasons.
+ */
+ if (allowed_points == 0) {
+ DRM_DEBUG_KMS("No QGV points provide sufficient memory"
+ " bandwidth for display configuration.\n");
return -EINVAL;
}
+ /*
+ * Leave only single point with highest bandwidth, if
+ * we can't enable SAGV due to the increased memory latency it may
+ * cause.
+ */
+ if (!intel_can_enable_sagv(state)) {
+ /*
+ * This is a special case, when we have 0 planes
+ * and SAGV can't be enabled means that we should keep QGV with
+ * highest bandwidth, however algorithm returns wrong result
+ * for 0 planes and 0 data rate case, so just stick to last config
+ * then. Otherwise use the QGV point with highest BW according
+ * to BSpec.
+ */
+ if (!data_rate && !num_active_planes) {
+ DRM_DEBUG_KMS("No SAGV, using old QGV mask\n");
+ allowed_points = (~dev_priv->qgv_points_mask) & mask;
+ } else {
+ allowed_points = 1 << max_bw_point;
+ DRM_DEBUG_KMS("No SAGV, using single QGV point %d\n",
+ max_bw_point);
+ }
+ }
+ /*
+ * We store the ones which need to be masked as that is what PCode
+ * actually accepts as a parameter.
+ */
+ state->qgv_points_mask = (~allowed_points) & mask;
+
+ DRM_DEBUG_KMS("New state %p qgv mask %x\n",
+ state, state->qgv_points_mask);
+
+ /*
+ * If the actual mask had changed we need to make sure that
+ * the commits are serialized(in case this is a nomodeset, nonblocking)
+ */
+ if (state->qgv_points_mask != dev_priv->qgv_points_mask) {
+ ret = intel_atomic_serialize_global_state(state);
+ if (ret) {
+ DRM_DEBUG_KMS("Could not serialize global state\n");
+ return ret;
+ }
+ }
+
return 0;
}
@@ -28,5 +28,7 @@ int intel_bw_init(struct drm_i915_private *dev_priv);
int intel_bw_atomic_check(struct intel_atomic_state *state);
void intel_bw_crtc_update(struct intel_bw_state *bw_state,
const struct intel_crtc_state *crtc_state);
+int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv,
+ u32 points_mask);
#endif /* __INTEL_BW_H__ */
@@ -14786,6 +14786,75 @@ static void intel_atomic_cleanup_work(struct work_struct *work)
intel_atomic_helper_free_state(i915);
}
+static void intel_qgv_points_mask(struct intel_atomic_state *state)
+{
+ struct drm_device *dev = state->base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ int ret;
+ u32 new_mask = dev_priv->qgv_points_mask | state->qgv_points_mask;
+ unsigned int num_qgv_points = dev_priv->max_bw[0].num_qgv_points;
+ unsigned int mask = (1 << num_qgv_points) - 1;
+
+ /*
+ * As we don't know initial hardware state during initial commit
+ * we should not do anything, until we actually figure out,
+ * what are the qgv points to mask.
+ */
+ if (!new_mask)
+ return;
+
+ WARN_ON(new_mask == mask);
+
+ /*
+ * Just return if we can't control SAGV or don't have it.
+ */
+ if (!intel_has_sagv(dev_priv))
+ return;
+
+ /*
+ * Restrict required qgv points before updating the configuration.
+ * According to BSpec we can't mask and unmask qgv points at the same
+ * time. Also masking should be done before updating the configuration
+ * and unmasking afterwards.
+ */
+ ret = icl_pcode_restrict_qgv_points(dev_priv, new_mask);
+ if (ret < 0)
+ DRM_DEBUG_KMS("Could not mask required qgv points(%d)\n",
+ ret);
+ else
+ dev_priv->qgv_points_mask = new_mask;
+}
+
+static void intel_qgv_points_unmask(struct intel_atomic_state *state)
+{
+ struct drm_device *dev = state->base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ int ret;
+ u32 new_mask = dev_priv->qgv_points_mask & state->qgv_points_mask;
+
+ /*
+ * Just return if we can't control SAGV or don't have it.
+ */
+ if (!intel_has_sagv(dev_priv))
+ return;
+
+ if (new_mask == dev_priv->qgv_points_mask)
+ return;
+
+ /*
+ * Allow required qgv points after updating the configuration.
+ * According to BSpec we can't mask and unmask qgv points at the same
+ * time. Also masking should be done before updating the configuration
+ * and unmasking afterwards.
+ */
+ ret = icl_pcode_restrict_qgv_points(dev_priv, new_mask);
+ if (ret < 0)
+ DRM_DEBUG_KMS("Could not unmask required qgv points(%d)\n",
+ ret);
+ else
+ dev_priv->qgv_points_mask = new_mask;
+}
+
static void intel_atomic_commit_tail(struct intel_atomic_state *state)
{
struct drm_device *dev = state->base.dev;
@@ -14813,6 +14882,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
}
}
+ if ((INTEL_GEN(dev_priv) >= 11))
+ intel_qgv_points_mask(state);
+
intel_commit_modeset_disables(state);
/* FIXME: Eventually get rid of our crtc->config pointer */
@@ -14831,8 +14903,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
* SKL workaround: bspec recommends we disable the SAGV when we
* have more then one pipe enabled
*/
- if (!intel_can_enable_sagv(state))
- intel_disable_sagv(dev_priv);
+ if (INTEL_GEN(dev_priv) < 11)
+ if (!intel_can_enable_sagv(state))
+ intel_disable_sagv(dev_priv);
intel_modeset_verify_disabled(dev_priv, state);
}
@@ -14913,8 +14986,11 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
if (state->modeset)
intel_verify_planes(state);
- if (state->modeset && intel_can_enable_sagv(state))
- intel_enable_sagv(dev_priv);
+ if (INTEL_GEN(dev_priv) < 11) {
+ if (state->modeset && intel_can_enable_sagv(state))
+ intel_enable_sagv(dev_priv);
+ } else
+ intel_qgv_points_unmask(state);
drm_atomic_helper_commit_hw_done(&state->base);
@@ -15061,7 +15137,7 @@ static int intel_atomic_commit(struct drm_device *dev,
intel_shared_dpll_swap_state(state);
intel_atomic_track_fbs(state);
- if (state->global_state_changed) {
+ if (state->global_state_changed && state->modeset) {
assert_global_state_locked(dev_priv);
memcpy(dev_priv->min_cdclk, state->min_cdclk,
@@ -528,6 +528,9 @@ struct intel_atomic_state {
struct i915_sw_fence commit_ready;
struct llist_node freed;
+
+ /* Gen11+ only */
+ u32 qgv_points_mask;
};
struct intel_plane_state {
@@ -853,6 +853,9 @@ enum intel_pipe_crc_source {
INTEL_PIPE_CRC_SOURCE_MAX,
};
+/* BSpec precisely defines this */
+#define NUM_SAGV_POINTS 8
+
#define INTEL_PIPE_CRC_ENTRIES_NR 128
struct intel_pipe_crc {
spinlock_t lock;
@@ -1247,6 +1250,8 @@ struct drm_i915_private {
u8 num_planes;
} max_bw[6];
+ u32 qgv_points_mask;
+
struct drm_private_obj bw_obj;
struct intel_runtime_pm runtime_pm;
@@ -8991,6 +8991,8 @@ enum {
#define GEN6_PCODE_UNIMPLEMENTED_CMD 0xFF
#define GEN7_PCODE_TIMEOUT 0x2
#define GEN7_PCODE_ILLEGAL_DATA 0x3
+#define GEN11_PCODE_MAIL_BOX_LOCKED 0x6
+#define GEN11_PCODE_REJECTED 0x11
#define GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE 0x10
#define GEN6_PCODE_WRITE_RC6VIDS 0x4
#define GEN6_PCODE_READ_RC6VIDS 0x5
@@ -9012,6 +9014,7 @@ enum {
#define ICL_PCODE_MEM_SUBSYSYSTEM_INFO 0xd
#define ICL_PCODE_MEM_SS_READ_GLOBAL_INFO (0x0 << 8)
#define ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point) (((point) << 16) | (0x1 << 8))
+#define ICL_PCODE_SAGV_DE_MEM_SS_CONFIG 0xe
#define GEN6_PCODE_READ_D_COMP 0x10
#define GEN6_PCODE_WRITE_D_COMP 0x11
#define HSW_PCODE_DE_WRITE_FREQ_REQ 0x17
@@ -9024,6 +9027,8 @@ enum {
#define GEN9_SAGV_IS_DISABLED 0x1
#define GEN9_SAGV_ENABLE 0x3
#define GEN12_PCODE_READ_SAGV_BLOCK_TIME_US 0x23
+#define GEN11_PCODE_POINTS_RESTRICTED 0x0
+#define GEN11_PCODE_POINTS_RESTRICTED_MASK 0x1
#define GEN6_PCODE_DATA _MMIO(0x138128)
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16
@@ -371,6 +371,29 @@ static inline int gen7_check_mailbox_status(u32 mbox)
}
}
+static inline int gen11_check_mailbox_status(u32 mbox)
+{
+ switch (mbox & GEN6_PCODE_ERROR_MASK) {
+ case GEN6_PCODE_SUCCESS:
+ return 0;
+ case GEN6_PCODE_ILLEGAL_CMD:
+ return -ENXIO;
+ case GEN7_PCODE_TIMEOUT:
+ return -ETIMEDOUT;
+ case GEN7_PCODE_ILLEGAL_DATA:
+ return -EINVAL;
+ case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE:
+ return -EOVERFLOW;
+ case GEN11_PCODE_MAIL_BOX_LOCKED:
+ return -EAGAIN;
+ case GEN11_PCODE_REJECTED:
+ return -EACCES;
+ default:
+ MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK);
+ return 0;
+ }
+}
+
static int __sandybridge_pcode_rw(struct drm_i915_private *i915,
u32 mbox, u32 *val, u32 *val1,
int fast_timeout_us,
@@ -408,7 +431,9 @@ static int __sandybridge_pcode_rw(struct drm_i915_private *i915,
if (is_read && val1)
*val1 = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA1);
- if (INTEL_GEN(i915) > 6)
+ if (INTEL_GEN(i915) >= 11)
+ return gen11_check_mailbox_status(mbox);
+ else if (INTEL_GEN(i915) > 6)
return gen7_check_mailbox_status(mbox);
else
return gen6_check_mailbox_status(mbox);