@@ -32,6 +32,7 @@
#include "i915_vgpu.h"
#include "i915_trace.h"
#include "intel_drv.h"
+#include "intel_mocs.h"
#include <linux/shmem_fs.h>
#include <linux/slab.h>
#include <linux/swap.h>
@@ -4882,6 +4883,12 @@ i915_gem_init_hw(struct drm_device *dev)
goto out;
}
+ /*
+ * lets program the mocs values for all engines the RCS will
+ * send a batch on context start, but that will have to happen
+ */
+ intel_program_mocs_all_engines(dev);
+
/* We can't enable contexts until all firmware is loaded */
if (HAS_GUC_UCODE(dev)) {
ret = intel_guc_ucode_load(dev);
@@ -128,9 +128,9 @@ static const struct drm_i915_mocs_entry broxton_mocs_table[] = {
/**
* get_mocs_settings()
- * @dev: DRM device.
+ * @dev: DRM device.
* @table: Output table that will be made to point at appropriate
- * MOCS values for the device.
+ * MOCS values for the device.
*
* This function will return the values of the MOCS table that needs to
* be programmed for the platform. It will return the values that need @@ -179,6 +179,48 @@ static i915_reg_t mocs_register(enum intel_ring_id ring, int index) }
/**
+ * program_mocs_control_table() - emit the mocs control table
+ * @req: Request to set up the MOCS table for.
+ * @table: The values to program into the control regs.
+ * @ring: The engine for whom to emit the registers.
+ *
+ * This function simply emits a MI_LOAD_REGISTER_IMM command for the
+ * given table starting at the given address.
+ *
+ * Return: 0 on success, otherwise the error status.
+ */
+static int program_mocs_control_table(struct drm_device *dev,
+ const struct drm_i915_mocs_table *table,
+ enum intel_ring_id ring)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned int index;
+
+ if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES))
+ return -ENODEV;
+
+ for (index = 0; index < table->size; index++) {
+ I915_WRITE(mocs_register(ring, index),
+ table->table[index].control_value);
+ }
+
+ /*
+ * Ok, now set the unused entries to uncached. These entries
+ * are officially undefined and no contract for the contents
+ * and settings is given for these entries.
+ *
+ * Entry 0 in the table is uncached - so we are just writing
+ * that value to all the used entries.
+ */
+ for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
+ I915_WRITE(mocs_register(ring, index),
+ table->table[0].control_value);
+ }
+
+ return 0;
+}
+
+/**
* emit_mocs_control_table() - emit the mocs control table
* @req: Request to set up the MOCS table for.
* @table: The values to program into the control regs.
@@ -302,6 +344,83 @@ static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req, }
/**
+ * program_mocs_l3cc_table() - program the mocs control table
+ * @dev: The the device to be programmed.
+ * @table: The values to program into the control regs.
+ *
+ * This function simply programs the mocs registers for the given table
+ * starting at the given address. This register set is programmed in pairs.
+ *
+ * These registers may get programmed more than once, it is simpler to
+ * re-program 32 registers than maintain the state of when they were programmed.
+ * We are always reprogramming with the same values and this only on
+context
+ * start.
+ *
+ * Return: Nothing.
+ */
+static void program_mocs_l3cc_table(struct drm_device *dev,
+ struct drm_i915_mocs_table *table) {
+ unsigned int count;
+ unsigned int i;
+ u32 value;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 filler = (table->table[0].l3cc_value & 0xffff) |
+ ((table->table[0].l3cc_value & 0xffff) << 16);
+
+ for (i = 0, count = 0; i < table->size / 2; i++, count += 2) {
+ value = (table->table[count].l3cc_value & 0xffff) |
+ ((table->table[count + 1].l3cc_value & 0xffff) << 16);
+
+ I915_WRITE(GEN9_LNCFCMOCS(i), value);
+ }
+
+ if (table->size & 0x01) {
+ /* Odd table size - 1 left over */
+ value = (table->table[count].l3cc_value & 0xffff) |
+ ((table->table[0].l3cc_value & 0xffff) << 16);
+ } else
+ value = filler;
+
+ /*
+ * Now set the rest of the table to uncached - use entry 0 as this
+ * will be uncached. Leave the last pair as initialised as they are
+ * reserved by the hardware.
+ */
+ for (; i < (GEN9_NUM_MOCS_ENTRIES / 2); i++) {
+ I915_WRITE(GEN9_LNCFCMOCS(i), value);
+ value = filler;
+ }
+}
+
+/*
+ * intel_program_mocs_all_engines() - program all the MOCS register.
+ *
+ * This function will program the MOCS registers with the correct values.
+ * For all engines.
+ *
+ * Return: Nothing.
+ */
+void intel_program_mocs_all_engines(struct drm_device *dev) {
+ struct drm_i915_mocs_table t;
+
+ if (get_mocs_settings(dev, &t)) {
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_engine_cs *ring;
+ enum intel_ring_id ring_id;
+
+ /* Program the control registers */
+ for_each_ring(ring, dev_priv, ring_id) {
+ program_mocs_control_table(dev, &t, ring_id);
+ }
+
+ /* Now program the l3cc registers */
+ program_mocs_l3cc_table(dev, &t);
+ }
+}
+
+/**
* intel_rcs_context_init_mocs() - program the MOCS register.
* @req: Request to set up the MOCS tables for.
*
@@ -323,16 +442,10 @@ int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req)
int ret;
if (get_mocs_settings(req->ring->dev, &t)) {
- struct drm_i915_private *dev_priv = req->i915;
- struct intel_engine_cs *ring;
- enum intel_ring_id ring_id;
-
- /* Program the control registers */
- for_each_ring(ring, dev_priv, ring_id) {
- ret = emit_mocs_control_table(req, &t, ring_id);
- if (ret)
- return ret;
- }
+ /* Program the RCS control registers */
+ ret = emit_mocs_control_table(req, &t, RCS);
+ if (ret)
+ return ret;
/* Now program the l3cc registers */
ret = emit_mocs_l3cc_table(req, &t);
@@ -53,5 +53,6 @@
#include "i915_drv.h"
int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req);
+void intel_program_mocs_all_engines(struct drm_device *dev);
#endif