[v4] drm/i915 : Added Programming of the MOCS
diff mbox

Message ID 1434554362-22384-1-git-send-email-peter.antoine@intel.com
State New
Headers show

Commit Message

Peter Antoine June 17, 2015, 3:19 p.m. UTC
This change adds the programming of the MOCS registers to the gen 9+
platforms. This change set programs the MOCS register values to a set
of values that are defined to be optimal.

It creates a fixed register set that is programmed across the different
engines so that all engines have the same table. This is done as the
main RCS context only holds the registers for itself and the shared
L3 values. By trying to keep the registers consistent across the
different engines it should make the programming for the registers
consistent.

v2:
-'static const' for private data structures and style changes.(Matt Turner)
v3:
- Make the tables "slightly" more readable. (Damien Lespiau)
- Updated tables fix performance regression.
v4:
- Code formatting. (Chris Wilson)
- re-privatised mocs code. (Daniel Vetter)

Signed-off-by: Peter Antoine <peter.antoine@intel.com>
---
 drivers/gpu/drm/i915/Makefile     |   1 +
 drivers/gpu/drm/i915/i915_reg.h   |   9 +
 drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
 drivers/gpu/drm/i915/intel_lrc.h  |   4 +
 drivers/gpu/drm/i915/intel_mocs.c | 373 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
 6 files changed, 460 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
 create mode 100644 drivers/gpu/drm/i915/intel_mocs.h

Comments

Chris Wilson June 17, 2015, 4:33 p.m. UTC | #1
On Wed, Jun 17, 2015 at 04:19:22PM +0100, Peter Antoine wrote:
> This change adds the programming of the MOCS registers to the gen 9+
> platforms. This change set programs the MOCS register values to a set
> of values that are defined to be optimal.
> 
> It creates a fixed register set that is programmed across the different
> engines so that all engines have the same table. This is done as the
> main RCS context only holds the registers for itself and the shared
> L3 values. By trying to keep the registers consistent across the
> different engines it should make the programming for the registers
> consistent.
> 
> v2:
> -'static const' for private data structures and style changes.(Matt Turner)
> v3:
> - Make the tables "slightly" more readable. (Damien Lespiau)
> - Updated tables fix performance regression.
> v4:
> - Code formatting. (Chris Wilson)
> - re-privatised mocs code. (Daniel Vetter)

Being really picky now, but reading your comments impressed upon me
the importance of reinforcing one particular point...

>  
> +	/*
> +	 * Failing to program the MOCS is non-fatal.The system will not
> +	 * run at peak performance. So generate a warning and carry on.
> +	 */
> +	if (gen9_program_mocs(ring, ctx) != 0)

I think this is better as intel_rcs_context_init_mocs(). Too me it is
important that you emphasize this is to be run once during very early
initialisation to setup the first context prior to anything else. i.e.
All subsequent execution state must be derived from this. Renaming it as
intel_rcs_context_init_mocs():

1 - indicates you have written it to handle all generation, this is
    important as you are otherwise passing in gen8 into a gen9 function.

2 - it is only called during RCS->init_context() and must not be called
    at any other time - this avoids the issue of modifying registers
    used by other rings at runtime, which is the trap you lead me into
    last time.

3 - init_mocs() vs mocs_init() because it is the context_init calling
    the mocs setup.

> +		DRM_ERROR("MOCS failed to program: expect performance issues.");

I guess asking for a new DRM_NOTICE() is too much :)

> +/*
> + * MOCS tables
> + *
> + * These are the MOCS tables that are programmed across all the rings.
> + * The control value is programmed to all the rings that support the
> + * MOCS registers. While the l3cc_values are only programmed to the
> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
> + *
> + * NOTE: These tables MUST start with being uncached and the length MUST be
> + *       less than 63 as the last two registers are reserved by the hardware.
> + */
> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {

static const struct... and propagate that const.

> +/**
> + * get_mocs_settings
> + *
> + * 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
> + * to be programmed and if they need to be programmed.
> + *
> + * If the return values is false then the registers do not need programming.
> + */
> +static bool get_mocs_settings(struct drm_device *dev,
> +			      struct drm_i915_mocs_table *table) {
> +	bool	result = false;

A tab?

> +
> +	if (IS_SKYLAKE(dev)) {
> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
> +		table->table = skylake_mocs_table;
> +		result = true;
> +	} else if (IS_BROXTON(dev)) {
> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
> +		table->table = broxton_mocs_table;
> +		result = true;
> +	} else {
> +		/* Platform that should have a MOCS table does not */
> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);

result = false; here would be fewer lines of code today and tomorrow. :)
> +	}
> +
> +	return result;
-Chris
Daniel Vetter June 18, 2015, 6:59 a.m. UTC | #2
On Wed, Jun 17, 2015 at 04:19:22PM +0100, Peter Antoine wrote:
> This change adds the programming of the MOCS registers to the gen 9+
> platforms. This change set programs the MOCS register values to a set
> of values that are defined to be optimal.
> 
> It creates a fixed register set that is programmed across the different
> engines so that all engines have the same table. This is done as the
> main RCS context only holds the registers for itself and the shared
> L3 values. By trying to keep the registers consistent across the
> different engines it should make the programming for the registers
> consistent.
> 
> v2:
> -'static const' for private data structures and style changes.(Matt Turner)
> v3:
> - Make the tables "slightly" more readable. (Damien Lespiau)
> - Updated tables fix performance regression.
> v4:
> - Code formatting. (Chris Wilson)
> - re-privatised mocs code. (Daniel Vetter)
> 
> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile     |   1 +
>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>  drivers/gpu/drm/i915/intel_mocs.c | 373 ++++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>  6 files changed, 460 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
> 
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index b7ddf48..c781e19 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>  	  i915_irq.o \
>  	  i915_trace_points.o \
>  	  intel_lrc.o \
> +	  intel_mocs.o \
>  	  intel_ringbuffer.o \
>  	  intel_uncore.o
>  
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 7213224..3a435b5 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>  
> +/* MOCS (Memory Object Control State) registers */
> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control base */
> +
> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base register*/
> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base register*/
> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base register*/
> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base register*/
> +
>  #endif /* _I915_REG_H_ */
> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
> index 9f5485d..73b919d 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -135,6 +135,7 @@
>  #include <drm/drmP.h>
>  #include <drm/i915_drm.h>
>  #include "i915_drv.h"
> +#include "intel_mocs.h"
>  
>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf,
>   *
>   * Return: non-zero if the ringbuffer is not ready to be written to.
>   */
> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>  				    struct intel_context *ctx, int num_dwords)
>  {
>  	struct intel_engine_cs *ring = ringbuf->ring;
> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct intel_engine_cs *ring,
>  	if (ret)
>  		return ret;
>  
> +	/*
> +	 * Failing to program the MOCS is non-fatal.The system will not
> +	 * run at peak performance. So generate a warning and carry on.
> +	 */

Is this really true? Userspace must make sure that they don't
inappropriately overwrite the caching settings using MOCS for frontbuffers
and in doing so causing coherency issues with the display block. If we
fail to program MOCS correctly then things won't look pretty.

Sounds like even more reaons imo why we really need the userspace side of
this ...

Also the general approach for render side setup failures is to return
-EIO, which will result in a wedged gpu. No reason imo here to eat this
failure.
-Daniel

> +	if (gen9_program_mocs(ring, ctx) != 0)
> +		DRM_ERROR("MOCS failed to program: expect performance issues.");
> +
>  	return intel_lr_context_render_state_init(ring, ctx);
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
> index 04d3a6d..dbbd6af 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.h
> +++ b/drivers/gpu/drm/i915/intel_lrc.h
> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>  
>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>  				  struct intel_context *ctx);
> +
> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
> +				    struct intel_context *ctx, int num_dwords);
> +
>  /**
>   * intel_logical_ring_advance() - advance the ringbuffer tail
>   * @ringbuf: Ringbuffer to advance.
> diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c
> new file mode 100644
> index 0000000..7c09e67
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_mocs.c
> @@ -0,0 +1,373 @@
> +/*
> + * Copyright (c) 2015 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions: *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + * Authors:
> + *    Peter Antoine <peter.antoine@intel.com>
> + */
> +
> +#include "intel_mocs.h"
> +#include "intel_lrc.h"
> +#include "intel_ringbuffer.h"
> +
> +/* structures required */
> +struct drm_i915_mocs_entry {
> +	u32	control_value;
> +	u16	l3cc_value;
> +};
> +
> +struct drm_i915_mocs_table {
> +	u32					size;
> +	const struct drm_i915_mocs_entry	*table;
> +};
> +
> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
> +#define	MOCS_CACHEABILITY(value)	(value << 0)
> +#define	MOCS_TGT_CACHE(value)		(value << 2)
> +#define	MOCS_LRUM(value)		(value << 4)
> +#define	MOCS_AOM(value)			(value << 6)
> +#define	MOCS_LECC_ESC(value)		(value << 7)
> +#define	MOCS_LECC_SCC(value)		(value << 8)
> +#define	MOC_PFM(value)			(value << 11)
> +#define	MOCS_SCF(value)			(value << 14)
> +
> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */
> +#define	MOCS_ESC(value)			(value << 0)
> +#define	MOCS_SCC(value)			(value << 1)
> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
> +
> +/* Helper defines */
> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program */
> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd */
> +
> +/* EDRAM Caching options */
> +#define EDRAM_PAGETABLE		(0)
> +#define EDRAM_UC		(1)
> +#define EDRAM_RESERVED		(2)
> +#define EDRAM_WB		(3)
> +
> +/* L3 Caching options */
> +#define L3_DIRECT		(0)
> +#define L3_UC			(1)
> +#define L3_RESERVED		(2)
> +#define L3_WB			(3)
> +
> +/* target cache */
> +#define ELLC			(0)
> +#define LLC			(1)
> +#define LLC_ELLC		(2)
> +
> +/*
> + * MOCS tables
> + *
> + * These are the MOCS tables that are programmed across all the rings.
> + * The control value is programmed to all the rings that support the
> + * MOCS registers. While the l3cc_values are only programmed to the
> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
> + *
> + * NOTE: These tables MUST start with being uncached and the length MUST be
> + *       less than 63 as the last two registers are reserved by the hardware.
> + */
> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
> +	 /* {0x00000009, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x0000003b, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000039, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000017, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000017, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000019, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000037, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000037, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x0000003b, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +};
> +
> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
> +	 /* {0x00000001, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000005, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000005, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000017, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000017, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000019, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000037, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000037, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x0000003b, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +};
> +
> +/**
> + * get_mocs_settings
> + *
> + * 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
> + * to be programmed and if they need to be programmed.
> + *
> + * If the return values is false then the registers do not need programming.
> + */
> +static bool get_mocs_settings(struct drm_device *dev,
> +			      struct drm_i915_mocs_table *table) {
> +	bool	result = false;
> +
> +	if (IS_SKYLAKE(dev)) {
> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
> +		table->table = skylake_mocs_table;
> +		result = true;
> +	} else if (IS_BROXTON(dev)) {
> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
> +		table->table = broxton_mocs_table;
> +		result = true;
> +	} else {
> +		/* Platform that should have a MOCS table does not */
> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
> +	}
> +
> +	return result;
> +}
> +
> +/**
> + * emit_mocs_control_table() - emit the mocs control table
> + * @ringbuf:	DRM device.
> + * @table:	The values to program into the control regs.
> + * @reg_base:	The base for the Engine that needs to be programmed.
> + *
> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
> + * given table starting at the given address.
> + *
> + * Return: Nothing.
> + */
> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
> +				    struct drm_i915_mocs_table *table,
> +				    u32 reg_base)
> +{
> +	unsigned int index;
> +
> +	intel_logical_ring_emit(ringbuf,
> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
> +
> +	for (index = 0; index < table->size; index++) {
> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
> +		intel_logical_ring_emit(ringbuf,
> +					table->table[index].control_value);
> +	}
> +
> +	/*
> +	 * Ok, now set the unused entries to uncached. These entries are
> +	 * officially undefined and no contact is given for the contents and
> +	 * settings is given for these entries.
> +	 *
> +	 * Entry 0 in the table is uncached - so we are just written that
> +	 * value to all the used entries.
> +	 */
> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
> +		intel_logical_ring_emit(ringbuf, table->table[0].control_value);
> +	}
> +
> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
> +}
> +
> +/**
> + * emit_mocs_l3cc_table() - emit the mocs control table
> + * @ringbuf:	DRM device.
> + * @table:	The values to program into the control regs.
> + *
> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
> + * given table starting at the given address. This register set is  programmed
> + * in pairs.
> + *
> + * Return: Nothing.
> + */
> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
> +			 struct drm_i915_mocs_table *table) {
> +	unsigned int count;
> +	unsigned int i;
> +	u32 value;
> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
> +			((table->table[0].l3cc_value & 0xffff) << 16);
> +
> +	intel_logical_ring_emit(ringbuf,
> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
> +
> +	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);
> +
> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
> +		intel_logical_ring_emit(ringbuf, value);
> +
> +		value = filler;
> +	}
> +
> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
> +}
> +
> +/*
> + * gen9_program_mocs() - program the MOCS register.
> + *
> + * ring:	The ring that the programming batch will be run in.
> + * ctx:		The intel_context to be used.
> + *
> + * This function will emit a batch buffer with the values required for
> + * programming the MOCS register values for all the currently supported
> + * rings.
> + *
> + * These registers are partially stored in the RCS context, so they are
> + * emitted at the same time so that when a context is created these registers
> + * are set up. These registers have to be emitted into the start of the
> + * context as setting the ELSP will re-init some of these registers back
> + * to the hw values.
> + *
> + * Return: 0 on success, otherwise the error status.
> + */
> +int gen9_program_mocs(struct intel_engine_cs *ring,
> +			  struct intel_context *ctx)
> +{
> +	int ret = 0;
> +
> +	struct drm_i915_mocs_table t;
> +	struct drm_device *dev = ring->dev;
> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
> +
> +	if (get_mocs_settings(dev, &t)) {
> +		u32 table_size;
> +
> +		/*
> +		 * OK. For each supported ring:
> +		 *  number of mocs entries * 2 dwords for each control_value
> +		 *  plus number of mocs entries /2 dwords for l3cc values.
> +		 *
> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
> +		 *  and the l3cc programming.
> +		 */
> +		table_size = GEN9_NUM_MOCS_RINGS *
> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
> +				GEN9_NUM_MOCS_ENTRIES + 2;
> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
> +		if (ret) {
> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret);
> +			return ret;
> +		}
> +
> +		/* program the control registers */
> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
> +
> +		/* now program the l3cc registers */
> +		emit_mocs_l3cc_table(ringbuf, &t);
> +
> +		intel_logical_ring_advance(ringbuf);
> +
> +		DRM_DEBUG("MOCS: Table set in Context\n");
> +	} else {
> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
> +	}
> +
> +	return ret;
> +}
> +
> diff --git a/drivers/gpu/drm/i915/intel_mocs.h b/drivers/gpu/drm/i915/intel_mocs.h
> new file mode 100644
> index 0000000..e2780ce
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_mocs.h
> @@ -0,0 +1,64 @@
> +/*
> + * Copyright (c) 2015 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + * Authors:
> + *    Peter Antoine <peter.antoine@intel.com>
> + */
> +
> +#ifndef INTEL_MOCS_H
> +#define INTEL_MOCS_H
> +
> +/**
> + * DOC: Memory Objects Control State (MOCS)
> + *
> + * Motivation:
> + * In previous Gens the MOCS settings was a value that was set by user land as
> + * part of the batch. In Gen9 this has changed to be a single table (per ring)
> + * that all batches now reference by index instead of programming the MOCS
> + * directly.
> + *
> + * The one wrinkle in this is that only PART of the MOCS tables are included
> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - LNCFCMOCS32
> + * registers). The rest are not (the settings for the other rings).
> + *
> + * This table needs to be set at system start-up because the way the table
> + * interacts with the contexts and the GmmLib interface.
> + *
> + *
> + * Implementation:
> + *
> + * The table is programmed on a platform basis from a table that is generated
> + * from the one that has been agreed by the different responsible parties. This
> + * tables (one per supported platform) is defined in intel_mocs.c and is
> + * programmed in the first batch after the context is loaded (with the hardware
> + * workarounds). This will then let the usual context handling keep the MOCS in
> + * step.
> + */
> +
> +#include <drm/drmP.h>
> +#include "i915_drv.h"
> +
> +int gen9_program_mocs(struct intel_engine_cs *ring,
> +			struct intel_context *ctx);
> +
> +#endif
> +
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Peter Antoine June 18, 2015, 7:36 a.m. UTC | #3
On Wed, 2015-06-17 at 17:33 +0100, Chris Wilson wrote:
> On Wed, Jun 17, 2015 at 04:19:22PM +0100, Peter Antoine wrote:

> > This change adds the programming of the MOCS registers to the gen 9+

> > platforms. This change set programs the MOCS register values to a set

> > of values that are defined to be optimal.

> > 

> > It creates a fixed register set that is programmed across the different

> > engines so that all engines have the same table. This is done as the

> > main RCS context only holds the registers for itself and the shared

> > L3 values. By trying to keep the registers consistent across the

> > different engines it should make the programming for the registers

> > consistent.

> > 

> > v2:

> > -'static const' for private data structures and style changes.(Matt Turner)

> > v3:

> > - Make the tables "slightly" more readable. (Damien Lespiau)

> > - Updated tables fix performance regression.

> > v4:

> > - Code formatting. (Chris Wilson)

> > - re-privatised mocs code. (Daniel Vetter)

> 

> Being really picky now, but reading your comments impressed upon me

> the importance of reinforcing one particular point...

> 

> >  

> > +	/*

> > +	 * Failing to program the MOCS is non-fatal.The system will not

> > +	 * run at peak performance. So generate a warning and carry on.

> > +	 */

> > +	if (gen9_program_mocs(ring, ctx) != 0)

> 

> I think this is better as intel_rcs_context_init_mocs(). Too me it is

> important that you emphasize this is to be run once during very early

> initialisation to setup the first context prior to anything else. i.e.

> All subsequent execution state must be derived from this. Renaming it as

> intel_rcs_context_init_mocs():

> 

> 1 - indicates you have written it to handle all generation, this is

>     important as you are otherwise passing in gen8 into a gen9 function.

> 

> 2 - it is only called during RCS->init_context() and must not be called

>     at any other time - this avoids the issue of modifying registers

>     used by other rings at runtime, which is the trap you lead me into

>     last time.

No problem with that.But adding rcs to the original name suggests that it
is only setting up the rcs engine and not all the engines. If any of the
other context engines have there context extended then we may need to call
the function from other ring initialise functions.

I'll change it to intel_context_emit_mocs() as this does say what it does
on the tin, it only emits the mocs to the context and does not program them.

> 

> 3 - init_mocs() vs mocs_init() because it is the context_init calling

>     the mocs setup.

> 

> > +		DRM_ERROR("MOCS failed to program: expect performance issues.");

> 

> I guess asking for a new DRM_NOTICE() is too much :)

I searched the code for NOTICE and DRM_NOTICE and could not find it. So changed
it from an WARN_ON to and ERROR.
> 

> > +/*

> > + * MOCS tables

> > + *

> > + * These are the MOCS tables that are programmed across all the rings.

> > + * The control value is programmed to all the rings that support the

> > + * MOCS registers. While the l3cc_values are only programmed to the

> > + * LNCFCMOCS0 - LNCFCMOCS32 registers.

> > + *

> > + * NOTE: These tables MUST start with being uncached and the length MUST be

> > + *       less than 63 as the last two registers are reserved by the hardware.

> > + */

> > +static struct drm_i915_mocs_entry skylake_mocs_table[] = {

> 

> static const struct... and propagate that const.

Yup, with make it static const.
> 

> > +/**

> > + * get_mocs_settings

> > + *

> > + * 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

> > + * to be programmed and if they need to be programmed.

> > + *

> > + * If the return values is false then the registers do not need programming.

> > + */

> > +static bool get_mocs_settings(struct drm_device *dev,

> > +			      struct drm_i915_mocs_table *table) {

> > +	bool	result = false;

> 

> A tab?

Ok.
> 

> > +

> > +	if (IS_SKYLAKE(dev)) {

> > +		table->size  = ARRAY_SIZE(skylake_mocs_table);

> > +		table->table = skylake_mocs_table;

> > +		result = true;

> > +	} else if (IS_BROXTON(dev)) {

> > +		table->size  = ARRAY_SIZE(broxton_mocs_table);

> > +		table->table = broxton_mocs_table;

> > +		result = true;

> > +	} else {

> > +		/* Platform that should have a MOCS table does not */

> > +		WARN_ON(INTEL_INFO(dev)->gen >= 9);

> 

> result = false; here would be fewer lines of code today and tomorrow. :)

Fail safe return value. Makes not difference here, but golden in larger
functions.
> > +	}

> > +

> > +	return result;

> -Chris

>
Chris Wilson June 18, 2015, 7:42 a.m. UTC | #4
On Thu, Jun 18, 2015 at 08:59:55AM +0200, Daniel Vetter wrote:
> > +	/*
> > +	 * Failing to program the MOCS is non-fatal.The system will not
> > +	 * run at peak performance. So generate a warning and carry on.
> > +	 */
> 
> Is this really true? Userspace must make sure that they don't
> inappropriately overwrite the caching settings using MOCS for frontbuffers
> and in doing so causing coherency issues with the display block. If we
> fail to program MOCS correctly then things won't look pretty.

I was under the presumption that the MOCS entries would default to UC,
since that is the failsafe mode.
-Chris
Chris Wilson June 18, 2015, 7:49 a.m. UTC | #5
On Thu, Jun 18, 2015 at 07:36:41AM +0000, Antoine, Peter wrote:
> 
> On Wed, 2015-06-17 at 17:33 +0100, Chris Wilson wrote:
> > On Wed, Jun 17, 2015 at 04:19:22PM +0100, Peter Antoine wrote:
> > > This change adds the programming of the MOCS registers to the gen 9+
> > > platforms. This change set programs the MOCS register values to a set
> > > of values that are defined to be optimal.
> > > 
> > > It creates a fixed register set that is programmed across the different
> > > engines so that all engines have the same table. This is done as the
> > > main RCS context only holds the registers for itself and the shared
> > > L3 values. By trying to keep the registers consistent across the
> > > different engines it should make the programming for the registers
> > > consistent.
> > > 
> > > v2:
> > > -'static const' for private data structures and style changes.(Matt Turner)
> > > v3:
> > > - Make the tables "slightly" more readable. (Damien Lespiau)
> > > - Updated tables fix performance regression.
> > > v4:
> > > - Code formatting. (Chris Wilson)
> > > - re-privatised mocs code. (Daniel Vetter)
> > 
> > Being really picky now, but reading your comments impressed upon me
> > the importance of reinforcing one particular point...
> > 
> > >  
> > > +	/*
> > > +	 * Failing to program the MOCS is non-fatal.The system will not
> > > +	 * run at peak performance. So generate a warning and carry on.
> > > +	 */
> > > +	if (gen9_program_mocs(ring, ctx) != 0)
> > 
> > I think this is better as intel_rcs_context_init_mocs(). Too me it is
> > important that you emphasize this is to be run once during very early
> > initialisation to setup the first context prior to anything else. i.e.
> > All subsequent execution state must be derived from this. Renaming it as
> > intel_rcs_context_init_mocs():
> > 
> > 1 - indicates you have written it to handle all generation, this is
> >     important as you are otherwise passing in gen8 into a gen9 function.
> > 
> > 2 - it is only called during RCS->init_context() and must not be called
> >     at any other time - this avoids the issue of modifying registers
> >     used by other rings at runtime, which is the trap you lead me into
> >     last time.
> No problem with that.But adding rcs to the original name suggests that it
> is only setting up the rcs engine and not all the engines. If any of the
> other context engines have there context extended then we may need to call
> the function from other ring initialise functions.

"intel_rcs_context" is the object
"init_mocs" is the verb, with "init" being a fairly well defined phase
of context operatinons.

My suggestion is that is only run during RCS context init. The comments
tell us that it affects all rings - and so we must emphasize that the
RCS context init *must* be run before the other rings are enabled for
submission.

If we have contexts being initialised on other rings, then one would not
think of calling intel_rcs_context_init* but instead think of how we
would need to interact with concurrent engine initialisation. Being
specifc here should stop someone simply calling the function and hoping
for the best.

> I'll change it to intel_context_emit_mocs() as this does say what it does
> on the tin, it only emits the mocs to the context and does not program them.

That misses the point I am trying to make.

> > > +	if (IS_SKYLAKE(dev)) {
> > > +		table->size  = ARRAY_SIZE(skylake_mocs_table);
> > > +		table->table = skylake_mocs_table;
> > > +		result = true;
> > > +	} else if (IS_BROXTON(dev)) {
> > > +		table->size  = ARRAY_SIZE(broxton_mocs_table);
> > > +		table->table = broxton_mocs_table;
> > > +		result = true;
> > > +	} else {
> > > +		/* Platform that should have a MOCS table does not */
> > > +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
> > 
> > result = false; here would be fewer lines of code today and tomorrow. :)
> Fail safe return value. Makes not difference here, but golden in larger
> functions.

Actually I don't see why you can't encode the ARRAY_SIZE into the static
const tables, then the return value is just the appropriate table. If
you don't set a default value, then you get a compiler warning telling
you missed adding it your new code.
-Chris
Peter Antoine June 18, 2015, 8:01 a.m. UTC | #6
-----Original Message-----
From: Chris Wilson [mailto:chris@chris-wilson.co.uk] 
Sent: Thursday, June 18, 2015 8:42 AM
To: Daniel Vetter
Cc: Antoine, Peter; intel-gfx@lists.freedesktop.org
Subject: Re: [Intel-gfx] [PATCH v4] drm/i915 : Added Programming of the MOCS

On Thu, Jun 18, 2015 at 08:59:55AM +0200, Daniel Vetter wrote:
> > +	/*
> > +	 * Failing to program the MOCS is non-fatal.The system will not
> > +	 * run at peak performance. So generate a warning and carry on.
> > +	 */
> 
> Is this really true? Userspace must make sure that they don't 
> inappropriately overwrite the caching settings using MOCS for 
> frontbuffers and in doing so causing coherency issues with the display 
> block. If we fail to program MOCS correctly then things won't look pretty.

I was under the presumption that the MOCS entries would default to UC, since that is the failsafe mode.
-Chris

No they will stay at the hardware defaults as specified in the Bspec.
Peter.

--
Chris Wilson, Intel Open Source Technology Centre
Peter Antoine June 18, 2015, 8:45 a.m. UTC | #7
On Thu, 2015-06-18 at 08:49 +0100, chris@chris-wilson.co.uk wrote:
> On Thu, Jun 18, 2015 at 07:36:41AM +0000, Antoine, Peter wrote:

> > 

> > On Wed, 2015-06-17 at 17:33 +0100, Chris Wilson wrote:

> > > On Wed, Jun 17, 2015 at 04:19:22PM +0100, Peter Antoine wrote:

> > > > This change adds the programming of the MOCS registers to the gen 9+

> > > > platforms. This change set programs the MOCS register values to a set

> > > > of values that are defined to be optimal.

> > > > 

> > > > It creates a fixed register set that is programmed across the different

> > > > engines so that all engines have the same table. This is done as the

> > > > main RCS context only holds the registers for itself and the shared

> > > > L3 values. By trying to keep the registers consistent across the

> > > > different engines it should make the programming for the registers

> > > > consistent.

> > > > 

> > > > v2:

> > > > -'static const' for private data structures and style changes.(Matt Turner)

> > > > v3:

> > > > - Make the tables "slightly" more readable. (Damien Lespiau)

> > > > - Updated tables fix performance regression.

> > > > v4:

> > > > - Code formatting. (Chris Wilson)

> > > > - re-privatised mocs code. (Daniel Vetter)

> > > 

> > > Being really picky now, but reading your comments impressed upon me

> > > the importance of reinforcing one particular point...

> > > 

> > > >  

> > > > +	/*

> > > > +	 * Failing to program the MOCS is non-fatal.The system will not

> > > > +	 * run at peak performance. So generate a warning and carry on.

> > > > +	 */

> > > > +	if (gen9_program_mocs(ring, ctx) != 0)

> > > 

> > > I think this is better as intel_rcs_context_init_mocs(). Too me it is

> > > important that you emphasize this is to be run once during very early

> > > initialisation to setup the first context prior to anything else. i.e.

> > > All subsequent execution state must be derived from this. Renaming it as

> > > intel_rcs_context_init_mocs():

> > > 

> > > 1 - indicates you have written it to handle all generation, this is

> > >     important as you are otherwise passing in gen8 into a gen9 function.

> > > 

> > > 2 - it is only called during RCS->init_context() and must not be called

> > >     at any other time - this avoids the issue of modifying registers

> > >     used by other rings at runtime, which is the trap you lead me into

> > >     last time.

> > No problem with that.But adding rcs to the original name suggests that it

> > is only setting up the rcs engine and not all the engines. If any of the

> > other context engines have there context extended then we may need to call

> > the function from other ring initialise functions.

> 

> "intel_rcs_context" is the object

> "init_mocs" is the verb, with "init" being a fairly well defined phase

> of context operatinons.

> 

> My suggestion is that is only run during RCS context init. The comments

> tell us that it affects all rings - and so we must emphasize that the

> RCS context init *must* be run before the other rings are enabled for

> submission.

> 

> If we have contexts being initialised on other rings, then one would not

> think of calling intel_rcs_context_init* but instead think of how we

> would need to interact with concurrent engine initialisation. Being

> specifc here should stop someone simply calling the function and hoping

> for the best.

> 

> > I'll change it to intel_context_emit_mocs() as this does say what it does

> > on the tin, it only emits the mocs to the context and does not program them.

> 

> That misses the point I am trying to make.


I don't get your point, the original seemed good to me.
Changing name to what you want as this needs to get in.

> 

> > > > +	if (IS_SKYLAKE(dev)) {

> > > > +		table->size  = ARRAY_SIZE(skylake_mocs_table);

> > > > +		table->table = skylake_mocs_table;

> > > > +		result = true;

> > > > +	} else if (IS_BROXTON(dev)) {

> > > > +		table->size  = ARRAY_SIZE(broxton_mocs_table);

> > > > +		table->table = broxton_mocs_table;

> > > > +		result = true;

> > > > +	} else {

> > > > +		/* Platform that should have a MOCS table does not */

> > > > +		WARN_ON(INTEL_INFO(dev)->gen >= 9);

> > > 

> > > result = false; here would be fewer lines of code today and tomorrow. :)

> > Fail safe return value. Makes not difference here, but golden in larger

> > functions.

> 

> Actually I don't see why you can't encode the ARRAY_SIZE into the static

> const tables, then the return value is just the appropriate table. If

> you don't set a default value, then you get a compiler warning telling

> you missed adding it your new code.

How does that make any difference?
We still need the if's to make it work on different platforms. So the
"result =" code still stays the same.

> -Chris

>
Chris Wilson June 18, 2015, 9:10 a.m. UTC | #8
On Thu, Jun 18, 2015 at 08:45:10AM +0000, Antoine, Peter wrote:
> On Thu, 2015-06-18 at 08:49 +0100, chris@chris-wilson.co.uk wrote:
> > On Thu, Jun 18, 2015 at 07:36:41AM +0000, Antoine, Peter wrote:
> > > 
> > > On Wed, 2015-06-17 at 17:33 +0100, Chris Wilson wrote:
> > > > On Wed, Jun 17, 2015 at 04:19:22PM +0100, Peter Antoine wrote:
> > > > > This change adds the programming of the MOCS registers to the gen 9+
> > > > > platforms. This change set programs the MOCS register values to a set
> > > > > of values that are defined to be optimal.
> > > > > 
> > > > > It creates a fixed register set that is programmed across the different
> > > > > engines so that all engines have the same table. This is done as the
> > > > > main RCS context only holds the registers for itself and the shared
> > > > > L3 values. By trying to keep the registers consistent across the
> > > > > different engines it should make the programming for the registers
> > > > > consistent.
> > > > > 
> > > > > v2:
> > > > > -'static const' for private data structures and style changes.(Matt Turner)
> > > > > v3:
> > > > > - Make the tables "slightly" more readable. (Damien Lespiau)
> > > > > - Updated tables fix performance regression.
> > > > > v4:
> > > > > - Code formatting. (Chris Wilson)
> > > > > - re-privatised mocs code. (Daniel Vetter)
> > > > 
> > > > Being really picky now, but reading your comments impressed upon me
> > > > the importance of reinforcing one particular point...
> > > > 
> > > > >  
> > > > > +	/*
> > > > > +	 * Failing to program the MOCS is non-fatal.The system will not
> > > > > +	 * run at peak performance. So generate a warning and carry on.
> > > > > +	 */
> > > > > +	if (gen9_program_mocs(ring, ctx) != 0)
> > > > 
> > > > I think this is better as intel_rcs_context_init_mocs(). Too me it is
> > > > important that you emphasize this is to be run once during very early
> > > > initialisation to setup the first context prior to anything else. i.e.
> > > > All subsequent execution state must be derived from this. Renaming it as
> > > > intel_rcs_context_init_mocs():
> > > > 
> > > > 1 - indicates you have written it to handle all generation, this is
> > > >     important as you are otherwise passing in gen8 into a gen9 function.
> > > > 
> > > > 2 - it is only called during RCS->init_context() and must not be called
> > > >     at any other time - this avoids the issue of modifying registers
> > > >     used by other rings at runtime, which is the trap you lead me into
> > > >     last time.
> > > No problem with that.But adding rcs to the original name suggests that it
> > > is only setting up the rcs engine and not all the engines. If any of the
> > > other context engines have there context extended then we may need to call
> > > the function from other ring initialise functions.
> > 
> > "intel_rcs_context" is the object
> > "init_mocs" is the verb, with "init" being a fairly well defined phase
> > of context operatinons.
> > 
> > My suggestion is that is only run during RCS context init. The comments
> > tell us that it affects all rings - and so we must emphasize that the
> > RCS context init *must* be run before the other rings are enabled for
> > submission.
> > 
> > If we have contexts being initialised on other rings, then one would not
> > think of calling intel_rcs_context_init* but instead think of how we
> > would need to interact with concurrent engine initialisation. Being
> > specifc here should stop someone simply calling the function and hoping
> > for the best.
> > 
> > > I'll change it to intel_context_emit_mocs() as this does say what it does
> > > on the tin, it only emits the mocs to the context and does not program them.
> > 
> > That misses the point I am trying to make.
> 
> I don't get your point, the original seemed good to me.
> Changing name to what you want as this needs to get in.

My point is that it is not a generic function and must be called at a
certain phase of context construction and lrc initialisation. I am
trying to suggest a name that encapsulates that to avoid possible
misuse.

> > > > > +	if (IS_SKYLAKE(dev)) {
> > > > > +		table->size  = ARRAY_SIZE(skylake_mocs_table);
> > > > > +		table->table = skylake_mocs_table;
> > > > > +		result = true;
> > > > > +	} else if (IS_BROXTON(dev)) {
> > > > > +		table->size  = ARRAY_SIZE(broxton_mocs_table);
> > > > > +		table->table = broxton_mocs_table;
> > > > > +		result = true;
> > > > > +	} else {
> > > > > +		/* Platform that should have a MOCS table does not */
> > > > > +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
> > > > 
> > > > result = false; here would be fewer lines of code today and tomorrow. :)
> > > Fail safe return value. Makes not difference here, but golden in larger
> > > functions.
> > 
> > Actually I don't see why you can't encode the ARRAY_SIZE into the static
> > const tables, then the return value is just the appropriate table. If
> > you don't set a default value, then you get a compiler warning telling
> > you missed adding it your new code.
> How does that make any difference?

In terms of code construction, simpler and able to the mark all the data
structures as const.
-Chris
Peter Antoine June 18, 2015, 12:18 p.m. UTC | #9
On Thu, 2015-06-18 at 10:10 +0100, chris@chris-wilson.co.uk wrote:
> On Thu, Jun 18, 2015 at 08:45:10AM +0000, Antoine, Peter wrote:

> > On Thu, 2015-06-18 at 08:49 +0100, chris@chris-wilson.co.uk wrote:

> > > On Thu, Jun 18, 2015 at 07:36:41AM +0000, Antoine, Peter wrote:

> > > > 

> > > > On Wed, 2015-06-17 at 17:33 +0100, Chris Wilson wrote:

> > > > > On Wed, Jun 17, 2015 at 04:19:22PM +0100, Peter Antoine wrote:

> > > > > > This change adds the programming of the MOCS registers to the gen 9+

> > > > > > platforms. This change set programs the MOCS register values to a set

> > > > > > of values that are defined to be optimal.

> > > > > > 

> > > > > > It creates a fixed register set that is programmed across the different

> > > > > > engines so that all engines have the same table. This is done as the

> > > > > > main RCS context only holds the registers for itself and the shared

> > > > > > L3 values. By trying to keep the registers consistent across the

> > > > > > different engines it should make the programming for the registers

> > > > > > consistent.

> > > > > > 

> > > > > > v2:

> > > > > > -'static const' for private data structures and style changes.(Matt Turner)

> > > > > > v3:

> > > > > > - Make the tables "slightly" more readable. (Damien Lespiau)

> > > > > > - Updated tables fix performance regression.

> > > > > > v4:

> > > > > > - Code formatting. (Chris Wilson)

> > > > > > - re-privatised mocs code. (Daniel Vetter)

> > > > > 

> > > > > Being really picky now, but reading your comments impressed upon me

> > > > > the importance of reinforcing one particular point...

> > > > > 

> > > > > >  

> > > > > > +	/*

> > > > > > +	 * Failing to program the MOCS is non-fatal.The system will not

> > > > > > +	 * run at peak performance. So generate a warning and carry on.

> > > > > > +	 */

> > > > > > +	if (gen9_program_mocs(ring, ctx) != 0)

> > > > > 

> > > > > I think this is better as intel_rcs_context_init_mocs(). Too me it is

> > > > > important that you emphasize this is to be run once during very early

> > > > > initialisation to setup the first context prior to anything else. i.e.

> > > > > All subsequent execution state must be derived from this. Renaming it as

> > > > > intel_rcs_context_init_mocs():

> > > > > 

> > > > > 1 - indicates you have written it to handle all generation, this is

> > > > >     important as you are otherwise passing in gen8 into a gen9 function.

> > > > > 

> > > > > 2 - it is only called during RCS->init_context() and must not be called

> > > > >     at any other time - this avoids the issue of modifying registers

> > > > >     used by other rings at runtime, which is the trap you lead me into

> > > > >     last time.

> > > > No problem with that.But adding rcs to the original name suggests that it

> > > > is only setting up the rcs engine and not all the engines. If any of the

> > > > other context engines have there context extended then we may need to call

> > > > the function from other ring initialise functions.

> > > 

> > > "intel_rcs_context" is the object

> > > "init_mocs" is the verb, with "init" being a fairly well defined phase

> > > of context operatinons.

> > > 

> > > My suggestion is that is only run during RCS context init. The comments

> > > tell us that it affects all rings - and so we must emphasize that the

> > > RCS context init *must* be run before the other rings are enabled for

> > > submission.

> > > 

> > > If we have contexts being initialised on other rings, then one would not

> > > think of calling intel_rcs_context_init* but instead think of how we

> > > would need to interact with concurrent engine initialisation. Being

> > > specifc here should stop someone simply calling the function and hoping

> > > for the best.

> > > 

> > > > I'll change it to intel_context_emit_mocs() as this does say what it does

> > > > on the tin, it only emits the mocs to the context and does not program them.

> > > 

> > > That misses the point I am trying to make.

> > 

> > I don't get your point, the original seemed good to me.

> > Changing name to what you want as this needs to get in.

> 

> My point is that it is not a generic function and must be called at a

> certain phase of context construction and lrc initialisation. I am

> trying to suggest a name that encapsulates that to avoid possible

> misuse.

> 

> > > > > > +	if (IS_SKYLAKE(dev)) {

> > > > > > +		table->size  = ARRAY_SIZE(skylake_mocs_table);

> > > > > > +		table->table = skylake_mocs_table;

> > > > > > +		result = true;

> > > > > > +	} else if (IS_BROXTON(dev)) {

> > > > > > +		table->size  = ARRAY_SIZE(broxton_mocs_table);

> > > > > > +		table->table = broxton_mocs_table;

> > > > > > +		result = true;

> > > > > > +	} else {

> > > > > > +		/* Platform that should have a MOCS table does not */

> > > > > > +		WARN_ON(INTEL_INFO(dev)->gen >= 9);

> > > > > 

> > > > > result = false; here would be fewer lines of code today and tomorrow. :)

> > > > Fail safe return value. Makes not difference here, but golden in larger

> > > > functions.

> > > 

> > > Actually I don't see why you can't encode the ARRAY_SIZE into the static

> > > const tables, then the return value is just the appropriate table. If

> > > you don't set a default value, then you get a compiler warning telling

> > > you missed adding it your new code.

> > How does that make any difference?

> 

> In terms of code construction, simpler and able to the mark all the data

> structures as const.

Going to leave the code as is. It's clean and readable. It's a simple
internal demux function and all the structures that are referenced are
const
-Peter.
> -Chris

>
Francisco Jerez June 25, 2015, 12:59 p.m. UTC | #10
Peter Antoine <peter.antoine@intel.com> writes:

> This change adds the programming of the MOCS registers to the gen 9+
> platforms. This change set programs the MOCS register values to a set
> of values that are defined to be optimal.
>
> It creates a fixed register set that is programmed across the different
> engines so that all engines have the same table. This is done as the
> main RCS context only holds the registers for itself and the shared
> L3 values. By trying to keep the registers consistent across the
> different engines it should make the programming for the registers
> consistent.
>
> v2:
> -'static const' for private data structures and style changes.(Matt Turner)
> v3:
> - Make the tables "slightly" more readable. (Damien Lespiau)
> - Updated tables fix performance regression.
> v4:
> - Code formatting. (Chris Wilson)
> - re-privatised mocs code. (Daniel Vetter)
>
> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile     |   1 +
>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>  drivers/gpu/drm/i915/intel_mocs.c | 373 ++++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>  6 files changed, 460 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index b7ddf48..c781e19 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>  	  i915_irq.o \
>  	  i915_trace_points.o \
>  	  intel_lrc.o \
> +	  intel_mocs.o \
>  	  intel_ringbuffer.o \
>  	  intel_uncore.o
>  
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 7213224..3a435b5 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>  
> +/* MOCS (Memory Object Control State) registers */
> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control base */
> +
> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base register*/
> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base register*/
> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base register*/
> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base register*/
> +
>  #endif /* _I915_REG_H_ */
> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
> index 9f5485d..73b919d 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -135,6 +135,7 @@
>  #include <drm/drmP.h>
>  #include <drm/i915_drm.h>
>  #include "i915_drv.h"
> +#include "intel_mocs.h"
>  
>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf,
>   *
>   * Return: non-zero if the ringbuffer is not ready to be written to.
>   */
> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>  				    struct intel_context *ctx, int num_dwords)
>  {
>  	struct intel_engine_cs *ring = ringbuf->ring;
> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct intel_engine_cs *ring,
>  	if (ret)
>  		return ret;
>  
> +	/*
> +	 * Failing to program the MOCS is non-fatal.The system will not
> +	 * run at peak performance. So generate a warning and carry on.
> +	 */
> +	if (gen9_program_mocs(ring, ctx) != 0)
> +		DRM_ERROR("MOCS failed to program: expect performance issues.");
> +
>  	return intel_lr_context_render_state_init(ring, ctx);
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
> index 04d3a6d..dbbd6af 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.h
> +++ b/drivers/gpu/drm/i915/intel_lrc.h
> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>  
>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>  				  struct intel_context *ctx);
> +
> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
> +				    struct intel_context *ctx, int num_dwords);
> +
>  /**
>   * intel_logical_ring_advance() - advance the ringbuffer tail
>   * @ringbuf: Ringbuffer to advance.
> diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c
> new file mode 100644
> index 0000000..7c09e67
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_mocs.c
> @@ -0,0 +1,373 @@
> +/*
> + * Copyright (c) 2015 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions: *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + * Authors:
> + *    Peter Antoine <peter.antoine@intel.com>
> + */
> +
> +#include "intel_mocs.h"
> +#include "intel_lrc.h"
> +#include "intel_ringbuffer.h"
> +
> +/* structures required */
> +struct drm_i915_mocs_entry {
> +	u32	control_value;
> +	u16	l3cc_value;
> +};
> +
> +struct drm_i915_mocs_table {
> +	u32					size;
> +	const struct drm_i915_mocs_entry	*table;
> +};
> +
> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
> +#define	MOCS_CACHEABILITY(value)	(value << 0)
> +#define	MOCS_TGT_CACHE(value)		(value << 2)
> +#define	MOCS_LRUM(value)		(value << 4)
> +#define	MOCS_AOM(value)			(value << 6)
> +#define	MOCS_LECC_ESC(value)		(value << 7)
> +#define	MOCS_LECC_SCC(value)		(value << 8)
> +#define	MOC_PFM(value)			(value << 11)
> +#define	MOCS_SCF(value)			(value << 14)
> +
> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */
> +#define	MOCS_ESC(value)			(value << 0)
> +#define	MOCS_SCC(value)			(value << 1)
> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
> +
> +/* Helper defines */
> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program */
> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd */
> +
> +/* EDRAM Caching options */
> +#define EDRAM_PAGETABLE		(0)
> +#define EDRAM_UC		(1)
> +#define EDRAM_RESERVED		(2)

According to the BSpec this is WT rather than reserved?

> +#define EDRAM_WB		(3)
> +
> +/* L3 Caching options */
> +#define L3_DIRECT		(0)
> +#define L3_UC			(1)
> +#define L3_RESERVED		(2)
> +#define L3_WB			(3)
> +
> +/* target cache */
> +#define ELLC			(0)

BSpec says that this is "Use TC/LRU controls from page table", but upon
a closer look it seems like the BSpec is wrong and your patch is
correct.  Can you confirm that this is what you intended?

> +#define LLC			(1)
> +#define LLC_ELLC		(2)
> +
> +/*
> + * MOCS tables
> + *
> + * These are the MOCS tables that are programmed across all the rings.
> + * The control value is programmed to all the rings that support the
> + * MOCS registers. While the l3cc_values are only programmed to the
> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
> + *
> + * NOTE: These tables MUST start with being uncached and the length MUST be
> + *       less than 63 as the last two registers are reserved by the hardware.
> + */
> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
> +	 /* {0x00000009, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x0000003b, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000039, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000017, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000017, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000019, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000037, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000037, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x0000003b, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +};

Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE, L3CC=WB,
everything else unset, I'll reply with a userspace patch making use of
your change if you add such an entry.

Another thing worth mentioning is that entries 0, 2 and 5 seem to do the
same thing suspiciously, the only difference is the LRUM field which
AFAIK doesn't have any effect for LeCC=UC.  Is my understanding correct?

> +
> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
> +	 /* {0x00000001, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000005, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000005, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000017, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000017, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000019, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x00000037, 0x0030} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
> +	 /* {0x00000037, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +	 /* {0x0000003b, 0x0010} */
> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
> +		MOC_PFM(0) | MOCS_SCF(0)),
> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
> +};
> +

Wouldn't it be a good idea to have BXT's entries match SKL's for a given
index?  The TC, LeCC and LRUM settings you do here arguably don't have
any effect on BXT, L3CC does but it doesn't match SKL's setting for
entries 1 and 2.  Is there any reason for this?

Other than that looks good.

> +/**
> + * get_mocs_settings
> + *
> + * 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
> + * to be programmed and if they need to be programmed.
> + *
> + * If the return values is false then the registers do not need programming.
> + */
> +static bool get_mocs_settings(struct drm_device *dev,
> +			      struct drm_i915_mocs_table *table) {
> +	bool	result = false;
> +
> +	if (IS_SKYLAKE(dev)) {
> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
> +		table->table = skylake_mocs_table;
> +		result = true;
> +	} else if (IS_BROXTON(dev)) {
> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
> +		table->table = broxton_mocs_table;
> +		result = true;
> +	} else {
> +		/* Platform that should have a MOCS table does not */
> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
> +	}
> +
> +	return result;
> +}
> +
> +/**
> + * emit_mocs_control_table() - emit the mocs control table
> + * @ringbuf:	DRM device.
> + * @table:	The values to program into the control regs.
> + * @reg_base:	The base for the Engine that needs to be programmed.
> + *
> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
> + * given table starting at the given address.
> + *
> + * Return: Nothing.
> + */
> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
> +				    struct drm_i915_mocs_table *table,
> +				    u32 reg_base)
> +{
> +	unsigned int index;
> +
> +	intel_logical_ring_emit(ringbuf,
> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
> +
> +	for (index = 0; index < table->size; index++) {
> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
> +		intel_logical_ring_emit(ringbuf,
> +					table->table[index].control_value);
> +	}
> +
> +	/*
> +	 * Ok, now set the unused entries to uncached. These entries are
> +	 * officially undefined and no contact is given for the contents and
> +	 * settings is given for these entries.
> +	 *
> +	 * Entry 0 in the table is uncached - so we are just written that
> +	 * value to all the used entries.
> +	 */
> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
> +		intel_logical_ring_emit(ringbuf, table->table[0].control_value);
> +	}
> +
> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
> +}
> +
> +/**
> + * emit_mocs_l3cc_table() - emit the mocs control table
> + * @ringbuf:	DRM device.
> + * @table:	The values to program into the control regs.
> + *
> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
> + * given table starting at the given address. This register set is  programmed
> + * in pairs.
> + *
> + * Return: Nothing.
> + */
> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
> +			 struct drm_i915_mocs_table *table) {
> +	unsigned int count;
> +	unsigned int i;
> +	u32 value;
> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
> +			((table->table[0].l3cc_value & 0xffff) << 16);
> +
> +	intel_logical_ring_emit(ringbuf,
> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
> +
> +	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);
> +
> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
> +		intel_logical_ring_emit(ringbuf, value);
> +
> +		value = filler;
> +	}
> +
> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
> +}
> +
> +/*
> + * gen9_program_mocs() - program the MOCS register.
> + *
> + * ring:	The ring that the programming batch will be run in.
> + * ctx:		The intel_context to be used.
> + *
> + * This function will emit a batch buffer with the values required for
> + * programming the MOCS register values for all the currently supported
> + * rings.
> + *
> + * These registers are partially stored in the RCS context, so they are
> + * emitted at the same time so that when a context is created these registers
> + * are set up. These registers have to be emitted into the start of the
> + * context as setting the ELSP will re-init some of these registers back
> + * to the hw values.
> + *
> + * Return: 0 on success, otherwise the error status.
> + */
> +int gen9_program_mocs(struct intel_engine_cs *ring,
> +			  struct intel_context *ctx)
> +{
> +	int ret = 0;
> +
> +	struct drm_i915_mocs_table t;
> +	struct drm_device *dev = ring->dev;
> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
> +
> +	if (get_mocs_settings(dev, &t)) {
> +		u32 table_size;
> +
> +		/*
> +		 * OK. For each supported ring:
> +		 *  number of mocs entries * 2 dwords for each control_value
> +		 *  plus number of mocs entries /2 dwords for l3cc values.
> +		 *
> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
> +		 *  and the l3cc programming.
> +		 */
> +		table_size = GEN9_NUM_MOCS_RINGS *
> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
> +				GEN9_NUM_MOCS_ENTRIES + 2;
> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
> +		if (ret) {
> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret);
> +			return ret;
> +		}
> +
> +		/* program the control registers */
> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
> +
> +		/* now program the l3cc registers */
> +		emit_mocs_l3cc_table(ringbuf, &t);
> +
> +		intel_logical_ring_advance(ringbuf);
> +
> +		DRM_DEBUG("MOCS: Table set in Context\n");
> +	} else {
> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
> +	}
> +
> +	return ret;
> +}
> +
> diff --git a/drivers/gpu/drm/i915/intel_mocs.h b/drivers/gpu/drm/i915/intel_mocs.h
> new file mode 100644
> index 0000000..e2780ce
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_mocs.h
> @@ -0,0 +1,64 @@
> +/*
> + * Copyright (c) 2015 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + * Authors:
> + *    Peter Antoine <peter.antoine@intel.com>
> + */
> +
> +#ifndef INTEL_MOCS_H
> +#define INTEL_MOCS_H
> +
> +/**
> + * DOC: Memory Objects Control State (MOCS)
> + *
> + * Motivation:
> + * In previous Gens the MOCS settings was a value that was set by user land as
> + * part of the batch. In Gen9 this has changed to be a single table (per ring)
> + * that all batches now reference by index instead of programming the MOCS
> + * directly.
> + *
> + * The one wrinkle in this is that only PART of the MOCS tables are included
> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - LNCFCMOCS32
> + * registers). The rest are not (the settings for the other rings).
> + *
> + * This table needs to be set at system start-up because the way the table
> + * interacts with the contexts and the GmmLib interface.
> + *
> + *
> + * Implementation:
> + *
> + * The table is programmed on a platform basis from a table that is generated
> + * from the one that has been agreed by the different responsible parties. This
> + * tables (one per supported platform) is defined in intel_mocs.c and is
> + * programmed in the first batch after the context is loaded (with the hardware
> + * workarounds). This will then let the usual context handling keep the MOCS in
> + * step.
> + */
> +
> +#include <drm/drmP.h>
> +#include "i915_drv.h"
> +
> +int gen9_program_mocs(struct intel_engine_cs *ring,
> +			struct intel_context *ctx);
> +
> +#endif
> +
> -- 
> 1.9.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Bish, Jim June 25, 2015, 9:06 p.m. UTC | #11
On 06/17/2015 08:19 AM, Peter Antoine wrote:
> This change adds the programming of the MOCS registers to the gen 9+

> platforms. This change set programs the MOCS register values to a set

> of values that are defined to be optimal.

> 

> It creates a fixed register set that is programmed across the different

> engines so that all engines have the same table. This is done as the

> main RCS context only holds the registers for itself and the shared

> L3 values. By trying to keep the registers consistent across the

> different engines it should make the programming for the registers

> consistent.

> 

> v2:

> -'static const' for private data structures and style changes.(Matt Turner)

> v3:

> - Make the tables "slightly" more readable. (Damien Lespiau)

> - Updated tables fix performance regression.

> v4:

> - Code formatting. (Chris Wilson)

> - re-privatised mocs code. (Daniel Vetter)

> 

> Signed-off-by: Peter Antoine <peter.antoine@intel.com>

> ---

>  drivers/gpu/drm/i915/Makefile     |   1 +

>  drivers/gpu/drm/i915/i915_reg.h   |   9 +

>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-

>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +

>  drivers/gpu/drm/i915/intel_mocs.c | 373 ++++++++++++++++++++++++++++++++++++++

>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++

>  6 files changed, 460 insertions(+), 1 deletion(-)

>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c

>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h

> 

> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile

> index b7ddf48..c781e19 100644

> --- a/drivers/gpu/drm/i915/Makefile

> +++ b/drivers/gpu/drm/i915/Makefile

> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \

>  	  i915_irq.o \

>  	  i915_trace_points.o \

>  	  intel_lrc.o \

> +	  intel_mocs.o \

>  	  intel_ringbuffer.o \

>  	  intel_uncore.o

>  

> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h

> index 7213224..3a435b5 100644

> --- a/drivers/gpu/drm/i915/i915_reg.h

> +++ b/drivers/gpu/drm/i915/i915_reg.h

> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {

>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)

>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)

>  

> +/* MOCS (Memory Object Control State) registers */

> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control base */

> +

> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base register*/

> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base register*/

> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base register*/

> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/

> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base register*/

> +

>  #endif /* _I915_REG_H_ */

> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c

> index 9f5485d..73b919d 100644

> --- a/drivers/gpu/drm/i915/intel_lrc.c

> +++ b/drivers/gpu/drm/i915/intel_lrc.c

> @@ -135,6 +135,7 @@

>  #include <drm/drmP.h>

>  #include <drm/i915_drm.h>

>  #include "i915_drv.h"

> +#include "intel_mocs.h"

>  

>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)

>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)

> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf,

>   *

>   * Return: non-zero if the ringbuffer is not ready to be written to.

>   */

> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,

> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,

>  				    struct intel_context *ctx, int num_dwords)

>  {

>  	struct intel_engine_cs *ring = ringbuf->ring;

> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct intel_engine_cs *ring,

>  	if (ret)

>  		return ret;

>  

> +	/*

> +	 * Failing to program the MOCS is non-fatal.The system will not

> +	 * run at peak performance. So generate a warning and carry on.

> +	 */

> +	if (gen9_program_mocs(ring, ctx) != 0)

> +		DRM_ERROR("MOCS failed to program: expect performance issues.");

> +

>  	return intel_lr_context_render_state_init(ring, ctx);

>  }

>  

> diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h

> index 04d3a6d..dbbd6af 100644

> --- a/drivers/gpu/drm/i915/intel_lrc.h

> +++ b/drivers/gpu/drm/i915/intel_lrc.h

> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);

>  

>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,

>  				  struct intel_context *ctx);

> +

> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,

> +				    struct intel_context *ctx, int num_dwords);

> +

>  /**

>   * intel_logical_ring_advance() - advance the ringbuffer tail

>   * @ringbuf: Ringbuffer to advance.

> diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c

> new file mode 100644

> index 0000000..7c09e67

> --- /dev/null

> +++ b/drivers/gpu/drm/i915/intel_mocs.c

> @@ -0,0 +1,373 @@

> +/*

> + * Copyright (c) 2015 Intel Corporation

> + *

> + * Permission is hereby granted, free of charge, to any person obtaining a

> + * copy of this software and associated documentation files (the "Software"),

> + * to deal in the Software without restriction, including without limitation

> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,

> + * and/or sell copies of the Software, and to permit persons to whom the

> + * Software is furnished to do so, subject to the following conditions: *

> + * The above copyright notice and this permission notice (including the next

> + * paragraph) shall be included in all copies or substantial portions of the

> + * Software.

> + *

> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL

> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

> + * SOFTWARE.

> + *

> + * Authors:

> + *    Peter Antoine <peter.antoine@intel.com>

> + */

> +

> +#include "intel_mocs.h"

> +#include "intel_lrc.h"

> +#include "intel_ringbuffer.h"

> +

> +/* structures required */

> +struct drm_i915_mocs_entry {

> +	u32	control_value;

> +	u16	l3cc_value;

> +};

> +

> +struct drm_i915_mocs_table {

> +	u32					size;

> +	const struct drm_i915_mocs_entry	*table;

> +};

> +

> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */

> +#define	MOCS_CACHEABILITY(value)	(value << 0)

> +#define	MOCS_TGT_CACHE(value)		(value << 2)

> +#define	MOCS_LRUM(value)		(value << 4)

> +#define	MOCS_AOM(value)			(value << 6)

> +#define	MOCS_LECC_ESC(value)		(value << 7)

> +#define	MOCS_LECC_SCC(value)		(value << 8)

> +#define	MOC_PFM(value)			(value << 11)

> +#define	MOCS_SCF(value)			(value << 14)

> +

> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */

> +#define	MOCS_ESC(value)			(value << 0)

> +#define	MOCS_SCC(value)			(value << 1)

> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)

> +

> +/* Helper defines */

> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program */

> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd */

spec shows top two entries as reserved for hardware.  please double check
and update
> +

> +/* EDRAM Caching options */

> +#define EDRAM_PAGETABLE		(0)

> +#define EDRAM_UC		(1)

> +#define EDRAM_RESERVED		(2)

> +#define EDRAM_WB		(3)

> +

> +/* L3 Caching options */

> +#define L3_DIRECT		(0)

> +#define L3_UC			(1)

> +#define L3_RESERVED		(2)

> +#define L3_WB			(3)

> +

> +/* target cache */

> +#define ELLC			(0)

> +#define LLC			(1)

> +#define LLC_ELLC		(2)

> +

> +/*

> + * MOCS tables

> + *

> + * These are the MOCS tables that are programmed across all the rings.

> + * The control value is programmed to all the rings that support the

> + * MOCS registers. While the l3cc_values are only programmed to the

> + * LNCFCMOCS0 - LNCFCMOCS32 registers.

> + *

> + * NOTE: These tables MUST start with being uncached and the length MUST be

> + *       less than 63 as the last two registers are reserved by the hardware.

> + */

> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {

> +	 /* {0x00000009, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |

> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +	 /* {0x0000003b, 0x0030} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |

> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},

> +	 /* {0x00000039, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |

> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +	 /* {0x00000017, 0x0030} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |

> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},

> +	 /* {0x00000017, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |

> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +	 /* {0x00000019, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |

> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +	 /* {0x00000037, 0x0030} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |

> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},

> +	 /* {0x00000037, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |

> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +	 /* {0x0000003b, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |

> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +};

> +

please add comment above the broxton table to clarify the use of LLC in the 
MOCS_TGT_CACHE as not applicable for broxton.

> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {

> +	 /* {0x00000001, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |

> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +	 /* {0x00000005, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |

> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +	 /* {0x00000005, 0x0030} */

> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |

> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},

> +	 /* {0x00000017, 0x0030} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |

> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},

> +	 /* {0x00000017, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |

> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +	 /* {0x00000019, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |

> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +	 /* {0x00000037, 0x0030} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |

> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},

> +	 /* {0x00000037, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |

> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +	 /* {0x0000003b, 0x0010} */

> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |

> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |

> +		MOC_PFM(0) | MOCS_SCF(0)),

> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},

> +};

> +

> +/**

> + * get_mocs_settings

> + *

> + * 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

> + * to be programmed and if they need to be programmed.

> + *

> + * If the return values is false then the registers do not need programming.

> + */

> +static bool get_mocs_settings(struct drm_device *dev,

> +			      struct drm_i915_mocs_table *table) {

> +	bool	result = false;

> +

> +	if (IS_SKYLAKE(dev)) {

> +		table->size  = ARRAY_SIZE(skylake_mocs_table);

> +		table->table = skylake_mocs_table;

> +		result = true;

> +	} else if (IS_BROXTON(dev)) {

> +		table->size  = ARRAY_SIZE(broxton_mocs_table);

> +		table->table = broxton_mocs_table;

> +		result = true;

> +	} else {

> +		/* Platform that should have a MOCS table does not */

> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);

> +	}

> +

> +	return result;

> +}

> +

> +/**

> + * emit_mocs_control_table() - emit the mocs control table

> + * @ringbuf:	DRM device.

> + * @table:	The values to program into the control regs.

> + * @reg_base:	The base for the Engine that needs to be programmed.

> + *

> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the

> + * given table starting at the given address.

> + *

> + * Return: Nothing.

> + */

> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,

> +				    struct drm_i915_mocs_table *table,

> +				    u32 reg_base)

> +{

> +	unsigned int index;

> +

> +	intel_logical_ring_emit(ringbuf,

> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));

> +

> +	for (index = 0; index < table->size; index++) {

> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));

> +		intel_logical_ring_emit(ringbuf,

> +					table->table[index].control_value);

> +	}

> +

> +	/*

> +	 * Ok, now set the unused entries to uncached. These entries are

> +	 * officially undefined and no contact is given for the contents and

> +	 * settings is given for these entries.

> +	 *

> +	 * Entry 0 in the table is uncached - so we are just written that

> +	 * value to all the used entries.

> +	 */

> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {

> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));

> +		intel_logical_ring_emit(ringbuf, table->table[0].control_value);

> +	}

> +

> +	intel_logical_ring_emit(ringbuf, MI_NOOP);

> +}

> +

> +/**

> + * emit_mocs_l3cc_table() - emit the mocs control table

> + * @ringbuf:	DRM device.

> + * @table:	The values to program into the control regs.

> + *

> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the

> + * given table starting at the given address. This register set is  programmed

> + * in pairs.

> + *

> + * Return: Nothing.

> + */

> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,

> +			 struct drm_i915_mocs_table *table) {

> +	unsigned int count;

> +	unsigned int i;

> +	u32 value;

> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |

> +			((table->table[0].l3cc_value & 0xffff) << 16);

> +

> +	intel_logical_ring_emit(ringbuf,

> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));

> +

> +	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);

> +

> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));

> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {

> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));

> +		intel_logical_ring_emit(ringbuf, value);

> +

> +		value = filler;

> +	}

> +

> +	intel_logical_ring_emit(ringbuf, MI_NOOP);

> +}

> +

> +/*

> + * gen9_program_mocs() - program the MOCS register.

> + *

> + * ring:	The ring that the programming batch will be run in.

> + * ctx:		The intel_context to be used.

> + *

> + * This function will emit a batch buffer with the values required for

> + * programming the MOCS register values for all the currently supported

> + * rings.

> + *

> + * These registers are partially stored in the RCS context, so they are

> + * emitted at the same time so that when a context is created these registers

> + * are set up. These registers have to be emitted into the start of the

> + * context as setting the ELSP will re-init some of these registers back

> + * to the hw values.

> + *

> + * Return: 0 on success, otherwise the error status.

> + */

> +int gen9_program_mocs(struct intel_engine_cs *ring,

> +			  struct intel_context *ctx)

> +{

> +	int ret = 0;

> +

> +	struct drm_i915_mocs_table t;

> +	struct drm_device *dev = ring->dev;

> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;

> +

> +	if (get_mocs_settings(dev, &t)) {

> +		u32 table_size;

> +

> +		/*

> +		 * OK. For each supported ring:

> +		 *  number of mocs entries * 2 dwords for each control_value

> +		 *  plus number of mocs entries /2 dwords for l3cc values.

> +		 *

> +		 *  Plus 1 for the load command and 1 for the NOOP per ring

> +		 *  and the l3cc programming.

> +		 */

> +		table_size = GEN9_NUM_MOCS_RINGS *

> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +

> +				GEN9_NUM_MOCS_ENTRIES + 2;

> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);

> +		if (ret) {

> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret);

> +			return ret;

> +		}

> +

> +		/* program the control registers */

> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);

> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);

> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);

> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);

> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);

> +

> +		/* now program the l3cc registers */

> +		emit_mocs_l3cc_table(ringbuf, &t);

> +

> +		intel_logical_ring_advance(ringbuf);

> +

> +		DRM_DEBUG("MOCS: Table set in Context\n");

> +	} else {

> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");

> +	}

> +

> +	return ret;

> +}

> +

> diff --git a/drivers/gpu/drm/i915/intel_mocs.h b/drivers/gpu/drm/i915/intel_mocs.h

> new file mode 100644

> index 0000000..e2780ce

> --- /dev/null

> +++ b/drivers/gpu/drm/i915/intel_mocs.h

> @@ -0,0 +1,64 @@

> +/*

> + * Copyright (c) 2015 Intel Corporation

> + *

> + * Permission is hereby granted, free of charge, to any person obtaining a

> + * copy of this software and associated documentation files (the "Software"),

> + * to deal in the Software without restriction, including without limitation

> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,

> + * and/or sell copies of the Software, and to permit persons to whom the

> + * Software is furnished to do so, subject to the following conditions:

> + *

> + * The above copyright notice and this permission notice (including the next

> + * paragraph) shall be included in all copies or substantial portions of the

> + * Software.

> + *

> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL

> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

> + * SOFTWARE.

> + *

> + * Authors:

> + *    Peter Antoine <peter.antoine@intel.com>

> + */

> +

> +#ifndef INTEL_MOCS_H

> +#define INTEL_MOCS_H

> +

> +/**

> + * DOC: Memory Objects Control State (MOCS)

> + *

> + * Motivation:

> + * In previous Gens the MOCS settings was a value that was set by user land as

> + * part of the batch. In Gen9 this has changed to be a single table (per ring)

> + * that all batches now reference by index instead of programming the MOCS

> + * directly.

> + *

> + * The one wrinkle in this is that only PART of the MOCS tables are included

> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - LNCFCMOCS32

> + * registers). The rest are not (the settings for the other rings).

> + *

> + * This table needs to be set at system start-up because the way the table

> + * interacts with the contexts and the GmmLib interface.

> + *

> + *

> + * Implementation:

> + *

> + * The table is programmed on a platform basis from a table that is generated

> + * from the one that has been agreed by the different responsible parties. This

> + * tables (one per supported platform) is defined in intel_mocs.c and is

> + * programmed in the first batch after the context is loaded (with the hardware

> + * workarounds). This will then let the usual context handling keep the MOCS in

> + * step.

> + */

> +

> +#include <drm/drmP.h>

> +#include "i915_drv.h"

> +

> +int gen9_program_mocs(struct intel_engine_cs *ring,

> +			struct intel_context *ctx);

> +

> +#endif

> +

>
Peter Antoine June 29, 2015, 7:09 a.m. UTC | #12
On Thu, 25 Jun 2015, Bish, Jim wrote:

>
>
> On 06/17/2015 08:19 AM, Peter Antoine wrote:
>> This change adds the programming of the MOCS registers to the gen 9+
>> platforms. This change set programs the MOCS register values to a set
>> of values that are defined to be optimal.
>>
>> It creates a fixed register set that is programmed across the different
>> engines so that all engines have the same table. This is done as the
>> main RCS context only holds the registers for itself and the shared
>> L3 values. By trying to keep the registers consistent across the
>> different engines it should make the programming for the registers
>> consistent.
>>
>> v2:
>> -'static const' for private data structures and style changes.(Matt Turner)
>> v3:
>> - Make the tables "slightly" more readable. (Damien Lespiau)
>> - Updated tables fix performance regression.
>> v4:
>> - Code formatting. (Chris Wilson)
>> - re-privatised mocs code. (Daniel Vetter)
>>
>> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
>> ---
>>  drivers/gpu/drm/i915/Makefile     |   1 +
>>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>>  drivers/gpu/drm/i915/intel_mocs.c | 373 ++++++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>>  6 files changed, 460 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>>
>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>> index b7ddf48..c781e19 100644
>> --- a/drivers/gpu/drm/i915/Makefile
>> +++ b/drivers/gpu/drm/i915/Makefile
>> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>>  	  i915_irq.o \
>>  	  i915_trace_points.o \
>>  	  intel_lrc.o \
>> +	  intel_mocs.o \
>>  	  intel_ringbuffer.o \
>>  	  intel_uncore.o
>>
>> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
>> index 7213224..3a435b5 100644
>> --- a/drivers/gpu/drm/i915/i915_reg.h
>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>>
>> +/* MOCS (Memory Object Control State) registers */
>> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control base */
>> +
>> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base register*/
>> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base register*/
>> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base register*/
>> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
>> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base register*/
>> +
>>  #endif /* _I915_REG_H_ */
>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
>> index 9f5485d..73b919d 100644
>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>> @@ -135,6 +135,7 @@
>>  #include <drm/drmP.h>
>>  #include <drm/i915_drm.h>
>>  #include "i915_drv.h"
>> +#include "intel_mocs.h"
>>
>>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
>> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf,
>>   *
>>   * Return: non-zero if the ringbuffer is not ready to be written to.
>>   */
>> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>  				    struct intel_context *ctx, int num_dwords)
>>  {
>>  	struct intel_engine_cs *ring = ringbuf->ring;
>> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct intel_engine_cs *ring,
>>  	if (ret)
>>  		return ret;
>>
>> +	/*
>> +	 * Failing to program the MOCS is non-fatal.The system will not
>> +	 * run at peak performance. So generate a warning and carry on.
>> +	 */
>> +	if (gen9_program_mocs(ring, ctx) != 0)
>> +		DRM_ERROR("MOCS failed to program: expect performance issues.");
>> +
>>  	return intel_lr_context_render_state_init(ring, ctx);
>>  }
>>
>> diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
>> index 04d3a6d..dbbd6af 100644
>> --- a/drivers/gpu/drm/i915/intel_lrc.h
>> +++ b/drivers/gpu/drm/i915/intel_lrc.h
>> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>>
>>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>>  				  struct intel_context *ctx);
>> +
>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>> +				    struct intel_context *ctx, int num_dwords);
>> +
>>  /**
>>   * intel_logical_ring_advance() - advance the ringbuffer tail
>>   * @ringbuf: Ringbuffer to advance.
>> diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c
>> new file mode 100644
>> index 0000000..7c09e67
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/intel_mocs.c
>> @@ -0,0 +1,373 @@
>> +/*
>> + * Copyright (c) 2015 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions: *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>> + * SOFTWARE.
>> + *
>> + * Authors:
>> + *    Peter Antoine <peter.antoine@intel.com>
>> + */
>> +
>> +#include "intel_mocs.h"
>> +#include "intel_lrc.h"
>> +#include "intel_ringbuffer.h"
>> +
>> +/* structures required */
>> +struct drm_i915_mocs_entry {
>> +	u32	control_value;
>> +	u16	l3cc_value;
>> +};
>> +
>> +struct drm_i915_mocs_table {
>> +	u32					size;
>> +	const struct drm_i915_mocs_entry	*table;
>> +};
>> +
>> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
>> +#define	MOCS_CACHEABILITY(value)	(value << 0)
>> +#define	MOCS_TGT_CACHE(value)		(value << 2)
>> +#define	MOCS_LRUM(value)		(value << 4)
>> +#define	MOCS_AOM(value)			(value << 6)
>> +#define	MOCS_LECC_ESC(value)		(value << 7)
>> +#define	MOCS_LECC_SCC(value)		(value << 8)
>> +#define	MOC_PFM(value)			(value << 11)
>> +#define	MOCS_SCF(value)			(value << 14)
>> +
>> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */
>> +#define	MOCS_ESC(value)			(value << 0)
>> +#define	MOCS_SCC(value)			(value << 1)
>> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
>> +
>> +/* Helper defines */
>> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program */
>> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd */
> spec shows top two entries as reserved for hardware.  please double check
> and update
You are right. The code does something nasty and relies on the rounding to 
get this right. Tidied up.
>> +
>> +/* EDRAM Caching options */
>> +#define EDRAM_PAGETABLE		(0)
>> +#define EDRAM_UC		(1)
>> +#define EDRAM_RESERVED		(2)
>> +#define EDRAM_WB		(3)
>> +
>> +/* L3 Caching options */
>> +#define L3_DIRECT		(0)
>> +#define L3_UC			(1)
>> +#define L3_RESERVED		(2)
>> +#define L3_WB			(3)
>> +
>> +/* target cache */
>> +#define ELLC			(0)
>> +#define LLC			(1)
>> +#define LLC_ELLC		(2)
>> +
>> +/*
>> + * MOCS tables
>> + *
>> + * These are the MOCS tables that are programmed across all the rings.
>> + * The control value is programmed to all the rings that support the
>> + * MOCS registers. While the l3cc_values are only programmed to the
>> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
>> + *
>> + * NOTE: These tables MUST start with being uncached and the length MUST be
>> + *       less than 63 as the last two registers are reserved by the hardware.
>> + */
>> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
>> +	 /* {0x00000009, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x0000003b, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000039, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000017, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000017, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000019, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000037, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000037, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x0000003b, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +};
>> +
> please add comment above the broxton table to clarify the use of LLC in the
> MOCS_TGT_CACHE as not applicable for broxton.
Added comments.
>
>> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
>> +	 /* {0x00000001, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000005, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000005, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000017, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000017, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000019, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000037, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000037, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x0000003b, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +};
>> +
>> +/**
>> + * get_mocs_settings
>> + *
>> + * 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
>> + * to be programmed and if they need to be programmed.
>> + *
>> + * If the return values is false then the registers do not need programming.
>> + */
>> +static bool get_mocs_settings(struct drm_device *dev,
>> +			      struct drm_i915_mocs_table *table) {
>> +	bool	result = false;
>> +
>> +	if (IS_SKYLAKE(dev)) {
>> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
>> +		table->table = skylake_mocs_table;
>> +		result = true;
>> +	} else if (IS_BROXTON(dev)) {
>> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
>> +		table->table = broxton_mocs_table;
>> +		result = true;
>> +	} else {
>> +		/* Platform that should have a MOCS table does not */
>> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
>> +	}
>> +
>> +	return result;
>> +}
>> +
>> +/**
>> + * emit_mocs_control_table() - emit the mocs control table
>> + * @ringbuf:	DRM device.
>> + * @table:	The values to program into the control regs.
>> + * @reg_base:	The base for the Engine that needs to be programmed.
>> + *
>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>> + * given table starting at the given address.
>> + *
>> + * Return: Nothing.
>> + */
>> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
>> +				    struct drm_i915_mocs_table *table,
>> +				    u32 reg_base)
>> +{
>> +	unsigned int index;
>> +
>> +	intel_logical_ring_emit(ringbuf,
>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
>> +
>> +	for (index = 0; index < table->size; index++) {
>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>> +		intel_logical_ring_emit(ringbuf,
>> +					table->table[index].control_value);
>> +	}
>> +
>> +	/*
>> +	 * Ok, now set the unused entries to uncached. These entries are
>> +	 * officially undefined and no contact is given for the contents and
>> +	 * settings is given for these entries.
>> +	 *
>> +	 * Entry 0 in the table is uncached - so we are just written that
>> +	 * value to all the used entries.
>> +	 */
>> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>> +		intel_logical_ring_emit(ringbuf, table->table[0].control_value);
>> +	}
>> +
>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>> +}
>> +
>> +/**
>> + * emit_mocs_l3cc_table() - emit the mocs control table
>> + * @ringbuf:	DRM device.
>> + * @table:	The values to program into the control regs.
>> + *
>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>> + * given table starting at the given address. This register set is  programmed
>> + * in pairs.
>> + *
>> + * Return: Nothing.
>> + */
>> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
>> +			 struct drm_i915_mocs_table *table) {
>> +	unsigned int count;
>> +	unsigned int i;
>> +	u32 value;
>> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
>> +			((table->table[0].l3cc_value & 0xffff) << 16);
>> +
>> +	intel_logical_ring_emit(ringbuf,
>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
>> +
>> +	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);
>> +
>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>> +		intel_logical_ring_emit(ringbuf, value);
>> +
>> +		value = filler;
>> +	}
>> +
>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>> +}
>> +
>> +/*
>> + * gen9_program_mocs() - program the MOCS register.
>> + *
>> + * ring:	The ring that the programming batch will be run in.
>> + * ctx:		The intel_context to be used.
>> + *
>> + * This function will emit a batch buffer with the values required for
>> + * programming the MOCS register values for all the currently supported
>> + * rings.
>> + *
>> + * These registers are partially stored in the RCS context, so they are
>> + * emitted at the same time so that when a context is created these registers
>> + * are set up. These registers have to be emitted into the start of the
>> + * context as setting the ELSP will re-init some of these registers back
>> + * to the hw values.
>> + *
>> + * Return: 0 on success, otherwise the error status.
>> + */
>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>> +			  struct intel_context *ctx)
>> +{
>> +	int ret = 0;
>> +
>> +	struct drm_i915_mocs_table t;
>> +	struct drm_device *dev = ring->dev;
>> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
>> +
>> +	if (get_mocs_settings(dev, &t)) {
>> +		u32 table_size;
>> +
>> +		/*
>> +		 * OK. For each supported ring:
>> +		 *  number of mocs entries * 2 dwords for each control_value
>> +		 *  plus number of mocs entries /2 dwords for l3cc values.
>> +		 *
>> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
>> +		 *  and the l3cc programming.
>> +		 */
>> +		table_size = GEN9_NUM_MOCS_RINGS *
>> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
>> +				GEN9_NUM_MOCS_ENTRIES + 2;
>> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
>> +		if (ret) {
>> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret);
>> +			return ret;
>> +		}
>> +
>> +		/* program the control registers */
>> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
>> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
>> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
>> +
>> +		/* now program the l3cc registers */
>> +		emit_mocs_l3cc_table(ringbuf, &t);
>> +
>> +		intel_logical_ring_advance(ringbuf);
>> +
>> +		DRM_DEBUG("MOCS: Table set in Context\n");
>> +	} else {
>> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> diff --git a/drivers/gpu/drm/i915/intel_mocs.h b/drivers/gpu/drm/i915/intel_mocs.h
>> new file mode 100644
>> index 0000000..e2780ce
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/intel_mocs.h
>> @@ -0,0 +1,64 @@
>> +/*
>> + * Copyright (c) 2015 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>> + * SOFTWARE.
>> + *
>> + * Authors:
>> + *    Peter Antoine <peter.antoine@intel.com>
>> + */
>> +
>> +#ifndef INTEL_MOCS_H
>> +#define INTEL_MOCS_H
>> +
>> +/**
>> + * DOC: Memory Objects Control State (MOCS)
>> + *
>> + * Motivation:
>> + * In previous Gens the MOCS settings was a value that was set by user land as
>> + * part of the batch. In Gen9 this has changed to be a single table (per ring)
>> + * that all batches now reference by index instead of programming the MOCS
>> + * directly.
>> + *
>> + * The one wrinkle in this is that only PART of the MOCS tables are included
>> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - LNCFCMOCS32
>> + * registers). The rest are not (the settings for the other rings).
>> + *
>> + * This table needs to be set at system start-up because the way the table
>> + * interacts with the contexts and the GmmLib interface.
>> + *
>> + *
>> + * Implementation:
>> + *
>> + * The table is programmed on a platform basis from a table that is generated
>> + * from the one that has been agreed by the different responsible parties. This
>> + * tables (one per supported platform) is defined in intel_mocs.c and is
>> + * programmed in the first batch after the context is loaded (with the hardware
>> + * workarounds). This will then let the usual context handling keep the MOCS in
>> + * step.
>> + */
>> +
>> +#include <drm/drmP.h>
>> +#include "i915_drv.h"
>> +
>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>> +			struct intel_context *ctx);
>> +
>> +#endif
>> +
>> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

--
    Peter Antoine (Android Graphics Driver Software Engineer)
    ---------------------------------------------------------------------
    Intel Corporation (UK) Limited
    Registered No. 1134945 (England)
    Registered Office: Pipers Way, Swindon SN3 1RJ
    VAT No: 860 2173 47
Peter Antoine June 29, 2015, 8:21 a.m. UTC | #13
On Thu, 25 Jun 2015, Francisco Jerez wrote:

> Peter Antoine <peter.antoine@intel.com> writes:
>
>> This change adds the programming of the MOCS registers to the gen 9+
>> platforms. This change set programs the MOCS register values to a set
>> of values that are defined to be optimal.
>>
>> It creates a fixed register set that is programmed across the different
>> engines so that all engines have the same table. This is done as the
>> main RCS context only holds the registers for itself and the shared
>> L3 values. By trying to keep the registers consistent across the
>> different engines it should make the programming for the registers
>> consistent.
>>
>> v2:
>> -'static const' for private data structures and style changes.(Matt Turner)
>> v3:
>> - Make the tables "slightly" more readable. (Damien Lespiau)
>> - Updated tables fix performance regression.
>> v4:
>> - Code formatting. (Chris Wilson)
>> - re-privatised mocs code. (Daniel Vetter)
>>
>> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
>> ---
>>  drivers/gpu/drm/i915/Makefile     |   1 +
>>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>>  drivers/gpu/drm/i915/intel_mocs.c | 373 ++++++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>>  6 files changed, 460 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>>
>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>> index b7ddf48..c781e19 100644
>> --- a/drivers/gpu/drm/i915/Makefile
>> +++ b/drivers/gpu/drm/i915/Makefile
>> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>>  	  i915_irq.o \
>>  	  i915_trace_points.o \
>>  	  intel_lrc.o \
>> +	  intel_mocs.o \
>>  	  intel_ringbuffer.o \
>>  	  intel_uncore.o
>>
>> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
>> index 7213224..3a435b5 100644
>> --- a/drivers/gpu/drm/i915/i915_reg.h
>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>>
>> +/* MOCS (Memory Object Control State) registers */
>> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control base */
>> +
>> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base register*/
>> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base register*/
>> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base register*/
>> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
>> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base register*/
>> +
>>  #endif /* _I915_REG_H_ */
>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
>> index 9f5485d..73b919d 100644
>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>> @@ -135,6 +135,7 @@
>>  #include <drm/drmP.h>
>>  #include <drm/i915_drm.h>
>>  #include "i915_drv.h"
>> +#include "intel_mocs.h"
>>
>>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
>> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf,
>>   *
>>   * Return: non-zero if the ringbuffer is not ready to be written to.
>>   */
>> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>  				    struct intel_context *ctx, int num_dwords)
>>  {
>>  	struct intel_engine_cs *ring = ringbuf->ring;
>> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct intel_engine_cs *ring,
>>  	if (ret)
>>  		return ret;
>>
>> +	/*
>> +	 * Failing to program the MOCS is non-fatal.The system will not
>> +	 * run at peak performance. So generate a warning and carry on.
>> +	 */
>> +	if (gen9_program_mocs(ring, ctx) != 0)
>> +		DRM_ERROR("MOCS failed to program: expect performance issues.");
>> +
>>  	return intel_lr_context_render_state_init(ring, ctx);
>>  }
>>
>> diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
>> index 04d3a6d..dbbd6af 100644
>> --- a/drivers/gpu/drm/i915/intel_lrc.h
>> +++ b/drivers/gpu/drm/i915/intel_lrc.h
>> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>>
>>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>>  				  struct intel_context *ctx);
>> +
>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>> +				    struct intel_context *ctx, int num_dwords);
>> +
>>  /**
>>   * intel_logical_ring_advance() - advance the ringbuffer tail
>>   * @ringbuf: Ringbuffer to advance.
>> diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c
>> new file mode 100644
>> index 0000000..7c09e67
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/intel_mocs.c
>> @@ -0,0 +1,373 @@
>> +/*
>> + * Copyright (c) 2015 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions: *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>> + * SOFTWARE.
>> + *
>> + * Authors:
>> + *    Peter Antoine <peter.antoine@intel.com>
>> + */
>> +
>> +#include "intel_mocs.h"
>> +#include "intel_lrc.h"
>> +#include "intel_ringbuffer.h"
>> +
>> +/* structures required */
>> +struct drm_i915_mocs_entry {
>> +	u32	control_value;
>> +	u16	l3cc_value;
>> +};
>> +
>> +struct drm_i915_mocs_table {
>> +	u32					size;
>> +	const struct drm_i915_mocs_entry	*table;
>> +};
>> +
>> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
>> +#define	MOCS_CACHEABILITY(value)	(value << 0)
>> +#define	MOCS_TGT_CACHE(value)		(value << 2)
>> +#define	MOCS_LRUM(value)		(value << 4)
>> +#define	MOCS_AOM(value)			(value << 6)
>> +#define	MOCS_LECC_ESC(value)		(value << 7)
>> +#define	MOCS_LECC_SCC(value)		(value << 8)
>> +#define	MOC_PFM(value)			(value << 11)
>> +#define	MOCS_SCF(value)			(value << 14)
>> +
>> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */
>> +#define	MOCS_ESC(value)			(value << 0)
>> +#define	MOCS_SCC(value)			(value << 1)
>> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
>> +
>> +/* Helper defines */
>> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program */
>> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd */
>> +
>> +/* EDRAM Caching options */
>> +#define EDRAM_PAGETABLE		(0)
>> +#define EDRAM_UC		(1)
>> +#define EDRAM_RESERVED		(2)
>
> According to the BSpec this is WT rather than reserved?a
Just checked the Bspec and you are correct, changing the text.
As well as for the items below.
>
>> +#define EDRAM_WB		(3)
>> +
>> +/* L3 Caching options */
>> +#define L3_DIRECT		(0)
>> +#define L3_UC			(1)
>> +#define L3_RESERVED		(2)
>> +#define L3_WB			(3)
>> +
>> +/* target cache */
>> +#define ELLC			(0)
>
> BSpec says that this is "Use TC/LRU controls from page table", but upon
> a closer look it seems like the BSpec is wrong and your patch is
> correct.  Can you confirm that this is what you intended?
These values look good, they are bits 3:2 for the XXX_MOCS_N registers 
(c800) and friends. 
>
>> +#define LLC			(1)
>> +#define LLC_ELLC		(2)
>> +
>> +/*
>> + * MOCS tables
>> + *
>> + * These are the MOCS tables that are programmed across all the rings.
>> + * The control value is programmed to all the rings that support the
>> + * MOCS registers. While the l3cc_values are only programmed to the
>> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
>> + *
>> + * NOTE: These tables MUST start with being uncached and the length MUST be
>> + *       less than 63 as the last two registers are reserved by the hardware.
>> + */
>> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
>> +	 /* {0x00000009, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x0000003b, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000039, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000017, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000017, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000019, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000037, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000037, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x0000003b, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +};
>
> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE, L3CC=WB,
> everything else unset, I'll reply with a userspace patch making use of
> your change if you add such an entry.
>
> Another thing worth mentioning is that entries 0, 2 and 5 seem to do the
> same thing suspiciously, the only difference is the LRUM field which
> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding correct?
>
These tables are generated via requests and then boiled down to the above. 
So some of the entries are by request. Swings and roundabouts, can remove 
the ones that look redundant but then the tuning that has been done wont 
match. I'll add the new entry at the end of the table.
>> +
>> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
>> +	 /* {0x00000001, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000005, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000005, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000017, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000017, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000019, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x00000037, 0x0030} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>> +	 /* {0x00000037, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +	 /* {0x0000003b, 0x0010} */
>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>> +		MOC_PFM(0) | MOCS_SCF(0)),
>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>> +};
>> +
>
> Wouldn't it be a good idea to have BXT's entries match SKL's for a given
> index?  The TC, LeCC and LRUM settings you do here arguably don't have
> any effect on BXT, L3CC does but it doesn't match SKL's setting for
> entries 1 and 2.  Is there any reason for this?
As mentioned above this table is auto-generated and matches another tuned 
table, simply keeping them the same allows for the tuning to be consistent 
across platforms.

Peter.
>
> Other than that looks good.
>
>> +/**
>> + * get_mocs_settings
>> + *
>> + * 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
>> + * to be programmed and if they need to be programmed.
>> + *
>> + * If the return values is false then the registers do not need programming.
>> + */
>> +static bool get_mocs_settings(struct drm_device *dev,
>> +			      struct drm_i915_mocs_table *table) {
>> +	bool	result = false;
>> +
>> +	if (IS_SKYLAKE(dev)) {
>> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
>> +		table->table = skylake_mocs_table;
>> +		result = true;
>> +	} else if (IS_BROXTON(dev)) {
>> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
>> +		table->table = broxton_mocs_table;
>> +		result = true;
>> +	} else {
>> +		/* Platform that should have a MOCS table does not */
>> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
>> +	}
>> +
>> +	return result;
>> +}
>> +
>> +/**
>> + * emit_mocs_control_table() - emit the mocs control table
>> + * @ringbuf:	DRM device.
>> + * @table:	The values to program into the control regs.
>> + * @reg_base:	The base for the Engine that needs to be programmed.
>> + *
>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>> + * given table starting at the given address.
>> + *
>> + * Return: Nothing.
>> + */
>> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
>> +				    struct drm_i915_mocs_table *table,
>> +				    u32 reg_base)
>> +{
>> +	unsigned int index;
>> +
>> +	intel_logical_ring_emit(ringbuf,
>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
>> +
>> +	for (index = 0; index < table->size; index++) {
>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>> +		intel_logical_ring_emit(ringbuf,
>> +					table->table[index].control_value);
>> +	}
>> +
>> +	/*
>> +	 * Ok, now set the unused entries to uncached. These entries are
>> +	 * officially undefined and no contact is given for the contents and
>> +	 * settings is given for these entries.
>> +	 *
>> +	 * Entry 0 in the table is uncached - so we are just written that
>> +	 * value to all the used entries.
>> +	 */
>> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>> +		intel_logical_ring_emit(ringbuf, table->table[0].control_value);
>> +	}
>> +
>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>> +}
>> +
>> +/**
>> + * emit_mocs_l3cc_table() - emit the mocs control table
>> + * @ringbuf:	DRM device.
>> + * @table:	The values to program into the control regs.
>> + *
>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>> + * given table starting at the given address. This register set is  programmed
>> + * in pairs.
>> + *
>> + * Return: Nothing.
>> + */
>> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
>> +			 struct drm_i915_mocs_table *table) {
>> +	unsigned int count;
>> +	unsigned int i;
>> +	u32 value;
>> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
>> +			((table->table[0].l3cc_value & 0xffff) << 16);
>> +
>> +	intel_logical_ring_emit(ringbuf,
>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
>> +
>> +	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);
>> +
>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>> +		intel_logical_ring_emit(ringbuf, value);
>> +
>> +		value = filler;
>> +	}
>> +
>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>> +}
>> +
>> +/*
>> + * gen9_program_mocs() - program the MOCS register.
>> + *
>> + * ring:	The ring that the programming batch will be run in.
>> + * ctx:		The intel_context to be used.
>> + *
>> + * This function will emit a batch buffer with the values required for
>> + * programming the MOCS register values for all the currently supported
>> + * rings.
>> + *
>> + * These registers are partially stored in the RCS context, so they are
>> + * emitted at the same time so that when a context is created these registers
>> + * are set up. These registers have to be emitted into the start of the
>> + * context as setting the ELSP will re-init some of these registers back
>> + * to the hw values.
>> + *
>> + * Return: 0 on success, otherwise the error status.
>> + */
>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>> +			  struct intel_context *ctx)
>> +{
>> +	int ret = 0;
>> +
>> +	struct drm_i915_mocs_table t;
>> +	struct drm_device *dev = ring->dev;
>> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
>> +
>> +	if (get_mocs_settings(dev, &t)) {
>> +		u32 table_size;
>> +
>> +		/*
>> +		 * OK. For each supported ring:
>> +		 *  number of mocs entries * 2 dwords for each control_value
>> +		 *  plus number of mocs entries /2 dwords for l3cc values.
>> +		 *
>> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
>> +		 *  and the l3cc programming.
>> +		 */
>> +		table_size = GEN9_NUM_MOCS_RINGS *
>> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
>> +				GEN9_NUM_MOCS_ENTRIES + 2;
>> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
>> +		if (ret) {
>> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret);
>> +			return ret;
>> +		}
>> +
>> +		/* program the control registers */
>> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
>> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
>> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
>> +
>> +		/* now program the l3cc registers */
>> +		emit_mocs_l3cc_table(ringbuf, &t);
>> +
>> +		intel_logical_ring_advance(ringbuf);
>> +
>> +		DRM_DEBUG("MOCS: Table set in Context\n");
>> +	} else {
>> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> diff --git a/drivers/gpu/drm/i915/intel_mocs.h b/drivers/gpu/drm/i915/intel_mocs.h
>> new file mode 100644
>> index 0000000..e2780ce
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/intel_mocs.h
>> @@ -0,0 +1,64 @@
>> +/*
>> + * Copyright (c) 2015 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>> + * SOFTWARE.
>> + *
>> + * Authors:
>> + *    Peter Antoine <peter.antoine@intel.com>
>> + */
>> +
>> +#ifndef INTEL_MOCS_H
>> +#define INTEL_MOCS_H
>> +
>> +/**
>> + * DOC: Memory Objects Control State (MOCS)
>> + *
>> + * Motivation:
>> + * In previous Gens the MOCS settings was a value that was set by user land as
>> + * part of the batch. In Gen9 this has changed to be a single table (per ring)
>> + * that all batches now reference by index instead of programming the MOCS
>> + * directly.
>> + *
>> + * The one wrinkle in this is that only PART of the MOCS tables are included
>> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - LNCFCMOCS32
>> + * registers). The rest are not (the settings for the other rings).
>> + *
>> + * This table needs to be set at system start-up because the way the table
>> + * interacts with the contexts and the GmmLib interface.
>> + *
>> + *
>> + * Implementation:
>> + *
>> + * The table is programmed on a platform basis from a table that is generated
>> + * from the one that has been agreed by the different responsible parties. This
>> + * tables (one per supported platform) is defined in intel_mocs.c and is
>> + * programmed in the first batch after the context is loaded (with the hardware
>> + * workarounds). This will then let the usual context handling keep the MOCS in
>> + * step.
>> + */
>> +
>> +#include <drm/drmP.h>
>> +#include "i915_drv.h"
>> +
>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>> +			struct intel_context *ctx);
>> +
>> +#endif
>> +
>> --
>> 1.9.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>

--
    Peter Antoine (Android Graphics Driver Software Engineer)
    ---------------------------------------------------------------------
    Intel Corporation (UK) Limited
    Registered No. 1134945 (England)
    Registered Office: Pipers Way, Swindon SN3 1RJ
    VAT No: 860 2173 47
Peter Antoine June 30, 2015, 1:11 p.m. UTC | #14
On Mon, 29 Jun 2015, Peter Antoine wrote:

> On Thu, 25 Jun 2015, Francisco Jerez wrote:
>
>> Peter Antoine <peter.antoine@intel.com> writes:
>>
>>> This change adds the programming of the MOCS registers to the gen 9+
>>> platforms. This change set programs the MOCS register values to a set
>>> of values that are defined to be optimal.
>>>
>>> It creates a fixed register set that is programmed across the different
>>> engines so that all engines have the same table. This is done as the
>>> main RCS context only holds the registers for itself and the shared
>>> L3 values. By trying to keep the registers consistent across the
>>> different engines it should make the programming for the registers
>>> consistent.
>>>
>>> v2:
>>> -'static const' for private data structures and style changes.(Matt 
> Turner)
>>> v3:
>>> - Make the tables "slightly" more readable. (Damien Lespiau)
>>> - Updated tables fix performance regression.
>>> v4:
>>> - Code formatting. (Chris Wilson)
>>> - re-privatised mocs code. (Daniel Vetter)
>>>
>>> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
>>> ---
>>>  drivers/gpu/drm/i915/Makefile     |   1 +
>>>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>>>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>>>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>>>  drivers/gpu/drm/i915/intel_mocs.c | 373 
> ++++++++++++++++++++++++++++++++++++++
>>>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>>>  6 files changed, 460 insertions(+), 1 deletion(-)
>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>>>
>>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>>> index b7ddf48..c781e19 100644
>>> --- a/drivers/gpu/drm/i915/Makefile
>>> +++ b/drivers/gpu/drm/i915/Makefile
>>> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>>>  	  i915_irq.o \
>>>  	  i915_trace_points.o \
>>>  	  intel_lrc.o \
>>> +	  intel_mocs.o \
>>>  	  intel_ringbuffer.o \
>>>  	  intel_uncore.o
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h 
> b/drivers/gpu/drm/i915/i915_reg.h
>>> index 7213224..3a435b5 100644
>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>>>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>>>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>>>
>>> +/* MOCS (Memory Object Control State) registers */
>>> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control 
> base */
>>> +
>>> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base 
> register*/
>>> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base 
> register*/
>>> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base 
> register*/
>>> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
>>> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base 
> register*/
>>> +
>>>  #endif /* _I915_REG_H_ */
>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c 
> b/drivers/gpu/drm/i915/intel_lrc.c
>>> index 9f5485d..73b919d 100644
>>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>>> @@ -135,6 +135,7 @@
>>>  #include <drm/drmP.h>
>>>  #include <drm/i915_drm.h>
>>>  #include "i915_drv.h"
>>> +#include "intel_mocs.h"
>>>
>>>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>>>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
>>> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct 
> intel_ringbuffer *ringbuf,
>>>   *
>>>   * Return: non-zero if the ringbuffer is not ready to be written to.
>>>   */
>>> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>  				    struct intel_context *ctx, int 
> num_dwords)
>>>  {
>>>  	struct intel_engine_cs *ring = ringbuf->ring;
>>> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct 
> intel_engine_cs *ring,
>>>  	if (ret)
>>>  		return ret;
>>>
>>> +	/*
>>> +	 * Failing to program the MOCS is non-fatal.The system will not
>>> +	 * run at peak performance. So generate a warning and carry on.
>>> +	 */
>>> +	if (gen9_program_mocs(ring, ctx) != 0)
>>> +		DRM_ERROR("MOCS failed to program: expect performance 
> issues.");
>>> +
>>>  	return intel_lr_context_render_state_init(ring, ctx);
>>>  }
>>>
>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.h 
> b/drivers/gpu/drm/i915/intel_lrc.h
>>> index 04d3a6d..dbbd6af 100644
>>> --- a/drivers/gpu/drm/i915/intel_lrc.h
>>> +++ b/drivers/gpu/drm/i915/intel_lrc.h
>>> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>>>
>>>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>>>  				  struct intel_context *ctx);
>>> +
>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>> +				    struct intel_context *ctx, int 
> num_dwords);
>>> +
>>>  /**
>>>   * intel_logical_ring_advance() - advance the ringbuffer tail
>>>   * @ringbuf: Ringbuffer to advance.
>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.c 
> b/drivers/gpu/drm/i915/intel_mocs.c
>>> new file mode 100644
>>> index 0000000..7c09e67
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/intel_mocs.c
>>> @@ -0,0 +1,373 @@
>>> +/*
>>> + * Copyright (c) 2015 Intel Corporation
>>> + *
>>> + * Permission is hereby granted, free of charge, to any person obtaining 
> a
>>> + * copy of this software and associated documentation files (the 
> "Software"),
>>> + * to deal in the Software without restriction, including without 
> limitation
>>> + * the rights to use, copy, modify, merge, publish, distribute, 
> sublicense,
>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>> + * Software is furnished to do so, subject to the following conditions: *
>>> + * The above copyright notice and this permission notice (including the 
> next
>>> + * paragraph) shall be included in all copies or substantial portions of 
> the
>>> + * Software.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
> EXPRESS OR
>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
> MERCHANTABILITY,
>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT 
> SHALL
>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
> OTHER
>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
> ARISING FROM,
>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
> IN THE
>>> + * SOFTWARE.
>>> + *
>>> + * Authors:
>>> + *    Peter Antoine <peter.antoine@intel.com>
>>> + */
>>> +
>>> +#include "intel_mocs.h"
>>> +#include "intel_lrc.h"
>>> +#include "intel_ringbuffer.h"
>>> +
>>> +/* structures required */
>>> +struct drm_i915_mocs_entry {
>>> +	u32	control_value;
>>> +	u16	l3cc_value;
>>> +};
>>> +
>>> +struct drm_i915_mocs_table {
>>> +	u32					size;
>>> +	const struct drm_i915_mocs_entry	*table;
>>> +};
>>> +
>>> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
>>> +#define	MOCS_CACHEABILITY(value)	(value << 0)
>>> +#define	MOCS_TGT_CACHE(value)		(value << 2)
>>> +#define	MOCS_LRUM(value)		(value << 4)
>>> +#define	MOCS_AOM(value)			(value << 6)
>>> +#define	MOCS_LECC_ESC(value)		(value << 7)
>>> +#define	MOCS_LECC_SCC(value)		(value << 8)
>>> +#define	MOC_PFM(value)			(value << 11)
>>> +#define	MOCS_SCF(value)			(value << 14)
>>> +
>>> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word 
> */
>>> +#define	MOCS_ESC(value)			(value << 0)
>>> +#define	MOCS_SCC(value)			(value << 1)
>>> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
>>> +
>>> +/* Helper defines */
>>> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program 
> */
>>> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd 
> */
>>> +
>>> +/* EDRAM Caching options */
>>> +#define EDRAM_PAGETABLE		(0)
>>> +#define EDRAM_UC		(1)
>>> +#define EDRAM_RESERVED		(2)
>>
>> According to the BSpec this is WT rather than reserved?a
> Just checked the Bspec and you are correct, changing the text.
> As well as for the items below.
Just to add - I was looking at the wrong gen.
>>
>>> +#define EDRAM_WB		(3)
>>> +
>>> +/* L3 Caching options */
>>> +#define L3_DIRECT		(0)
>>> +#define L3_UC			(1)
>>> +#define L3_RESERVED		(2)
>>> +#define L3_WB			(3)
>>> +
>>> +/* target cache */
>>> +#define ELLC			(0)
>>
>> BSpec says that this is "Use TC/LRU controls from page table", but upon
>> a closer look it seems like the BSpec is wrong and your patch is
>> correct.  Can you confirm that this is what you intended?
> These values look good, they are bits 3:2 for the XXX_MOCS_N registers 
> (c800) and friends. 
>>
>>> +#define LLC			(1)
>>> +#define LLC_ELLC		(2)
>>> +
>>> +/*
>>> + * MOCS tables
>>> + *
>>> + * These are the MOCS tables that are programmed across all the rings.
>>> + * The control value is programmed to all the rings that support the
>>> + * MOCS registers. While the l3cc_values are only programmed to the
>>> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
>>> + *
>>> + * NOTE: These tables MUST start with being uncached and the length MUST 
> be
>>> + *       less than 63 as the last two registers are reserved by the 
> hardware.
>>> + */
>>> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
>>> +	 /* {0x00000009, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +	 /* {0x0000003b, 0x0030} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>> +	 /* {0x00000039, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +	 /* {0x00000017, 0x0030} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>> +	 /* {0x00000017, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +	 /* {0x00000019, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +	 /* {0x00000037, 0x0030} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>> +	 /* {0x00000037, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +	 /* {0x0000003b, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +};
>>
>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE, L3CC=WB,
>> everything else unset, I'll reply with a userspace patch making use of
>> your change if you add such an entry.
Ok. I think what you want is, same as entry two, but use the underlying
pagetable settings and not specify the EDRAM settings. Please confirm in 
the new patchset.
>>
>> Another thing worth mentioning is that entries 0, 2 and 5 seem to do the
>> same thing suspiciously, the only difference is the LRUM field which
>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding correct?
>>
> These tables are generated via requests and then boiled down to the above. 
> So some of the entries are by request. Swings and roundabouts, can remove 
> the ones that look redundant but then the tuning that has been done wont 
> match. I'll add the new entry at the end of the table.
>>> +
>>> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
>>> +	 /* {0x00000001, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +	 /* {0x00000005, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +	 /* {0x00000005, 0x0030} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>> +	 /* {0x00000017, 0x0030} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>> +	 /* {0x00000017, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +	 /* {0x00000019, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +	 /* {0x00000037, 0x0030} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>> +	 /* {0x00000037, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +	 /* {0x0000003b, 0x0010} */
>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>> +};
>>> +
>>
>> Wouldn't it be a good idea to have BXT's entries match SKL's for a given
>> index?  The TC, LeCC and LRUM settings you do here arguably don't have
>> any effect on BXT, L3CC does but it doesn't match SKL's setting for
>> entries 1 and 2.  Is there any reason for this?
> As mentioned above this table is auto-generated and matches another tuned 
> table, simply keeping them the same allows for the tuning to be consistent 
> across platforms.
>
> Peter.
>>
>> Other than that looks good.
>>
>>> +/**
>>> + * get_mocs_settings
>>> + *
>>> + * 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
>>> + * to be programmed and if they need to be programmed.
>>> + *
>>> + * If the return values is false then the registers do not need 
> programming.
>>> + */
>>> +static bool get_mocs_settings(struct drm_device *dev,
>>> +			      struct drm_i915_mocs_table *table) {
>>> +	bool	result = false;
>>> +
>>> +	if (IS_SKYLAKE(dev)) {
>>> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
>>> +		table->table = skylake_mocs_table;
>>> +		result = true;
>>> +	} else if (IS_BROXTON(dev)) {
>>> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
>>> +		table->table = broxton_mocs_table;
>>> +		result = true;
>>> +	} else {
>>> +		/* Platform that should have a MOCS table does not */
>>> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
>>> +	}
>>> +
>>> +	return result;
>>> +}
>>> +
>>> +/**
>>> + * emit_mocs_control_table() - emit the mocs control table
>>> + * @ringbuf:	DRM device.
>>> + * @table:	The values to program into the control regs.
>>> + * @reg_base:	The base for the Engine that needs to be programmed.
>>> + *
>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>> + * given table starting at the given address.
>>> + *
>>> + * Return: Nothing.
>>> + */
>>> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
>>> +				    struct drm_i915_mocs_table *table,
>>> +				    u32 reg_base)
>>> +{
>>> +	unsigned int index;
>>> +
>>> +	intel_logical_ring_emit(ringbuf,
>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
>>> +
>>> +	for (index = 0; index < table->size; index++) {
>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>> +		intel_logical_ring_emit(ringbuf,
>>> +					table->table[index].control_value);
>>> +	}
>>> +
>>> +	/*
>>> +	 * Ok, now set the unused entries to uncached. These entries are
>>> +	 * officially undefined and no contact is given for the contents and
>>> +	 * settings is given for these entries.
>>> +	 *
>>> +	 * Entry 0 in the table is uncached - so we are just written that
>>> +	 * value to all the used entries.
>>> +	 */
>>> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>> +		intel_logical_ring_emit(ringbuf, 
> table->table[0].control_value);
>>> +	}
>>> +
>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>> +}
>>> +
>>> +/**
>>> + * emit_mocs_l3cc_table() - emit the mocs control table
>>> + * @ringbuf:	DRM device.
>>> + * @table:	The values to program into the control regs.
>>> + *
>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>> + * given table starting at the given address. This register set is 
> programmed
>>> + * in pairs.
>>> + *
>>> + * Return: Nothing.
>>> + */
>>> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
>>> +			 struct drm_i915_mocs_table *table) {
>>> +	unsigned int count;
>>> +	unsigned int i;
>>> +	u32 value;
>>> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
>>> +			((table->table[0].l3cc_value & 0xffff) << 16);
>>> +
>>> +	intel_logical_ring_emit(ringbuf,
>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
>>> +
>>> +	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);
>>> +
>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>> +		intel_logical_ring_emit(ringbuf, value);
>>> +
>>> +		value = filler;
>>> +	}
>>> +
>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>> +}
>>> +
>>> +/*
>>> + * gen9_program_mocs() - program the MOCS register.
>>> + *
>>> + * ring:	The ring that the programming batch will be run in.
>>> + * ctx:		The intel_context to be used.
>>> + *
>>> + * This function will emit a batch buffer with the values required for
>>> + * programming the MOCS register values for all the currently supported
>>> + * rings.
>>> + *
>>> + * These registers are partially stored in the RCS context, so they are
>>> + * emitted at the same time so that when a context is created these 
> registers
>>> + * are set up. These registers have to be emitted into the start of the
>>> + * context as setting the ELSP will re-init some of these registers back
>>> + * to the hw values.
>>> + *
>>> + * Return: 0 on success, otherwise the error status.
>>> + */
>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>> +			  struct intel_context *ctx)
>>> +{
>>> +	int ret = 0;
>>> +
>>> +	struct drm_i915_mocs_table t;
>>> +	struct drm_device *dev = ring->dev;
>>> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
>>> +
>>> +	if (get_mocs_settings(dev, &t)) {
>>> +		u32 table_size;
>>> +
>>> +		/*
>>> +		 * OK. For each supported ring:
>>> +		 *  number of mocs entries * 2 dwords for each control_value
>>> +		 *  plus number of mocs entries /2 dwords for l3cc values.
>>> +		 *
>>> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
>>> +		 *  and the l3cc programming.
>>> +		 */
>>> +		table_size = GEN9_NUM_MOCS_RINGS *
>>> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
>>> +				GEN9_NUM_MOCS_ENTRIES + 2;
>>> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
>>> +		if (ret) {
>>> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n", 
> ret);
>>> +			return ret;
>>> +		}
>>> +
>>> +		/* program the control registers */
>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
>>> +
>>> +		/* now program the l3cc registers */
>>> +		emit_mocs_l3cc_table(ringbuf, &t);
>>> +
>>> +		intel_logical_ring_advance(ringbuf);
>>> +
>>> +		DRM_DEBUG("MOCS: Table set in Context\n");
>>> +	} else {
>>> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
>>> +	}
>>> +
>>> +	return ret;
>>> +}
>>> +
>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.h 
> b/drivers/gpu/drm/i915/intel_mocs.h
>>> new file mode 100644
>>> index 0000000..e2780ce
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/intel_mocs.h
>>> @@ -0,0 +1,64 @@
>>> +/*
>>> + * Copyright (c) 2015 Intel Corporation
>>> + *
>>> + * Permission is hereby granted, free of charge, to any person obtaining 
> a
>>> + * copy of this software and associated documentation files (the 
> "Software"),
>>> + * to deal in the Software without restriction, including without 
> limitation
>>> + * the rights to use, copy, modify, merge, publish, distribute, 
> sublicense,
>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>> + * Software is furnished to do so, subject to the following conditions:
>>> + *
>>> + * The above copyright notice and this permission notice (including the 
> next
>>> + * paragraph) shall be included in all copies or substantial portions of 
> the
>>> + * Software.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
> EXPRESS OR
>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
> MERCHANTABILITY,
>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT 
> SHALL
>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
> OTHER
>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
> ARISING FROM,
>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
> IN THE
>>> + * SOFTWARE.
>>> + *
>>> + * Authors:
>>> + *    Peter Antoine <peter.antoine@intel.com>
>>> + */
>>> +
>>> +#ifndef INTEL_MOCS_H
>>> +#define INTEL_MOCS_H
>>> +
>>> +/**
>>> + * DOC: Memory Objects Control State (MOCS)
>>> + *
>>> + * Motivation:
>>> + * In previous Gens the MOCS settings was a value that was set by user 
> land as
>>> + * part of the batch. In Gen9 this has changed to be a single table (per 
> ring)
>>> + * that all batches now reference by index instead of programming the 
> MOCS
>>> + * directly.
>>> + *
>>> + * The one wrinkle in this is that only PART of the MOCS tables are 
> included
>>> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - 
> LNCFCMOCS32
>>> + * registers). The rest are not (the settings for the other rings).
>>> + *
>>> + * This table needs to be set at system start-up because the way the 
> table
>>> + * interacts with the contexts and the GmmLib interface.
>>> + *
>>> + *
>>> + * Implementation:
>>> + *
>>> + * The table is programmed on a platform basis from a table that is 
> generated
>>> + * from the one that has been agreed by the different responsible 
> parties. This
>>> + * tables (one per supported platform) is defined in intel_mocs.c and is
>>> + * programmed in the first batch after the context is loaded (with the 
> hardware
>>> + * workarounds). This will then let the usual context handling keep the 
> MOCS in
>>> + * step.
>>> + */
>>> +
>>> +#include <drm/drmP.h>
>>> +#include "i915_drv.h"
>>> +
>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>> +			struct intel_context *ctx);
>>> +
>>> +#endif
>>> +
>>> --
>>> 1.9.1
>>>
>>> _______________________________________________
>>> Intel-gfx mailing list
>>> Intel-gfx@lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>
>
> --
>    Peter Antoine (Android Graphics Driver Software Engineer)
>    ---------------------------------------------------------------------
>    Intel Corporation (UK) Limited
>    Registered No. 1134945 (England)
>    Registered Office: Pipers Way, Swindon SN3 1RJ
>    VAT No: 860 2173 47
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>

--
    Peter Antoine (Android Graphics Driver Software Engineer)
    ---------------------------------------------------------------------
    Intel Corporation (UK) Limited
    Registered No. 1134945 (England)
    Registered Office: Pipers Way, Swindon SN3 1RJ
    VAT No: 860 2173 47
Francisco Jerez June 30, 2015, 5 p.m. UTC | #15
Peter Antoine <peter.antoine@intel.com> writes:

> On Mon, 29 Jun 2015, Peter Antoine wrote:
>
>> On Thu, 25 Jun 2015, Francisco Jerez wrote:
>>
>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>
>>>> This change adds the programming of the MOCS registers to the gen 9+
>>>> platforms. This change set programs the MOCS register values to a set
>>>> of values that are defined to be optimal.
>>>>
>>>> It creates a fixed register set that is programmed across the different
>>>> engines so that all engines have the same table. This is done as the
>>>> main RCS context only holds the registers for itself and the shared
>>>> L3 values. By trying to keep the registers consistent across the
>>>> different engines it should make the programming for the registers
>>>> consistent.
>>>>
>>>> v2:
>>>> -'static const' for private data structures and style changes.(Matt 
>> Turner)
>>>> v3:
>>>> - Make the tables "slightly" more readable. (Damien Lespiau)
>>>> - Updated tables fix performance regression.
>>>> v4:
>>>> - Code formatting. (Chris Wilson)
>>>> - re-privatised mocs code. (Daniel Vetter)
>>>>
>>>> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
>>>> ---
>>>>  drivers/gpu/drm/i915/Makefile     |   1 +
>>>>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>>>>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>>>>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>>>>  drivers/gpu/drm/i915/intel_mocs.c | 373 
>> ++++++++++++++++++++++++++++++++++++++
>>>>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>>>>  6 files changed, 460 insertions(+), 1 deletion(-)
>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>>>> index b7ddf48..c781e19 100644
>>>> --- a/drivers/gpu/drm/i915/Makefile
>>>> +++ b/drivers/gpu/drm/i915/Makefile
>>>> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>>>>  	  i915_irq.o \
>>>>  	  i915_trace_points.o \
>>>>  	  intel_lrc.o \
>>>> +	  intel_mocs.o \
>>>>  	  intel_ringbuffer.o \
>>>>  	  intel_uncore.o
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h 
>> b/drivers/gpu/drm/i915/i915_reg.h
>>>> index 7213224..3a435b5 100644
>>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>>> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>>>>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>>>>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>>>>
>>>> +/* MOCS (Memory Object Control State) registers */
>>>> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control 
>> base */
>>>> +
>>>> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base 
>> register*/
>>>> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base 
>> register*/
>>>> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base 
>> register*/
>>>> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
>>>> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base 
>> register*/
>>>> +
>>>>  #endif /* _I915_REG_H_ */
>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c 
>> b/drivers/gpu/drm/i915/intel_lrc.c
>>>> index 9f5485d..73b919d 100644
>>>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>>>> @@ -135,6 +135,7 @@
>>>>  #include <drm/drmP.h>
>>>>  #include <drm/i915_drm.h>
>>>>  #include "i915_drv.h"
>>>> +#include "intel_mocs.h"
>>>>
>>>>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>>>>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
>>>> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct 
>> intel_ringbuffer *ringbuf,
>>>>   *
>>>>   * Return: non-zero if the ringbuffer is not ready to be written to.
>>>>   */
>>>> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>  				    struct intel_context *ctx, int 
>> num_dwords)
>>>>  {
>>>>  	struct intel_engine_cs *ring = ringbuf->ring;
>>>> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct 
>> intel_engine_cs *ring,
>>>>  	if (ret)
>>>>  		return ret;
>>>>
>>>> +	/*
>>>> +	 * Failing to program the MOCS is non-fatal.The system will not
>>>> +	 * run at peak performance. So generate a warning and carry on.
>>>> +	 */
>>>> +	if (gen9_program_mocs(ring, ctx) != 0)
>>>> +		DRM_ERROR("MOCS failed to program: expect performance 
>> issues.");
>>>> +
>>>>  	return intel_lr_context_render_state_init(ring, ctx);
>>>>  }
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.h 
>> b/drivers/gpu/drm/i915/intel_lrc.h
>>>> index 04d3a6d..dbbd6af 100644
>>>> --- a/drivers/gpu/drm/i915/intel_lrc.h
>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.h
>>>> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>>>>
>>>>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>>>>  				  struct intel_context *ctx);
>>>> +
>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>> +				    struct intel_context *ctx, int 
>> num_dwords);
>>>> +
>>>>  /**
>>>>   * intel_logical_ring_advance() - advance the ringbuffer tail
>>>>   * @ringbuf: Ringbuffer to advance.
>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.c 
>> b/drivers/gpu/drm/i915/intel_mocs.c
>>>> new file mode 100644
>>>> index 0000000..7c09e67
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.c
>>>> @@ -0,0 +1,373 @@
>>>> +/*
>>>> + * Copyright (c) 2015 Intel Corporation
>>>> + *
>>>> + * Permission is hereby granted, free of charge, to any person obtaining 
>> a
>>>> + * copy of this software and associated documentation files (the 
>> "Software"),
>>>> + * to deal in the Software without restriction, including without 
>> limitation
>>>> + * the rights to use, copy, modify, merge, publish, distribute, 
>> sublicense,
>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>> + * Software is furnished to do so, subject to the following conditions: *
>>>> + * The above copyright notice and this permission notice (including the 
>> next
>>>> + * paragraph) shall be included in all copies or substantial portions of 
>> the
>>>> + * Software.
>>>> + *
>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
>> EXPRESS OR
>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
>> MERCHANTABILITY,
>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT 
>> SHALL
>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
>> OTHER
>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
>> ARISING FROM,
>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
>> IN THE
>>>> + * SOFTWARE.
>>>> + *
>>>> + * Authors:
>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>> + */
>>>> +
>>>> +#include "intel_mocs.h"
>>>> +#include "intel_lrc.h"
>>>> +#include "intel_ringbuffer.h"
>>>> +
>>>> +/* structures required */
>>>> +struct drm_i915_mocs_entry {
>>>> +	u32	control_value;
>>>> +	u16	l3cc_value;
>>>> +};
>>>> +
>>>> +struct drm_i915_mocs_table {
>>>> +	u32					size;
>>>> +	const struct drm_i915_mocs_entry	*table;
>>>> +};
>>>> +
>>>> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
>>>> +#define	MOCS_CACHEABILITY(value)	(value << 0)
>>>> +#define	MOCS_TGT_CACHE(value)		(value << 2)
>>>> +#define	MOCS_LRUM(value)		(value << 4)
>>>> +#define	MOCS_AOM(value)			(value << 6)
>>>> +#define	MOCS_LECC_ESC(value)		(value << 7)
>>>> +#define	MOCS_LECC_SCC(value)		(value << 8)
>>>> +#define	MOC_PFM(value)			(value << 11)
>>>> +#define	MOCS_SCF(value)			(value << 14)
>>>> +
>>>> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word 
>> */
>>>> +#define	MOCS_ESC(value)			(value << 0)
>>>> +#define	MOCS_SCC(value)			(value << 1)
>>>> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
>>>> +
>>>> +/* Helper defines */
>>>> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program 
>> */
>>>> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd 
>> */
>>>> +
>>>> +/* EDRAM Caching options */
>>>> +#define EDRAM_PAGETABLE		(0)
>>>> +#define EDRAM_UC		(1)
>>>> +#define EDRAM_RESERVED		(2)
>>>
>>> According to the BSpec this is WT rather than reserved?a
>> Just checked the Bspec and you are correct, changing the text.
>> As well as for the items below.
> Just to add - I was looking at the wrong gen.
>>>
>>>> +#define EDRAM_WB		(3)
>>>> +
>>>> +/* L3 Caching options */
>>>> +#define L3_DIRECT		(0)
>>>> +#define L3_UC			(1)
>>>> +#define L3_RESERVED		(2)
>>>> +#define L3_WB			(3)
>>>> +
>>>> +/* target cache */
>>>> +#define ELLC			(0)
>>>
>>> BSpec says that this is "Use TC/LRU controls from page table", but upon
>>> a closer look it seems like the BSpec is wrong and your patch is
>>> correct.  Can you confirm that this is what you intended?
>> These values look good, they are bits 3:2 for the XXX_MOCS_N registers 
>> (c800) and friends. 
>>>
>>>> +#define LLC			(1)
>>>> +#define LLC_ELLC		(2)
>>>> +
>>>> +/*
>>>> + * MOCS tables
>>>> + *
>>>> + * These are the MOCS tables that are programmed across all the rings.
>>>> + * The control value is programmed to all the rings that support the
>>>> + * MOCS registers. While the l3cc_values are only programmed to the
>>>> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
>>>> + *
>>>> + * NOTE: These tables MUST start with being uncached and the length MUST 
>> be
>>>> + *       less than 63 as the last two registers are reserved by the 
>> hardware.
>>>> + */
>>>> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
>>>> +	 /* {0x00000009, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +	 /* {0x0000003b, 0x0030} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>> +	 /* {0x00000039, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +	 /* {0x00000017, 0x0030} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>> +	 /* {0x00000017, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +	 /* {0x00000019, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +	 /* {0x00000037, 0x0030} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>> +	 /* {0x00000037, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +	 /* {0x0000003b, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +};
>>>
>>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE, L3CC=WB,
>>> everything else unset, I'll reply with a userspace patch making use of
>>> your change if you add such an entry.
> Ok. I think what you want is, same as entry two, but use the underlying
> pagetable settings and not specify the EDRAM settings. Please confirm in 
> the new patchset.

Yeah, that sounds good.

>>>
>>> Another thing worth mentioning is that entries 0, 2 and 5 seem to do the
>>> same thing suspiciously, the only difference is the LRUM field which
>>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding correct?
>>>
>> These tables are generated via requests and then boiled down to the above. 
>> So some of the entries are by request. Swings and roundabouts, can remove 
>> the ones that look redundant but then the tuning that has been done wont 
>> match. I'll add the new entry at the end of the table.
>>>> +
>>>> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
>>>> +	 /* {0x00000001, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +	 /* {0x00000005, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +	 /* {0x00000005, 0x0030} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>> +	 /* {0x00000017, 0x0030} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>> +	 /* {0x00000017, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +	 /* {0x00000019, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +	 /* {0x00000037, 0x0030} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>> +	 /* {0x00000037, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +	 /* {0x0000003b, 0x0010} */
>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>> +};
>>>> +
>>>
>>> Wouldn't it be a good idea to have BXT's entries match SKL's for a given
>>> index?  The TC, LeCC and LRUM settings you do here arguably don't have
>>> any effect on BXT, L3CC does but it doesn't match SKL's setting for
>>> entries 1 and 2.  Is there any reason for this?
>> As mentioned above this table is auto-generated and matches another tuned 
>> table, simply keeping them the same allows for the tuning to be consistent 
>> across platforms.
>>
>> Peter.
>>>
>>> Other than that looks good.
>>>
>>>> +/**
>>>> + * get_mocs_settings
>>>> + *
>>>> + * 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
>>>> + * to be programmed and if they need to be programmed.
>>>> + *
>>>> + * If the return values is false then the registers do not need 
>> programming.
>>>> + */
>>>> +static bool get_mocs_settings(struct drm_device *dev,
>>>> +			      struct drm_i915_mocs_table *table) {
>>>> +	bool	result = false;
>>>> +
>>>> +	if (IS_SKYLAKE(dev)) {
>>>> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
>>>> +		table->table = skylake_mocs_table;
>>>> +		result = true;
>>>> +	} else if (IS_BROXTON(dev)) {
>>>> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
>>>> +		table->table = broxton_mocs_table;
>>>> +		result = true;
>>>> +	} else {
>>>> +		/* Platform that should have a MOCS table does not */
>>>> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
>>>> +	}
>>>> +
>>>> +	return result;
>>>> +}
>>>> +
>>>> +/**
>>>> + * emit_mocs_control_table() - emit the mocs control table
>>>> + * @ringbuf:	DRM device.
>>>> + * @table:	The values to program into the control regs.
>>>> + * @reg_base:	The base for the Engine that needs to be programmed.
>>>> + *
>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>> + * given table starting at the given address.
>>>> + *
>>>> + * Return: Nothing.
>>>> + */
>>>> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
>>>> +				    struct drm_i915_mocs_table *table,
>>>> +				    u32 reg_base)
>>>> +{
>>>> +	unsigned int index;
>>>> +
>>>> +	intel_logical_ring_emit(ringbuf,
>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
>>>> +
>>>> +	for (index = 0; index < table->size; index++) {
>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>> +		intel_logical_ring_emit(ringbuf,
>>>> +					table->table[index].control_value);
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * Ok, now set the unused entries to uncached. These entries are
>>>> +	 * officially undefined and no contact is given for the contents and
>>>> +	 * settings is given for these entries.
>>>> +	 *
>>>> +	 * Entry 0 in the table is uncached - so we are just written that
>>>> +	 * value to all the used entries.
>>>> +	 */
>>>> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>> +		intel_logical_ring_emit(ringbuf, 
>> table->table[0].control_value);
>>>> +	}
>>>> +
>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>> +}
>>>> +
>>>> +/**
>>>> + * emit_mocs_l3cc_table() - emit the mocs control table
>>>> + * @ringbuf:	DRM device.
>>>> + * @table:	The values to program into the control regs.
>>>> + *
>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>> + * given table starting at the given address. This register set is 
>> programmed
>>>> + * in pairs.
>>>> + *
>>>> + * Return: Nothing.
>>>> + */
>>>> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
>>>> +			 struct drm_i915_mocs_table *table) {
>>>> +	unsigned int count;
>>>> +	unsigned int i;
>>>> +	u32 value;
>>>> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
>>>> +			((table->table[0].l3cc_value & 0xffff) << 16);
>>>> +
>>>> +	intel_logical_ring_emit(ringbuf,
>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
>>>> +
>>>> +	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);
>>>> +
>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>> +		intel_logical_ring_emit(ringbuf, value);
>>>> +
>>>> +		value = filler;
>>>> +	}
>>>> +
>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>> +}
>>>> +
>>>> +/*
>>>> + * gen9_program_mocs() - program the MOCS register.
>>>> + *
>>>> + * ring:	The ring that the programming batch will be run in.
>>>> + * ctx:		The intel_context to be used.
>>>> + *
>>>> + * This function will emit a batch buffer with the values required for
>>>> + * programming the MOCS register values for all the currently supported
>>>> + * rings.
>>>> + *
>>>> + * These registers are partially stored in the RCS context, so they are
>>>> + * emitted at the same time so that when a context is created these 
>> registers
>>>> + * are set up. These registers have to be emitted into the start of the
>>>> + * context as setting the ELSP will re-init some of these registers back
>>>> + * to the hw values.
>>>> + *
>>>> + * Return: 0 on success, otherwise the error status.
>>>> + */
>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>> +			  struct intel_context *ctx)
>>>> +{
>>>> +	int ret = 0;
>>>> +
>>>> +	struct drm_i915_mocs_table t;
>>>> +	struct drm_device *dev = ring->dev;
>>>> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
>>>> +
>>>> +	if (get_mocs_settings(dev, &t)) {
>>>> +		u32 table_size;
>>>> +
>>>> +		/*
>>>> +		 * OK. For each supported ring:
>>>> +		 *  number of mocs entries * 2 dwords for each control_value
>>>> +		 *  plus number of mocs entries /2 dwords for l3cc values.
>>>> +		 *
>>>> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
>>>> +		 *  and the l3cc programming.
>>>> +		 */
>>>> +		table_size = GEN9_NUM_MOCS_RINGS *
>>>> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
>>>> +				GEN9_NUM_MOCS_ENTRIES + 2;
>>>> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
>>>> +		if (ret) {
>>>> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n", 
>> ret);
>>>> +			return ret;
>>>> +		}
>>>> +
>>>> +		/* program the control registers */
>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
>>>> +
>>>> +		/* now program the l3cc registers */
>>>> +		emit_mocs_l3cc_table(ringbuf, &t);
>>>> +
>>>> +		intel_logical_ring_advance(ringbuf);
>>>> +
>>>> +		DRM_DEBUG("MOCS: Table set in Context\n");
>>>> +	} else {
>>>> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
>>>> +	}
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.h 
>> b/drivers/gpu/drm/i915/intel_mocs.h
>>>> new file mode 100644
>>>> index 0000000..e2780ce
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.h
>>>> @@ -0,0 +1,64 @@
>>>> +/*
>>>> + * Copyright (c) 2015 Intel Corporation
>>>> + *
>>>> + * Permission is hereby granted, free of charge, to any person obtaining 
>> a
>>>> + * copy of this software and associated documentation files (the 
>> "Software"),
>>>> + * to deal in the Software without restriction, including without 
>> limitation
>>>> + * the rights to use, copy, modify, merge, publish, distribute, 
>> sublicense,
>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>> + * Software is furnished to do so, subject to the following conditions:
>>>> + *
>>>> + * The above copyright notice and this permission notice (including the 
>> next
>>>> + * paragraph) shall be included in all copies or substantial portions of 
>> the
>>>> + * Software.
>>>> + *
>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
>> EXPRESS OR
>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
>> MERCHANTABILITY,
>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT 
>> SHALL
>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
>> OTHER
>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
>> ARISING FROM,
>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
>> IN THE
>>>> + * SOFTWARE.
>>>> + *
>>>> + * Authors:
>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>> + */
>>>> +
>>>> +#ifndef INTEL_MOCS_H
>>>> +#define INTEL_MOCS_H
>>>> +
>>>> +/**
>>>> + * DOC: Memory Objects Control State (MOCS)
>>>> + *
>>>> + * Motivation:
>>>> + * In previous Gens the MOCS settings was a value that was set by user 
>> land as
>>>> + * part of the batch. In Gen9 this has changed to be a single table (per 
>> ring)
>>>> + * that all batches now reference by index instead of programming the 
>> MOCS
>>>> + * directly.
>>>> + *
>>>> + * The one wrinkle in this is that only PART of the MOCS tables are 
>> included
>>>> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - 
>> LNCFCMOCS32
>>>> + * registers). The rest are not (the settings for the other rings).
>>>> + *
>>>> + * This table needs to be set at system start-up because the way the 
>> table
>>>> + * interacts with the contexts and the GmmLib interface.
>>>> + *
>>>> + *
>>>> + * Implementation:
>>>> + *
>>>> + * The table is programmed on a platform basis from a table that is 
>> generated
>>>> + * from the one that has been agreed by the different responsible 
>> parties. This
>>>> + * tables (one per supported platform) is defined in intel_mocs.c and is
>>>> + * programmed in the first batch after the context is loaded (with the 
>> hardware
>>>> + * workarounds). This will then let the usual context handling keep the 
>> MOCS in
>>>> + * step.
>>>> + */
>>>> +
>>>> +#include <drm/drmP.h>
>>>> +#include "i915_drv.h"
>>>> +
>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>> +			struct intel_context *ctx);
>>>> +
>>>> +#endif
>>>> +
>>>> --
>>>> 1.9.1
>>>>
>>>> _______________________________________________
>>>> Intel-gfx mailing list
>>>> Intel-gfx@lists.freedesktop.org
>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>
>>
>> --
>>    Peter Antoine (Android Graphics Driver Software Engineer)
>>    ---------------------------------------------------------------------
>>    Intel Corporation (UK) Limited
>>    Registered No. 1134945 (England)
>>    Registered Office: Pipers Way, Swindon SN3 1RJ
>>    VAT No: 860 2173 47
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>
>
> --
>     Peter Antoine (Android Graphics Driver Software Engineer)
>     ---------------------------------------------------------------------
>     Intel Corporation (UK) Limited
>     Registered No. 1134945 (England)
>     Registered Office: Pipers Way, Swindon SN3 1RJ
>     VAT No: 860 2173 47
Francisco Jerez June 30, 2015, 6:17 p.m. UTC | #16
Francisco Jerez <currojerez@riseup.net> writes:

> Peter Antoine <peter.antoine@intel.com> writes:
>
>> On Mon, 29 Jun 2015, Peter Antoine wrote:
>>
>>> On Thu, 25 Jun 2015, Francisco Jerez wrote:
>>>
>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>
>>>>> This change adds the programming of the MOCS registers to the gen 9+
>>>>> platforms. This change set programs the MOCS register values to a set
>>>>> of values that are defined to be optimal.
>>>>>
>>>>> It creates a fixed register set that is programmed across the different
>>>>> engines so that all engines have the same table. This is done as the
>>>>> main RCS context only holds the registers for itself and the shared
>>>>> L3 values. By trying to keep the registers consistent across the
>>>>> different engines it should make the programming for the registers
>>>>> consistent.
>>>>>
>>>>> v2:
>>>>> -'static const' for private data structures and style changes.(Matt 
>>> Turner)
>>>>> v3:
>>>>> - Make the tables "slightly" more readable. (Damien Lespiau)
>>>>> - Updated tables fix performance regression.
>>>>> v4:
>>>>> - Code formatting. (Chris Wilson)
>>>>> - re-privatised mocs code. (Daniel Vetter)
>>>>>
>>>>> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
>>>>> ---
>>>>>  drivers/gpu/drm/i915/Makefile     |   1 +
>>>>>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>>>>>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>>>>>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>>>>>  drivers/gpu/drm/i915/intel_mocs.c | 373 
>>> ++++++++++++++++++++++++++++++++++++++
>>>>>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>>>>>  6 files changed, 460 insertions(+), 1 deletion(-)
>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>>>>>
>>>>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>>>>> index b7ddf48..c781e19 100644
>>>>> --- a/drivers/gpu/drm/i915/Makefile
>>>>> +++ b/drivers/gpu/drm/i915/Makefile
>>>>> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>>>>>  	  i915_irq.o \
>>>>>  	  i915_trace_points.o \
>>>>>  	  intel_lrc.o \
>>>>> +	  intel_mocs.o \
>>>>>  	  intel_ringbuffer.o \
>>>>>  	  intel_uncore.o
>>>>>
>>>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h 
>>> b/drivers/gpu/drm/i915/i915_reg.h
>>>>> index 7213224..3a435b5 100644
>>>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>>>> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>>>>>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>>>>>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>>>>>
>>>>> +/* MOCS (Memory Object Control State) registers */
>>>>> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control 
>>> base */
>>>>> +
>>>>> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base 
>>> register*/
>>>>> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base 
>>> register*/
>>>>> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base 
>>> register*/
>>>>> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
>>>>> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base 
>>> register*/
>>>>> +
>>>>>  #endif /* _I915_REG_H_ */
>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c 
>>> b/drivers/gpu/drm/i915/intel_lrc.c
>>>>> index 9f5485d..73b919d 100644
>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>>>>> @@ -135,6 +135,7 @@
>>>>>  #include <drm/drmP.h>
>>>>>  #include <drm/i915_drm.h>
>>>>>  #include "i915_drv.h"
>>>>> +#include "intel_mocs.h"
>>>>>
>>>>>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>>>>>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
>>>>> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct 
>>> intel_ringbuffer *ringbuf,
>>>>>   *
>>>>>   * Return: non-zero if the ringbuffer is not ready to be written to.
>>>>>   */
>>>>> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>  				    struct intel_context *ctx, int 
>>> num_dwords)
>>>>>  {
>>>>>  	struct intel_engine_cs *ring = ringbuf->ring;
>>>>> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct 
>>> intel_engine_cs *ring,
>>>>>  	if (ret)
>>>>>  		return ret;
>>>>>
>>>>> +	/*
>>>>> +	 * Failing to program the MOCS is non-fatal.The system will not
>>>>> +	 * run at peak performance. So generate a warning and carry on.
>>>>> +	 */
>>>>> +	if (gen9_program_mocs(ring, ctx) != 0)
>>>>> +		DRM_ERROR("MOCS failed to program: expect performance 
>>> issues.");
>>>>> +
>>>>>  	return intel_lr_context_render_state_init(ring, ctx);
>>>>>  }
>>>>>
>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.h 
>>> b/drivers/gpu/drm/i915/intel_lrc.h
>>>>> index 04d3a6d..dbbd6af 100644
>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.h
>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.h
>>>>> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>>>>>
>>>>>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>>>>>  				  struct intel_context *ctx);
>>>>> +
>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>> +				    struct intel_context *ctx, int 
>>> num_dwords);
>>>>> +
>>>>>  /**
>>>>>   * intel_logical_ring_advance() - advance the ringbuffer tail
>>>>>   * @ringbuf: Ringbuffer to advance.
>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.c 
>>> b/drivers/gpu/drm/i915/intel_mocs.c
>>>>> new file mode 100644
>>>>> index 0000000..7c09e67
>>>>> --- /dev/null
>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.c
>>>>> @@ -0,0 +1,373 @@
>>>>> +/*
>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>> + *
>>>>> + * Permission is hereby granted, free of charge, to any person obtaining 
>>> a
>>>>> + * copy of this software and associated documentation files (the 
>>> "Software"),
>>>>> + * to deal in the Software without restriction, including without 
>>> limitation
>>>>> + * the rights to use, copy, modify, merge, publish, distribute, 
>>> sublicense,
>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>> + * Software is furnished to do so, subject to the following conditions: *
>>>>> + * The above copyright notice and this permission notice (including the 
>>> next
>>>>> + * paragraph) shall be included in all copies or substantial portions of 
>>> the
>>>>> + * Software.
>>>>> + *
>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
>>> EXPRESS OR
>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
>>> MERCHANTABILITY,
>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT 
>>> SHALL
>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
>>> OTHER
>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
>>> ARISING FROM,
>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
>>> IN THE
>>>>> + * SOFTWARE.
>>>>> + *
>>>>> + * Authors:
>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>> + */
>>>>> +
>>>>> +#include "intel_mocs.h"
>>>>> +#include "intel_lrc.h"
>>>>> +#include "intel_ringbuffer.h"
>>>>> +
>>>>> +/* structures required */
>>>>> +struct drm_i915_mocs_entry {
>>>>> +	u32	control_value;
>>>>> +	u16	l3cc_value;
>>>>> +};
>>>>> +
>>>>> +struct drm_i915_mocs_table {
>>>>> +	u32					size;
>>>>> +	const struct drm_i915_mocs_entry	*table;
>>>>> +};
>>>>> +
>>>>> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
>>>>> +#define	MOCS_CACHEABILITY(value)	(value << 0)
>>>>> +#define	MOCS_TGT_CACHE(value)		(value << 2)
>>>>> +#define	MOCS_LRUM(value)		(value << 4)
>>>>> +#define	MOCS_AOM(value)			(value << 6)
>>>>> +#define	MOCS_LECC_ESC(value)		(value << 7)
>>>>> +#define	MOCS_LECC_SCC(value)		(value << 8)
>>>>> +#define	MOC_PFM(value)			(value << 11)
>>>>> +#define	MOCS_SCF(value)			(value << 14)
>>>>> +
>>>>> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word 
>>> */
>>>>> +#define	MOCS_ESC(value)			(value << 0)
>>>>> +#define	MOCS_SCC(value)			(value << 1)
>>>>> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
>>>>> +
>>>>> +/* Helper defines */
>>>>> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program 
>>> */
>>>>> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd 
>>> */
>>>>> +
>>>>> +/* EDRAM Caching options */
>>>>> +#define EDRAM_PAGETABLE		(0)
>>>>> +#define EDRAM_UC		(1)
>>>>> +#define EDRAM_RESERVED		(2)
>>>>
>>>> According to the BSpec this is WT rather than reserved?a
>>> Just checked the Bspec and you are correct, changing the text.
>>> As well as for the items below.
>> Just to add - I was looking at the wrong gen.
>>>>
>>>>> +#define EDRAM_WB		(3)
>>>>> +
>>>>> +/* L3 Caching options */
>>>>> +#define L3_DIRECT		(0)
>>>>> +#define L3_UC			(1)
>>>>> +#define L3_RESERVED		(2)
>>>>> +#define L3_WB			(3)
>>>>> +
>>>>> +/* target cache */
>>>>> +#define ELLC			(0)
>>>>
>>>> BSpec says that this is "Use TC/LRU controls from page table", but upon
>>>> a closer look it seems like the BSpec is wrong and your patch is
>>>> correct.  Can you confirm that this is what you intended?
>>> These values look good, they are bits 3:2 for the XXX_MOCS_N registers 
>>> (c800) and friends. 
>>>>
>>>>> +#define LLC			(1)
>>>>> +#define LLC_ELLC		(2)
>>>>> +
>>>>> +/*
>>>>> + * MOCS tables
>>>>> + *
>>>>> + * These are the MOCS tables that are programmed across all the rings.
>>>>> + * The control value is programmed to all the rings that support the
>>>>> + * MOCS registers. While the l3cc_values are only programmed to the
>>>>> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
>>>>> + *
>>>>> + * NOTE: These tables MUST start with being uncached and the length MUST 
>>> be
>>>>> + *       less than 63 as the last two registers are reserved by the 
>>> hardware.
>>>>> + */
>>>>> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
>>>>> +	 /* {0x00000009, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +	 /* {0x0000003b, 0x0030} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>> +	 /* {0x00000039, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +	 /* {0x00000017, 0x0030} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>> +	 /* {0x00000017, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +	 /* {0x00000019, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +	 /* {0x00000037, 0x0030} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>> +	 /* {0x00000037, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +};
>>>>
>>>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE, L3CC=WB,
>>>> everything else unset, I'll reply with a userspace patch making use of
>>>> your change if you add such an entry.
>> Ok. I think what you want is, same as entry two, but use the underlying
>> pagetable settings and not specify the EDRAM settings. Please confirm in 
>> the new patchset.
>
> Yeah, that sounds good.
>
>>>>
>>>> Another thing worth mentioning is that entries 0, 2 and 5 seem to do the
>>>> same thing suspiciously, the only difference is the LRUM field which
>>>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding correct?
>>>>
>>> These tables are generated via requests and then boiled down to the above. 
>>> So some of the entries are by request. Swings and roundabouts, can remove 
>>> the ones that look redundant but then the tuning that has been done wont 
>>> match. I'll add the new entry at the end of the table.

Are you planning to propagate the entry you just added back to the
original table this was generated from?  What about new entries we may
need to add in the future?  What should be the process to make sure that
our table and the master table don't diverge and end up with conflicting
entries we cannot remove because of ABI compatibility?  I guess there
should be a comment on the top warning that the table is part of the
kernel ABI and supposed to be kept in sync with your table, so other
people don't change it unknowingly?

Thanks.

>>>>> +
>>>>> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
>>>>> +	 /* {0x00000001, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +	 /* {0x00000005, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +	 /* {0x00000005, 0x0030} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>> +	 /* {0x00000017, 0x0030} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>> +	 /* {0x00000017, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +	 /* {0x00000019, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +	 /* {0x00000037, 0x0030} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>> +	 /* {0x00000037, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>> +};
>>>>> +
>>>>
>>>> Wouldn't it be a good idea to have BXT's entries match SKL's for a given
>>>> index?  The TC, LeCC and LRUM settings you do here arguably don't have
>>>> any effect on BXT, L3CC does but it doesn't match SKL's setting for
>>>> entries 1 and 2.  Is there any reason for this?
>>> As mentioned above this table is auto-generated and matches another tuned 
>>> table, simply keeping them the same allows for the tuning to be consistent 
>>> across platforms.
>>>
>>> Peter.
>>>>
>>>> Other than that looks good.
>>>>
>>>>> +/**
>>>>> + * get_mocs_settings
>>>>> + *
>>>>> + * 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
>>>>> + * to be programmed and if they need to be programmed.
>>>>> + *
>>>>> + * If the return values is false then the registers do not need 
>>> programming.
>>>>> + */
>>>>> +static bool get_mocs_settings(struct drm_device *dev,
>>>>> +			      struct drm_i915_mocs_table *table) {
>>>>> +	bool	result = false;
>>>>> +
>>>>> +	if (IS_SKYLAKE(dev)) {
>>>>> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
>>>>> +		table->table = skylake_mocs_table;
>>>>> +		result = true;
>>>>> +	} else if (IS_BROXTON(dev)) {
>>>>> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
>>>>> +		table->table = broxton_mocs_table;
>>>>> +		result = true;
>>>>> +	} else {
>>>>> +		/* Platform that should have a MOCS table does not */
>>>>> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
>>>>> +	}
>>>>> +
>>>>> +	return result;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * emit_mocs_control_table() - emit the mocs control table
>>>>> + * @ringbuf:	DRM device.
>>>>> + * @table:	The values to program into the control regs.
>>>>> + * @reg_base:	The base for the Engine that needs to be programmed.
>>>>> + *
>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>> + * given table starting at the given address.
>>>>> + *
>>>>> + * Return: Nothing.
>>>>> + */
>>>>> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
>>>>> +				    struct drm_i915_mocs_table *table,
>>>>> +				    u32 reg_base)
>>>>> +{
>>>>> +	unsigned int index;
>>>>> +
>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
>>>>> +
>>>>> +	for (index = 0; index < table->size; index++) {
>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>> +		intel_logical_ring_emit(ringbuf,
>>>>> +					table->table[index].control_value);
>>>>> +	}
>>>>> +
>>>>> +	/*
>>>>> +	 * Ok, now set the unused entries to uncached. These entries are
>>>>> +	 * officially undefined and no contact is given for the contents and
>>>>> +	 * settings is given for these entries.
>>>>> +	 *
>>>>> +	 * Entry 0 in the table is uncached - so we are just written that
>>>>> +	 * value to all the used entries.
>>>>> +	 */
>>>>> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>> +		intel_logical_ring_emit(ringbuf, 
>>> table->table[0].control_value);
>>>>> +	}
>>>>> +
>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * emit_mocs_l3cc_table() - emit the mocs control table
>>>>> + * @ringbuf:	DRM device.
>>>>> + * @table:	The values to program into the control regs.
>>>>> + *
>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>> + * given table starting at the given address. This register set is 
>>> programmed
>>>>> + * in pairs.
>>>>> + *
>>>>> + * Return: Nothing.
>>>>> + */
>>>>> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
>>>>> +			 struct drm_i915_mocs_table *table) {
>>>>> +	unsigned int count;
>>>>> +	unsigned int i;
>>>>> +	u32 value;
>>>>> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
>>>>> +			((table->table[0].l3cc_value & 0xffff) << 16);
>>>>> +
>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
>>>>> +
>>>>> +	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);
>>>>> +
>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>> +		intel_logical_ring_emit(ringbuf, value);
>>>>> +
>>>>> +		value = filler;
>>>>> +	}
>>>>> +
>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>> +}
>>>>> +
>>>>> +/*
>>>>> + * gen9_program_mocs() - program the MOCS register.
>>>>> + *
>>>>> + * ring:	The ring that the programming batch will be run in.
>>>>> + * ctx:		The intel_context to be used.
>>>>> + *
>>>>> + * This function will emit a batch buffer with the values required for
>>>>> + * programming the MOCS register values for all the currently supported
>>>>> + * rings.
>>>>> + *
>>>>> + * These registers are partially stored in the RCS context, so they are
>>>>> + * emitted at the same time so that when a context is created these 
>>> registers
>>>>> + * are set up. These registers have to be emitted into the start of the
>>>>> + * context as setting the ELSP will re-init some of these registers back
>>>>> + * to the hw values.
>>>>> + *
>>>>> + * Return: 0 on success, otherwise the error status.
>>>>> + */
>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>> +			  struct intel_context *ctx)
>>>>> +{
>>>>> +	int ret = 0;
>>>>> +
>>>>> +	struct drm_i915_mocs_table t;
>>>>> +	struct drm_device *dev = ring->dev;
>>>>> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
>>>>> +
>>>>> +	if (get_mocs_settings(dev, &t)) {
>>>>> +		u32 table_size;
>>>>> +
>>>>> +		/*
>>>>> +		 * OK. For each supported ring:
>>>>> +		 *  number of mocs entries * 2 dwords for each control_value
>>>>> +		 *  plus number of mocs entries /2 dwords for l3cc values.
>>>>> +		 *
>>>>> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
>>>>> +		 *  and the l3cc programming.
>>>>> +		 */
>>>>> +		table_size = GEN9_NUM_MOCS_RINGS *
>>>>> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
>>>>> +				GEN9_NUM_MOCS_ENTRIES + 2;
>>>>> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
>>>>> +		if (ret) {
>>>>> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n", 
>>> ret);
>>>>> +			return ret;
>>>>> +		}
>>>>> +
>>>>> +		/* program the control registers */
>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
>>>>> +
>>>>> +		/* now program the l3cc registers */
>>>>> +		emit_mocs_l3cc_table(ringbuf, &t);
>>>>> +
>>>>> +		intel_logical_ring_advance(ringbuf);
>>>>> +
>>>>> +		DRM_DEBUG("MOCS: Table set in Context\n");
>>>>> +	} else {
>>>>> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
>>>>> +	}
>>>>> +
>>>>> +	return ret;
>>>>> +}
>>>>> +
>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.h 
>>> b/drivers/gpu/drm/i915/intel_mocs.h
>>>>> new file mode 100644
>>>>> index 0000000..e2780ce
>>>>> --- /dev/null
>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.h
>>>>> @@ -0,0 +1,64 @@
>>>>> +/*
>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>> + *
>>>>> + * Permission is hereby granted, free of charge, to any person obtaining 
>>> a
>>>>> + * copy of this software and associated documentation files (the 
>>> "Software"),
>>>>> + * to deal in the Software without restriction, including without 
>>> limitation
>>>>> + * the rights to use, copy, modify, merge, publish, distribute, 
>>> sublicense,
>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>> + * Software is furnished to do so, subject to the following conditions:
>>>>> + *
>>>>> + * The above copyright notice and this permission notice (including the 
>>> next
>>>>> + * paragraph) shall be included in all copies or substantial portions of 
>>> the
>>>>> + * Software.
>>>>> + *
>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
>>> EXPRESS OR
>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
>>> MERCHANTABILITY,
>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT 
>>> SHALL
>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
>>> OTHER
>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
>>> ARISING FROM,
>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
>>> IN THE
>>>>> + * SOFTWARE.
>>>>> + *
>>>>> + * Authors:
>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>> + */
>>>>> +
>>>>> +#ifndef INTEL_MOCS_H
>>>>> +#define INTEL_MOCS_H
>>>>> +
>>>>> +/**
>>>>> + * DOC: Memory Objects Control State (MOCS)
>>>>> + *
>>>>> + * Motivation:
>>>>> + * In previous Gens the MOCS settings was a value that was set by user 
>>> land as
>>>>> + * part of the batch. In Gen9 this has changed to be a single table (per 
>>> ring)
>>>>> + * that all batches now reference by index instead of programming the 
>>> MOCS
>>>>> + * directly.
>>>>> + *
>>>>> + * The one wrinkle in this is that only PART of the MOCS tables are 
>>> included
>>>>> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - 
>>> LNCFCMOCS32
>>>>> + * registers). The rest are not (the settings for the other rings).
>>>>> + *
>>>>> + * This table needs to be set at system start-up because the way the 
>>> table
>>>>> + * interacts with the contexts and the GmmLib interface.
>>>>> + *
>>>>> + *
>>>>> + * Implementation:
>>>>> + *
>>>>> + * The table is programmed on a platform basis from a table that is 
>>> generated
>>>>> + * from the one that has been agreed by the different responsible 
>>> parties. This
>>>>> + * tables (one per supported platform) is defined in intel_mocs.c and is
>>>>> + * programmed in the first batch after the context is loaded (with the 
>>> hardware
>>>>> + * workarounds). This will then let the usual context handling keep the 
>>> MOCS in
>>>>> + * step.
>>>>> + */
>>>>> +
>>>>> +#include <drm/drmP.h>
>>>>> +#include "i915_drv.h"
>>>>> +
>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>> +			struct intel_context *ctx);
>>>>> +
>>>>> +#endif
>>>>> +
>>>>> --
>>>>> 1.9.1
>>>>>
>>>>> _______________________________________________
>>>>> Intel-gfx mailing list
>>>>> Intel-gfx@lists.freedesktop.org
>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>
>>>
>>> --
>>>    Peter Antoine (Android Graphics Driver Software Engineer)
>>>    ---------------------------------------------------------------------
>>>    Intel Corporation (UK) Limited
>>>    Registered No. 1134945 (England)
>>>    Registered Office: Pipers Way, Swindon SN3 1RJ
>>>    VAT No: 860 2173 47
>>> _______________________________________________
>>> Intel-gfx mailing list
>>> Intel-gfx@lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>
>>
>> --
>>     Peter Antoine (Android Graphics Driver Software Engineer)
>>     ---------------------------------------------------------------------
>>     Intel Corporation (UK) Limited
>>     Registered No. 1134945 (England)
>>     Registered Office: Pipers Way, Swindon SN3 1RJ
>>     VAT No: 860 2173 47
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Peter Antoine July 1, 2015, 7:29 a.m. UTC | #17
On Tue, 30 Jun 2015, Francisco Jerez wrote:

> Francisco Jerez <currojerez@riseup.net> writes:
>
>> Peter Antoine <peter.antoine@intel.com> writes:
>>
>>> On Mon, 29 Jun 2015, Peter Antoine wrote:
>>>
>>>> On Thu, 25 Jun 2015, Francisco Jerez wrote:
>>>>
>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>
>>>>>> This change adds the programming of the MOCS registers to the gen 9+
>>>>>> platforms. This change set programs the MOCS register values to a set
>>>>>> of values that are defined to be optimal.
>>>>>>
>>>>>> It creates a fixed register set that is programmed across the different
>>>>>> engines so that all engines have the same table. This is done as the
>>>>>> main RCS context only holds the registers for itself and the shared
>>>>>> L3 values. By trying to keep the registers consistent across the
>>>>>> different engines it should make the programming for the registers
>>>>>> consistent.
>>>>>>
>>>>>> v2:
>>>>>> -'static const' for private data structures and style changes.(Matt
>>>> Turner)
>>>>>> v3:
>>>>>> - Make the tables "slightly" more readable. (Damien Lespiau)
>>>>>> - Updated tables fix performance regression.
>>>>>> v4:
>>>>>> - Code formatting. (Chris Wilson)
>>>>>> - re-privatised mocs code. (Daniel Vetter)
>>>>>>
>>>>>> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
>>>>>> ---
>>>>>>  drivers/gpu/drm/i915/Makefile     |   1 +
>>>>>>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>>>>>>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>>>>>>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>>>>>>  drivers/gpu/drm/i915/intel_mocs.c | 373
>>>> ++++++++++++++++++++++++++++++++++++++
>>>>>>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>>>>>>  6 files changed, 460 insertions(+), 1 deletion(-)
>>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>>>>>> index b7ddf48..c781e19 100644
>>>>>> --- a/drivers/gpu/drm/i915/Makefile
>>>>>> +++ b/drivers/gpu/drm/i915/Makefile
>>>>>> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>>>>>>  	  i915_irq.o \
>>>>>>  	  i915_trace_points.o \
>>>>>>  	  intel_lrc.o \
>>>>>> +	  intel_mocs.o \
>>>>>>  	  intel_ringbuffer.o \
>>>>>>  	  intel_uncore.o
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h
>>>> b/drivers/gpu/drm/i915/i915_reg.h
>>>>>> index 7213224..3a435b5 100644
>>>>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>>>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>>>>> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>>>>>>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>>>>>>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>>>>>>
>>>>>> +/* MOCS (Memory Object Control State) registers */
>>>>>> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control
>>>> base */
>>>>>> +
>>>>>> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base
>>>> register*/
>>>>>> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base
>>>> register*/
>>>>>> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base
>>>> register*/
>>>>>> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
>>>>>> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base
>>>> register*/
>>>>>> +
>>>>>>  #endif /* _I915_REG_H_ */
>>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c
>>>> b/drivers/gpu/drm/i915/intel_lrc.c
>>>>>> index 9f5485d..73b919d 100644
>>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>>>>>> @@ -135,6 +135,7 @@
>>>>>>  #include <drm/drmP.h>
>>>>>>  #include <drm/i915_drm.h>
>>>>>>  #include "i915_drv.h"
>>>>>> +#include "intel_mocs.h"
>>>>>>
>>>>>>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>>>>>>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
>>>>>> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct
>>>> intel_ringbuffer *ringbuf,
>>>>>>   *
>>>>>>   * Return: non-zero if the ringbuffer is not ready to be written to.
>>>>>>   */
>>>>>> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>  				    struct intel_context *ctx, int
>>>> num_dwords)
>>>>>>  {
>>>>>>  	struct intel_engine_cs *ring = ringbuf->ring;
>>>>>> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct
>>>> intel_engine_cs *ring,
>>>>>>  	if (ret)
>>>>>>  		return ret;
>>>>>>
>>>>>> +	/*
>>>>>> +	 * Failing to program the MOCS is non-fatal.The system will not
>>>>>> +	 * run at peak performance. So generate a warning and carry on.
>>>>>> +	 */
>>>>>> +	if (gen9_program_mocs(ring, ctx) != 0)
>>>>>> +		DRM_ERROR("MOCS failed to program: expect performance
>>>> issues.");
>>>>>> +
>>>>>>  	return intel_lr_context_render_state_init(ring, ctx);
>>>>>>  }
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.h
>>>> b/drivers/gpu/drm/i915/intel_lrc.h
>>>>>> index 04d3a6d..dbbd6af 100644
>>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.h
>>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.h
>>>>>> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>>>>>>
>>>>>>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>>>>>>  				  struct intel_context *ctx);
>>>>>> +
>>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>> +				    struct intel_context *ctx, int
>>>> num_dwords);
>>>>>> +
>>>>>>  /**
>>>>>>   * intel_logical_ring_advance() - advance the ringbuffer tail
>>>>>>   * @ringbuf: Ringbuffer to advance.
>>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.c
>>>> b/drivers/gpu/drm/i915/intel_mocs.c
>>>>>> new file mode 100644
>>>>>> index 0000000..7c09e67
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.c
>>>>>> @@ -0,0 +1,373 @@
>>>>>> +/*
>>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>>> + *
>>>>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>>> a
>>>>>> + * copy of this software and associated documentation files (the
>>>> "Software"),
>>>>>> + * to deal in the Software without restriction, including without
>>>> limitation
>>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>> sublicense,
>>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>>> + * Software is furnished to do so, subject to the following conditions: *
>>>>>> + * The above copyright notice and this permission notice (including the
>>>> next
>>>>>> + * paragraph) shall be included in all copies or substantial portions of
>>>> the
>>>>>> + * Software.
>>>>>> + *
>>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>> EXPRESS OR
>>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>> MERCHANTABILITY,
>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>>>> SHALL
>>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>> OTHER
>>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>> ARISING FROM,
>>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>>> IN THE
>>>>>> + * SOFTWARE.
>>>>>> + *
>>>>>> + * Authors:
>>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>>> + */
>>>>>> +
>>>>>> +#include "intel_mocs.h"
>>>>>> +#include "intel_lrc.h"
>>>>>> +#include "intel_ringbuffer.h"
>>>>>> +
>>>>>> +/* structures required */
>>>>>> +struct drm_i915_mocs_entry {
>>>>>> +	u32	control_value;
>>>>>> +	u16	l3cc_value;
>>>>>> +};
>>>>>> +
>>>>>> +struct drm_i915_mocs_table {
>>>>>> +	u32					size;
>>>>>> +	const struct drm_i915_mocs_entry	*table;
>>>>>> +};
>>>>>> +
>>>>>> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
>>>>>> +#define	MOCS_CACHEABILITY(value)	(value << 0)
>>>>>> +#define	MOCS_TGT_CACHE(value)		(value << 2)
>>>>>> +#define	MOCS_LRUM(value)		(value << 4)
>>>>>> +#define	MOCS_AOM(value)			(value << 6)
>>>>>> +#define	MOCS_LECC_ESC(value)		(value << 7)
>>>>>> +#define	MOCS_LECC_SCC(value)		(value << 8)
>>>>>> +#define	MOC_PFM(value)			(value << 11)
>>>>>> +#define	MOCS_SCF(value)			(value << 14)
>>>>>> +
>>>>>> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word
>>>> */
>>>>>> +#define	MOCS_ESC(value)			(value << 0)
>>>>>> +#define	MOCS_SCC(value)			(value << 1)
>>>>>> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
>>>>>> +
>>>>>> +/* Helper defines */
>>>>>> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program
>>>> */
>>>>>> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd
>>>> */
>>>>>> +
>>>>>> +/* EDRAM Caching options */
>>>>>> +#define EDRAM_PAGETABLE		(0)
>>>>>> +#define EDRAM_UC		(1)
>>>>>> +#define EDRAM_RESERVED		(2)
>>>>>
>>>>> According to the BSpec this is WT rather than reserved?a
>>>> Just checked the Bspec and you are correct, changing the text.
>>>> As well as for the items below.
>>> Just to add - I was looking at the wrong gen.
>>>>>
>>>>>> +#define EDRAM_WB		(3)
>>>>>> +
>>>>>> +/* L3 Caching options */
>>>>>> +#define L3_DIRECT		(0)
>>>>>> +#define L3_UC			(1)
>>>>>> +#define L3_RESERVED		(2)
>>>>>> +#define L3_WB			(3)
>>>>>> +
>>>>>> +/* target cache */
>>>>>> +#define ELLC			(0)
>>>>>
>>>>> BSpec says that this is "Use TC/LRU controls from page table", but upon
>>>>> a closer look it seems like the BSpec is wrong and your patch is
>>>>> correct.  Can you confirm that this is what you intended?
>>>> These values look good, they are bits 3:2 for the XXX_MOCS_N registers
>>>> (c800) and friends.
>>>>>
>>>>>> +#define LLC			(1)
>>>>>> +#define LLC_ELLC		(2)
>>>>>> +
>>>>>> +/*
>>>>>> + * MOCS tables
>>>>>> + *
>>>>>> + * These are the MOCS tables that are programmed across all the rings.
>>>>>> + * The control value is programmed to all the rings that support the
>>>>>> + * MOCS registers. While the l3cc_values are only programmed to the
>>>>>> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
>>>>>> + *
>>>>>> + * NOTE: These tables MUST start with being uncached and the length MUST
>>>> be
>>>>>> + *       less than 63 as the last two registers are reserved by the
>>>> hardware.
>>>>>> + */
>>>>>> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
>>>>>> +	 /* {0x00000009, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +	 /* {0x0000003b, 0x0030} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>> +	 /* {0x00000039, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +	 /* {0x00000017, 0x0030} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>> +	 /* {0x00000017, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +	 /* {0x00000019, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +	 /* {0x00000037, 0x0030} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>> +	 /* {0x00000037, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +};
>>>>>
>>>>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE, L3CC=WB,
>>>>> everything else unset, I'll reply with a userspace patch making use of
>>>>> your change if you add such an entry.
>>> Ok. I think what you want is, same as entry two, but use the underlying
>>> pagetable settings and not specify the EDRAM settings. Please confirm in
>>> the new patchset.
>>
>> Yeah, that sounds good.
>>
>>>>>
>>>>> Another thing worth mentioning is that entries 0, 2 and 5 seem to do the
>>>>> same thing suspiciously, the only difference is the LRUM field which
>>>>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding correct?
>>>>>
>>>> These tables are generated via requests and then boiled down to the above.
>>>> So some of the entries are by request. Swings and roundabouts, can remove
>>>> the ones that look redundant but then the tuning that has been done wont
>>>> match. I'll add the new entry at the end of the table.
>
> Are you planning to propagate the entry you just added back to the
> original table this was generated from?  What about new entries we may
> need to add in the future?  What should be the process to make sure that
> our table and the master table don't diverge and end up with conflicting
> entries we cannot remove because of ABI compatibility?  I guess there
> should be a comment on the top warning that the table is part of the
> kernel ABI and supposed to be kept in sync with your table, so other
> people don't change it unknowingly?
>
> Thanks.
I am talking to the team that handles this and see if they will add this 
(so future gens this is baked in) but it is unlikely that the other tables 
will stay in step as getting in changes will cause too much grief getting 
them upstreamed and as the table is auto-generated we will not be able to 
guarantee the ordering. It will have to be manual job for anyone doing 
this. It is required for other platforms for the tables to match the 
userspace for performance reasons, but on Linux it will be by request if 
there is a problem. We will see what happens.

Peter.

>
>>>>>> +
>>>>>> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
>>>>>> +	 /* {0x00000001, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +	 /* {0x00000005, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +	 /* {0x00000005, 0x0030} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>> +	 /* {0x00000017, 0x0030} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>> +	 /* {0x00000017, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +	 /* {0x00000019, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +	 /* {0x00000037, 0x0030} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>> +	 /* {0x00000037, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>> +};
>>>>>> +
>>>>>
>>>>> Wouldn't it be a good idea to have BXT's entries match SKL's for a given
>>>>> index?  The TC, LeCC and LRUM settings you do here arguably don't have
>>>>> any effect on BXT, L3CC does but it doesn't match SKL's setting for
>>>>> entries 1 and 2.  Is there any reason for this?
>>>> As mentioned above this table is auto-generated and matches another tuned
>>>> table, simply keeping them the same allows for the tuning to be consistent
>>>> across platforms.
>>>>
>>>> Peter.
>>>>>
>>>>> Other than that looks good.
>>>>>
>>>>>> +/**
>>>>>> + * get_mocs_settings
>>>>>> + *
>>>>>> + * 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
>>>>>> + * to be programmed and if they need to be programmed.
>>>>>> + *
>>>>>> + * If the return values is false then the registers do not need
>>>> programming.
>>>>>> + */
>>>>>> +static bool get_mocs_settings(struct drm_device *dev,
>>>>>> +			      struct drm_i915_mocs_table *table) {
>>>>>> +	bool	result = false;
>>>>>> +
>>>>>> +	if (IS_SKYLAKE(dev)) {
>>>>>> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
>>>>>> +		table->table = skylake_mocs_table;
>>>>>> +		result = true;
>>>>>> +	} else if (IS_BROXTON(dev)) {
>>>>>> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
>>>>>> +		table->table = broxton_mocs_table;
>>>>>> +		result = true;
>>>>>> +	} else {
>>>>>> +		/* Platform that should have a MOCS table does not */
>>>>>> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
>>>>>> +	}
>>>>>> +
>>>>>> +	return result;
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * emit_mocs_control_table() - emit the mocs control table
>>>>>> + * @ringbuf:	DRM device.
>>>>>> + * @table:	The values to program into the control regs.
>>>>>> + * @reg_base:	The base for the Engine that needs to be programmed.
>>>>>> + *
>>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>>> + * given table starting at the given address.
>>>>>> + *
>>>>>> + * Return: Nothing.
>>>>>> + */
>>>>>> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
>>>>>> +				    struct drm_i915_mocs_table *table,
>>>>>> +				    u32 reg_base)
>>>>>> +{
>>>>>> +	unsigned int index;
>>>>>> +
>>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
>>>>>> +
>>>>>> +	for (index = 0; index < table->size; index++) {
>>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>>> +		intel_logical_ring_emit(ringbuf,
>>>>>> +					table->table[index].control_value);
>>>>>> +	}
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * Ok, now set the unused entries to uncached. These entries are
>>>>>> +	 * officially undefined and no contact is given for the contents and
>>>>>> +	 * settings is given for these entries.
>>>>>> +	 *
>>>>>> +	 * Entry 0 in the table is uncached - so we are just written that
>>>>>> +	 * value to all the used entries.
>>>>>> +	 */
>>>>>> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
>>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>>> +		intel_logical_ring_emit(ringbuf,
>>>> table->table[0].control_value);
>>>>>> +	}
>>>>>> +
>>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * emit_mocs_l3cc_table() - emit the mocs control table
>>>>>> + * @ringbuf:	DRM device.
>>>>>> + * @table:	The values to program into the control regs.
>>>>>> + *
>>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>>> + * given table starting at the given address. This register set is
>>>> programmed
>>>>>> + * in pairs.
>>>>>> + *
>>>>>> + * Return: Nothing.
>>>>>> + */
>>>>>> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
>>>>>> +			 struct drm_i915_mocs_table *table) {
>>>>>> +	unsigned int count;
>>>>>> +	unsigned int i;
>>>>>> +	u32 value;
>>>>>> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
>>>>>> +			((table->table[0].l3cc_value & 0xffff) << 16);
>>>>>> +
>>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
>>>>>> +
>>>>>> +	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);
>>>>>> +
>>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>>> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
>>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>>> +		intel_logical_ring_emit(ringbuf, value);
>>>>>> +
>>>>>> +		value = filler;
>>>>>> +	}
>>>>>> +
>>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>> + * gen9_program_mocs() - program the MOCS register.
>>>>>> + *
>>>>>> + * ring:	The ring that the programming batch will be run in.
>>>>>> + * ctx:		The intel_context to be used.
>>>>>> + *
>>>>>> + * This function will emit a batch buffer with the values required for
>>>>>> + * programming the MOCS register values for all the currently supported
>>>>>> + * rings.
>>>>>> + *
>>>>>> + * These registers are partially stored in the RCS context, so they are
>>>>>> + * emitted at the same time so that when a context is created these
>>>> registers
>>>>>> + * are set up. These registers have to be emitted into the start of the
>>>>>> + * context as setting the ELSP will re-init some of these registers back
>>>>>> + * to the hw values.
>>>>>> + *
>>>>>> + * Return: 0 on success, otherwise the error status.
>>>>>> + */
>>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>>> +			  struct intel_context *ctx)
>>>>>> +{
>>>>>> +	int ret = 0;
>>>>>> +
>>>>>> +	struct drm_i915_mocs_table t;
>>>>>> +	struct drm_device *dev = ring->dev;
>>>>>> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
>>>>>> +
>>>>>> +	if (get_mocs_settings(dev, &t)) {
>>>>>> +		u32 table_size;
>>>>>> +
>>>>>> +		/*
>>>>>> +		 * OK. For each supported ring:
>>>>>> +		 *  number of mocs entries * 2 dwords for each control_value
>>>>>> +		 *  plus number of mocs entries /2 dwords for l3cc values.
>>>>>> +		 *
>>>>>> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
>>>>>> +		 *  and the l3cc programming.
>>>>>> +		 */
>>>>>> +		table_size = GEN9_NUM_MOCS_RINGS *
>>>>>> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
>>>>>> +				GEN9_NUM_MOCS_ENTRIES + 2;
>>>>>> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
>>>>>> +		if (ret) {
>>>>>> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n",
>>>> ret);
>>>>>> +			return ret;
>>>>>> +		}
>>>>>> +
>>>>>> +		/* program the control registers */
>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
>>>>>> +
>>>>>> +		/* now program the l3cc registers */
>>>>>> +		emit_mocs_l3cc_table(ringbuf, &t);
>>>>>> +
>>>>>> +		intel_logical_ring_advance(ringbuf);
>>>>>> +
>>>>>> +		DRM_DEBUG("MOCS: Table set in Context\n");
>>>>>> +	} else {
>>>>>> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
>>>>>> +	}
>>>>>> +
>>>>>> +	return ret;
>>>>>> +}
>>>>>> +
>>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.h
>>>> b/drivers/gpu/drm/i915/intel_mocs.h
>>>>>> new file mode 100644
>>>>>> index 0000000..e2780ce
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.h
>>>>>> @@ -0,0 +1,64 @@
>>>>>> +/*
>>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>>> + *
>>>>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>>> a
>>>>>> + * copy of this software and associated documentation files (the
>>>> "Software"),
>>>>>> + * to deal in the Software without restriction, including without
>>>> limitation
>>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>> sublicense,
>>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>>> + * Software is furnished to do so, subject to the following conditions:
>>>>>> + *
>>>>>> + * The above copyright notice and this permission notice (including the
>>>> next
>>>>>> + * paragraph) shall be included in all copies or substantial portions of
>>>> the
>>>>>> + * Software.
>>>>>> + *
>>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>> EXPRESS OR
>>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>> MERCHANTABILITY,
>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>>>> SHALL
>>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>> OTHER
>>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>> ARISING FROM,
>>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>>> IN THE
>>>>>> + * SOFTWARE.
>>>>>> + *
>>>>>> + * Authors:
>>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef INTEL_MOCS_H
>>>>>> +#define INTEL_MOCS_H
>>>>>> +
>>>>>> +/**
>>>>>> + * DOC: Memory Objects Control State (MOCS)
>>>>>> + *
>>>>>> + * Motivation:
>>>>>> + * In previous Gens the MOCS settings was a value that was set by user
>>>> land as
>>>>>> + * part of the batch. In Gen9 this has changed to be a single table (per
>>>> ring)
>>>>>> + * that all batches now reference by index instead of programming the
>>>> MOCS
>>>>>> + * directly.
>>>>>> + *
>>>>>> + * The one wrinkle in this is that only PART of the MOCS tables are
>>>> included
>>>>>> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 -
>>>> LNCFCMOCS32
>>>>>> + * registers). The rest are not (the settings for the other rings).
>>>>>> + *
>>>>>> + * This table needs to be set at system start-up because the way the
>>>> table
>>>>>> + * interacts with the contexts and the GmmLib interface.
>>>>>> + *
>>>>>> + *
>>>>>> + * Implementation:
>>>>>> + *
>>>>>> + * The table is programmed on a platform basis from a table that is
>>>> generated
>>>>>> + * from the one that has been agreed by the different responsible
>>>> parties. This
>>>>>> + * tables (one per supported platform) is defined in intel_mocs.c and is
>>>>>> + * programmed in the first batch after the context is loaded (with the
>>>> hardware
>>>>>> + * workarounds). This will then let the usual context handling keep the
>>>> MOCS in
>>>>>> + * step.
>>>>>> + */
>>>>>> +
>>>>>> +#include <drm/drmP.h>
>>>>>> +#include "i915_drv.h"
>>>>>> +
>>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>>> +			struct intel_context *ctx);
>>>>>> +
>>>>>> +#endif
>>>>>> +
>>>>>> --
>>>>>> 1.9.1
>>>>>>
>>>>>> _______________________________________________
>>>>>> Intel-gfx mailing list
>>>>>> Intel-gfx@lists.freedesktop.org
>>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>>
>>>>
>>>> --
>>>>    Peter Antoine (Android Graphics Driver Software Engineer)
>>>>    ---------------------------------------------------------------------
>>>>    Intel Corporation (UK) Limited
>>>>    Registered No. 1134945 (England)
>>>>    Registered Office: Pipers Way, Swindon SN3 1RJ
>>>>    VAT No: 860 2173 47
>>>> _______________________________________________
>>>> Intel-gfx mailing list
>>>> Intel-gfx@lists.freedesktop.org
>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>
>>>
>>> --
>>>     Peter Antoine (Android Graphics Driver Software Engineer)
>>>     ---------------------------------------------------------------------
>>>     Intel Corporation (UK) Limited
>>>     Registered No. 1134945 (England)
>>>     Registered Office: Pipers Way, Swindon SN3 1RJ
>>>     VAT No: 860 2173 47
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>

--
    Peter Antoine (Android Graphics Driver Software Engineer)
    ---------------------------------------------------------------------
    Intel Corporation (UK) Limited
    Registered No. 1134945 (England)
    Registered Office: Pipers Way, Swindon SN3 1RJ
    VAT No: 860 2173 47
Francisco Jerez July 1, 2015, 1:05 p.m. UTC | #18
Peter Antoine <peter.antoine@intel.com> writes:

> On Tue, 30 Jun 2015, Francisco Jerez wrote:
>
>> Francisco Jerez <currojerez@riseup.net> writes:
>>
>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>
>>>> On Mon, 29 Jun 2015, Peter Antoine wrote:
>>>>
>>>>> On Thu, 25 Jun 2015, Francisco Jerez wrote:
>>>>>
>>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>>
>>>>>>> This change adds the programming of the MOCS registers to the gen 9+
>>>>>>> platforms. This change set programs the MOCS register values to a set
>>>>>>> of values that are defined to be optimal.
>>>>>>>
>>>>>>> It creates a fixed register set that is programmed across the different
>>>>>>> engines so that all engines have the same table. This is done as the
>>>>>>> main RCS context only holds the registers for itself and the shared
>>>>>>> L3 values. By trying to keep the registers consistent across the
>>>>>>> different engines it should make the programming for the registers
>>>>>>> consistent.
>>>>>>>
>>>>>>> v2:
>>>>>>> -'static const' for private data structures and style changes.(Matt
>>>>> Turner)
>>>>>>> v3:
>>>>>>> - Make the tables "slightly" more readable. (Damien Lespiau)
>>>>>>> - Updated tables fix performance regression.
>>>>>>> v4:
>>>>>>> - Code formatting. (Chris Wilson)
>>>>>>> - re-privatised mocs code. (Daniel Vetter)
>>>>>>>
>>>>>>> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
>>>>>>> ---
>>>>>>>  drivers/gpu/drm/i915/Makefile     |   1 +
>>>>>>>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>>>>>>>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>>>>>>>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>>>>>>>  drivers/gpu/drm/i915/intel_mocs.c | 373
>>>>> ++++++++++++++++++++++++++++++++++++++
>>>>>>>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>>>>>>>  6 files changed, 460 insertions(+), 1 deletion(-)
>>>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>
>>>>>>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>>>>>>> index b7ddf48..c781e19 100644
>>>>>>> --- a/drivers/gpu/drm/i915/Makefile
>>>>>>> +++ b/drivers/gpu/drm/i915/Makefile
>>>>>>> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>>>>>>>  	  i915_irq.o \
>>>>>>>  	  i915_trace_points.o \
>>>>>>>  	  intel_lrc.o \
>>>>>>> +	  intel_mocs.o \
>>>>>>>  	  intel_ringbuffer.o \
>>>>>>>  	  intel_uncore.o
>>>>>>>
>>>>>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h
>>>>> b/drivers/gpu/drm/i915/i915_reg.h
>>>>>>> index 7213224..3a435b5 100644
>>>>>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>>>>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>>>>>> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>>>>>>>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>>>>>>>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>>>>>>>
>>>>>>> +/* MOCS (Memory Object Control State) registers */
>>>>>>> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control
>>>>> base */
>>>>>>> +
>>>>>>> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base
>>>>> register*/
>>>>>>> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base
>>>>> register*/
>>>>>>> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base
>>>>> register*/
>>>>>>> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
>>>>>>> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base
>>>>> register*/
>>>>>>> +
>>>>>>>  #endif /* _I915_REG_H_ */
>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c
>>>>> b/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>> index 9f5485d..73b919d 100644
>>>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>> @@ -135,6 +135,7 @@
>>>>>>>  #include <drm/drmP.h>
>>>>>>>  #include <drm/i915_drm.h>
>>>>>>>  #include "i915_drv.h"
>>>>>>> +#include "intel_mocs.h"
>>>>>>>
>>>>>>>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>>>>>>>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
>>>>>>> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct
>>>>> intel_ringbuffer *ringbuf,
>>>>>>>   *
>>>>>>>   * Return: non-zero if the ringbuffer is not ready to be written to.
>>>>>>>   */
>>>>>>> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>>  				    struct intel_context *ctx, int
>>>>> num_dwords)
>>>>>>>  {
>>>>>>>  	struct intel_engine_cs *ring = ringbuf->ring;
>>>>>>> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct
>>>>> intel_engine_cs *ring,
>>>>>>>  	if (ret)
>>>>>>>  		return ret;
>>>>>>>
>>>>>>> +	/*
>>>>>>> +	 * Failing to program the MOCS is non-fatal.The system will not
>>>>>>> +	 * run at peak performance. So generate a warning and carry on.
>>>>>>> +	 */
>>>>>>> +	if (gen9_program_mocs(ring, ctx) != 0)
>>>>>>> +		DRM_ERROR("MOCS failed to program: expect performance
>>>>> issues.");
>>>>>>> +
>>>>>>>  	return intel_lr_context_render_state_init(ring, ctx);
>>>>>>>  }
>>>>>>>
>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.h
>>>>> b/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>> index 04d3a6d..dbbd6af 100644
>>>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>>>>>>>
>>>>>>>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>>>>>>>  				  struct intel_context *ctx);
>>>>>>> +
>>>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>> +				    struct intel_context *ctx, int
>>>>> num_dwords);
>>>>>>> +
>>>>>>>  /**
>>>>>>>   * intel_logical_ring_advance() - advance the ringbuffer tail
>>>>>>>   * @ringbuf: Ringbuffer to advance.
>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.c
>>>>> b/drivers/gpu/drm/i915/intel_mocs.c
>>>>>>> new file mode 100644
>>>>>>> index 0000000..7c09e67
>>>>>>> --- /dev/null
>>>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.c
>>>>>>> @@ -0,0 +1,373 @@
>>>>>>> +/*
>>>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>>>> + *
>>>>>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>>>> a
>>>>>>> + * copy of this software and associated documentation files (the
>>>>> "Software"),
>>>>>>> + * to deal in the Software without restriction, including without
>>>>> limitation
>>>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>>> sublicense,
>>>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>>>> + * Software is furnished to do so, subject to the following conditions: *
>>>>>>> + * The above copyright notice and this permission notice (including the
>>>>> next
>>>>>>> + * paragraph) shall be included in all copies or substantial portions of
>>>>> the
>>>>>>> + * Software.
>>>>>>> + *
>>>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>>> EXPRESS OR
>>>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>>> MERCHANTABILITY,
>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>>>>> SHALL
>>>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>>> OTHER
>>>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>>> ARISING FROM,
>>>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>>>> IN THE
>>>>>>> + * SOFTWARE.
>>>>>>> + *
>>>>>>> + * Authors:
>>>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>>>> + */
>>>>>>> +
>>>>>>> +#include "intel_mocs.h"
>>>>>>> +#include "intel_lrc.h"
>>>>>>> +#include "intel_ringbuffer.h"
>>>>>>> +
>>>>>>> +/* structures required */
>>>>>>> +struct drm_i915_mocs_entry {
>>>>>>> +	u32	control_value;
>>>>>>> +	u16	l3cc_value;
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct drm_i915_mocs_table {
>>>>>>> +	u32					size;
>>>>>>> +	const struct drm_i915_mocs_entry	*table;
>>>>>>> +};
>>>>>>> +
>>>>>>> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
>>>>>>> +#define	MOCS_CACHEABILITY(value)	(value << 0)
>>>>>>> +#define	MOCS_TGT_CACHE(value)		(value << 2)
>>>>>>> +#define	MOCS_LRUM(value)		(value << 4)
>>>>>>> +#define	MOCS_AOM(value)			(value << 6)
>>>>>>> +#define	MOCS_LECC_ESC(value)		(value << 7)
>>>>>>> +#define	MOCS_LECC_SCC(value)		(value << 8)
>>>>>>> +#define	MOC_PFM(value)			(value << 11)
>>>>>>> +#define	MOCS_SCF(value)			(value << 14)
>>>>>>> +
>>>>>>> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word
>>>>> */
>>>>>>> +#define	MOCS_ESC(value)			(value << 0)
>>>>>>> +#define	MOCS_SCC(value)			(value << 1)
>>>>>>> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
>>>>>>> +
>>>>>>> +/* Helper defines */
>>>>>>> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program
>>>>> */
>>>>>>> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd
>>>>> */
>>>>>>> +
>>>>>>> +/* EDRAM Caching options */
>>>>>>> +#define EDRAM_PAGETABLE		(0)
>>>>>>> +#define EDRAM_UC		(1)
>>>>>>> +#define EDRAM_RESERVED		(2)
>>>>>>
>>>>>> According to the BSpec this is WT rather than reserved?a
>>>>> Just checked the Bspec and you are correct, changing the text.
>>>>> As well as for the items below.
>>>> Just to add - I was looking at the wrong gen.
>>>>>>
>>>>>>> +#define EDRAM_WB		(3)
>>>>>>> +
>>>>>>> +/* L3 Caching options */
>>>>>>> +#define L3_DIRECT		(0)
>>>>>>> +#define L3_UC			(1)
>>>>>>> +#define L3_RESERVED		(2)
>>>>>>> +#define L3_WB			(3)
>>>>>>> +
>>>>>>> +/* target cache */
>>>>>>> +#define ELLC			(0)
>>>>>>
>>>>>> BSpec says that this is "Use TC/LRU controls from page table", but upon
>>>>>> a closer look it seems like the BSpec is wrong and your patch is
>>>>>> correct.  Can you confirm that this is what you intended?
>>>>> These values look good, they are bits 3:2 for the XXX_MOCS_N registers
>>>>> (c800) and friends.
>>>>>>
>>>>>>> +#define LLC			(1)
>>>>>>> +#define LLC_ELLC		(2)
>>>>>>> +
>>>>>>> +/*
>>>>>>> + * MOCS tables
>>>>>>> + *
>>>>>>> + * These are the MOCS tables that are programmed across all the rings.
>>>>>>> + * The control value is programmed to all the rings that support the
>>>>>>> + * MOCS registers. While the l3cc_values are only programmed to the
>>>>>>> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
>>>>>>> + *
>>>>>>> + * NOTE: These tables MUST start with being uncached and the length MUST
>>>>> be
>>>>>>> + *       less than 63 as the last two registers are reserved by the
>>>>> hardware.
>>>>>>> + */
>>>>>>> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
>>>>>>> +	 /* {0x00000009, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +	 /* {0x0000003b, 0x0030} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>> +	 /* {0x00000039, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +	 /* {0x00000017, 0x0030} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>> +	 /* {0x00000017, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +	 /* {0x00000019, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +	 /* {0x00000037, 0x0030} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>> +	 /* {0x00000037, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +};
>>>>>>
>>>>>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE, L3CC=WB,
>>>>>> everything else unset, I'll reply with a userspace patch making use of
>>>>>> your change if you add such an entry.
>>>> Ok. I think what you want is, same as entry two, but use the underlying
>>>> pagetable settings and not specify the EDRAM settings. Please confirm in
>>>> the new patchset.
>>>
>>> Yeah, that sounds good.
>>>
>>>>>>
>>>>>> Another thing worth mentioning is that entries 0, 2 and 5 seem to do the
>>>>>> same thing suspiciously, the only difference is the LRUM field which
>>>>>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding correct?
>>>>>>
>>>>> These tables are generated via requests and then boiled down to the above.
>>>>> So some of the entries are by request. Swings and roundabouts, can remove
>>>>> the ones that look redundant but then the tuning that has been done wont
>>>>> match. I'll add the new entry at the end of the table.
>>
>> Are you planning to propagate the entry you just added back to the
>> original table this was generated from?  What about new entries we may
>> need to add in the future?  What should be the process to make sure that
>> our table and the master table don't diverge and end up with conflicting
>> entries we cannot remove because of ABI compatibility?  I guess there
>> should be a comment on the top warning that the table is part of the
>> kernel ABI and supposed to be kept in sync with your table, so other
>> people don't change it unknowingly?
>>
>> Thanks.
> I am talking to the team that handles this and see if they will add this 
> (so future gens this is baked in) but it is unlikely that the other tables 
> will stay in step as getting in changes will cause too much grief getting 
> them upstreamed and as the table is auto-generated we will not be able to 
> guarantee the ordering. It will have to be manual job for anyone doing 
> this. It is required for other platforms for the tables to match the 
> userspace for performance reasons, but on Linux it will be by request if 
> there is a problem. We will see what happens.
>
I think it only makes sense for Linux to maintain compatibility with
Android's tables if we agree on some straightforward process for us to
allocate new entries without causing conflicts (otherwise people are
likely to ignore the issue completely and let the tables diverge, as you
mentioned yourself), and have some guarantee that any entries ever
contributed by your team to the Linux kernel (and therefore part of our
stable ABI) will never be changed or reordered in the future.

I have the impression that because of your development model you have
far more freedom to make changes in your kernel ABI after the fact than
we do -- OTOH we would be locked in if we accept to import Android's
tables now, what brings me to the next question: How would you feel
about reversing the roles of our tables?  The workflow could be as
follows:

 - The MOCS tables part of the Linux kernel would be developed and
   discussed publicly in this mailing list, independently from your team
   (which doesn't mean that your contributions and feed-back regarding
   future changes in the MOCS tables wouldn't be very much welcome).

 - If you wish you may maintain compatibility with Linux by sync'ing
   your tables periodically.  If you do you may still have the choice to
   break compatibility in the future and start from scratch with clean
   tables if this turns out to become a burden for you.  (Note that the
   converse statement doesn't work if the tables part of the Linux
   kernel were to be considered downstream, because we have the
   requirement of keeping backwards compatibility with previous
   revisions of the ABI).

 - If you choose to keep compatibility the process for you to allocate
   new entries avoiding conflicts should be relatively straightforward:
   Send a patch to this mailing list and once it's ACK'ed you would have
   the guarantee that the same index wouldn't ever be reused for any
   other purpose in the future, and you could start making use of it in
   the Android stack right away.

How do you feel about this proposal?  It would also be nice to hear the
opinion of other people from the Linux side.  Ben?  Jesse?

> Peter.
>
>>
>>>>>>> +
>>>>>>> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
>>>>>>> +	 /* {0x00000001, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +	 /* {0x00000005, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +	 /* {0x00000005, 0x0030} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>> +	 /* {0x00000017, 0x0030} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>> +	 /* {0x00000017, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +	 /* {0x00000019, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +	 /* {0x00000037, 0x0030} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>> +	 /* {0x00000037, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>> +};
>>>>>>> +
>>>>>>
>>>>>> Wouldn't it be a good idea to have BXT's entries match SKL's for a given
>>>>>> index?  The TC, LeCC and LRUM settings you do here arguably don't have
>>>>>> any effect on BXT, L3CC does but it doesn't match SKL's setting for
>>>>>> entries 1 and 2.  Is there any reason for this?
>>>>> As mentioned above this table is auto-generated and matches another tuned
>>>>> table, simply keeping them the same allows for the tuning to be consistent
>>>>> across platforms.
>>>>>
>>>>> Peter.
>>>>>>
>>>>>> Other than that looks good.
>>>>>>
>>>>>>> +/**
>>>>>>> + * get_mocs_settings
>>>>>>> + *
>>>>>>> + * 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
>>>>>>> + * to be programmed and if they need to be programmed.
>>>>>>> + *
>>>>>>> + * If the return values is false then the registers do not need
>>>>> programming.
>>>>>>> + */
>>>>>>> +static bool get_mocs_settings(struct drm_device *dev,
>>>>>>> +			      struct drm_i915_mocs_table *table) {
>>>>>>> +	bool	result = false;
>>>>>>> +
>>>>>>> +	if (IS_SKYLAKE(dev)) {
>>>>>>> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
>>>>>>> +		table->table = skylake_mocs_table;
>>>>>>> +		result = true;
>>>>>>> +	} else if (IS_BROXTON(dev)) {
>>>>>>> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
>>>>>>> +		table->table = broxton_mocs_table;
>>>>>>> +		result = true;
>>>>>>> +	} else {
>>>>>>> +		/* Platform that should have a MOCS table does not */
>>>>>>> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	return result;
>>>>>>> +}
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * emit_mocs_control_table() - emit the mocs control table
>>>>>>> + * @ringbuf:	DRM device.
>>>>>>> + * @table:	The values to program into the control regs.
>>>>>>> + * @reg_base:	The base for the Engine that needs to be programmed.
>>>>>>> + *
>>>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>>>> + * given table starting at the given address.
>>>>>>> + *
>>>>>>> + * Return: Nothing.
>>>>>>> + */
>>>>>>> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
>>>>>>> +				    struct drm_i915_mocs_table *table,
>>>>>>> +				    u32 reg_base)
>>>>>>> +{
>>>>>>> +	unsigned int index;
>>>>>>> +
>>>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
>>>>>>> +
>>>>>>> +	for (index = 0; index < table->size; index++) {
>>>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>>>> +		intel_logical_ring_emit(ringbuf,
>>>>>>> +					table->table[index].control_value);
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	/*
>>>>>>> +	 * Ok, now set the unused entries to uncached. These entries are
>>>>>>> +	 * officially undefined and no contact is given for the contents and
>>>>>>> +	 * settings is given for these entries.
>>>>>>> +	 *
>>>>>>> +	 * Entry 0 in the table is uncached - so we are just written that
>>>>>>> +	 * value to all the used entries.
>>>>>>> +	 */
>>>>>>> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
>>>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>>>> +		intel_logical_ring_emit(ringbuf,
>>>>> table->table[0].control_value);
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>>>> +}
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * emit_mocs_l3cc_table() - emit the mocs control table
>>>>>>> + * @ringbuf:	DRM device.
>>>>>>> + * @table:	The values to program into the control regs.
>>>>>>> + *
>>>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>>>> + * given table starting at the given address. This register set is
>>>>> programmed
>>>>>>> + * in pairs.
>>>>>>> + *
>>>>>>> + * Return: Nothing.
>>>>>>> + */
>>>>>>> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
>>>>>>> +			 struct drm_i915_mocs_table *table) {
>>>>>>> +	unsigned int count;
>>>>>>> +	unsigned int i;
>>>>>>> +	u32 value;
>>>>>>> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
>>>>>>> +			((table->table[0].l3cc_value & 0xffff) << 16);
>>>>>>> +
>>>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
>>>>>>> +
>>>>>>> +	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);
>>>>>>> +
>>>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>>>> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
>>>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>>>> +		intel_logical_ring_emit(ringbuf, value);
>>>>>>> +
>>>>>>> +		value = filler;
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>>>> +}
>>>>>>> +
>>>>>>> +/*
>>>>>>> + * gen9_program_mocs() - program the MOCS register.
>>>>>>> + *
>>>>>>> + * ring:	The ring that the programming batch will be run in.
>>>>>>> + * ctx:		The intel_context to be used.
>>>>>>> + *
>>>>>>> + * This function will emit a batch buffer with the values required for
>>>>>>> + * programming the MOCS register values for all the currently supported
>>>>>>> + * rings.
>>>>>>> + *
>>>>>>> + * These registers are partially stored in the RCS context, so they are
>>>>>>> + * emitted at the same time so that when a context is created these
>>>>> registers
>>>>>>> + * are set up. These registers have to be emitted into the start of the
>>>>>>> + * context as setting the ELSP will re-init some of these registers back
>>>>>>> + * to the hw values.
>>>>>>> + *
>>>>>>> + * Return: 0 on success, otherwise the error status.
>>>>>>> + */
>>>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>>>> +			  struct intel_context *ctx)
>>>>>>> +{
>>>>>>> +	int ret = 0;
>>>>>>> +
>>>>>>> +	struct drm_i915_mocs_table t;
>>>>>>> +	struct drm_device *dev = ring->dev;
>>>>>>> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
>>>>>>> +
>>>>>>> +	if (get_mocs_settings(dev, &t)) {
>>>>>>> +		u32 table_size;
>>>>>>> +
>>>>>>> +		/*
>>>>>>> +		 * OK. For each supported ring:
>>>>>>> +		 *  number of mocs entries * 2 dwords for each control_value
>>>>>>> +		 *  plus number of mocs entries /2 dwords for l3cc values.
>>>>>>> +		 *
>>>>>>> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
>>>>>>> +		 *  and the l3cc programming.
>>>>>>> +		 */
>>>>>>> +		table_size = GEN9_NUM_MOCS_RINGS *
>>>>>>> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
>>>>>>> +				GEN9_NUM_MOCS_ENTRIES + 2;
>>>>>>> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
>>>>>>> +		if (ret) {
>>>>>>> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n",
>>>>> ret);
>>>>>>> +			return ret;
>>>>>>> +		}
>>>>>>> +
>>>>>>> +		/* program the control registers */
>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
>>>>>>> +
>>>>>>> +		/* now program the l3cc registers */
>>>>>>> +		emit_mocs_l3cc_table(ringbuf, &t);
>>>>>>> +
>>>>>>> +		intel_logical_ring_advance(ringbuf);
>>>>>>> +
>>>>>>> +		DRM_DEBUG("MOCS: Table set in Context\n");
>>>>>>> +	} else {
>>>>>>> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	return ret;
>>>>>>> +}
>>>>>>> +
>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.h
>>>>> b/drivers/gpu/drm/i915/intel_mocs.h
>>>>>>> new file mode 100644
>>>>>>> index 0000000..e2780ce
>>>>>>> --- /dev/null
>>>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.h
>>>>>>> @@ -0,0 +1,64 @@
>>>>>>> +/*
>>>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>>>> + *
>>>>>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>>>> a
>>>>>>> + * copy of this software and associated documentation files (the
>>>>> "Software"),
>>>>>>> + * to deal in the Software without restriction, including without
>>>>> limitation
>>>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>>> sublicense,
>>>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>>>> + * Software is furnished to do so, subject to the following conditions:
>>>>>>> + *
>>>>>>> + * The above copyright notice and this permission notice (including the
>>>>> next
>>>>>>> + * paragraph) shall be included in all copies or substantial portions of
>>>>> the
>>>>>>> + * Software.
>>>>>>> + *
>>>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>>> EXPRESS OR
>>>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>>> MERCHANTABILITY,
>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>>>>> SHALL
>>>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>>> OTHER
>>>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>>> ARISING FROM,
>>>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>>>> IN THE
>>>>>>> + * SOFTWARE.
>>>>>>> + *
>>>>>>> + * Authors:
>>>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>>>> + */
>>>>>>> +
>>>>>>> +#ifndef INTEL_MOCS_H
>>>>>>> +#define INTEL_MOCS_H
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * DOC: Memory Objects Control State (MOCS)
>>>>>>> + *
>>>>>>> + * Motivation:
>>>>>>> + * In previous Gens the MOCS settings was a value that was set by user
>>>>> land as
>>>>>>> + * part of the batch. In Gen9 this has changed to be a single table (per
>>>>> ring)
>>>>>>> + * that all batches now reference by index instead of programming the
>>>>> MOCS
>>>>>>> + * directly.
>>>>>>> + *
>>>>>>> + * The one wrinkle in this is that only PART of the MOCS tables are
>>>>> included
>>>>>>> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 -
>>>>> LNCFCMOCS32
>>>>>>> + * registers). The rest are not (the settings for the other rings).
>>>>>>> + *
>>>>>>> + * This table needs to be set at system start-up because the way the
>>>>> table
>>>>>>> + * interacts with the contexts and the GmmLib interface.
>>>>>>> + *
>>>>>>> + *
>>>>>>> + * Implementation:
>>>>>>> + *
>>>>>>> + * The table is programmed on a platform basis from a table that is
>>>>> generated
>>>>>>> + * from the one that has been agreed by the different responsible
>>>>> parties. This
>>>>>>> + * tables (one per supported platform) is defined in intel_mocs.c and is
>>>>>>> + * programmed in the first batch after the context is loaded (with the
>>>>> hardware
>>>>>>> + * workarounds). This will then let the usual context handling keep the
>>>>> MOCS in
>>>>>>> + * step.
>>>>>>> + */
>>>>>>> +
>>>>>>> +#include <drm/drmP.h>
>>>>>>> +#include "i915_drv.h"
>>>>>>> +
>>>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>>>> +			struct intel_context *ctx);
>>>>>>> +
>>>>>>> +#endif
>>>>>>> +
>>>>>>> --
>>>>>>> 1.9.1
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> Intel-gfx mailing list
>>>>>>> Intel-gfx@lists.freedesktop.org
>>>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>>>
>>>>>
>>>>> --
>>>>>    Peter Antoine (Android Graphics Driver Software Engineer)
>>>>>    ---------------------------------------------------------------------
>>>>>    Intel Corporation (UK) Limited
>>>>>    Registered No. 1134945 (England)
>>>>>    Registered Office: Pipers Way, Swindon SN3 1RJ
>>>>>    VAT No: 860 2173 47
>>>>> _______________________________________________
>>>>> Intel-gfx mailing list
>>>>> Intel-gfx@lists.freedesktop.org
>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>>
>>>>
>>>> --
>>>>     Peter Antoine (Android Graphics Driver Software Engineer)
>>>>     ---------------------------------------------------------------------
>>>>     Intel Corporation (UK) Limited
>>>>     Registered No. 1134945 (England)
>>>>     Registered Office: Pipers Way, Swindon SN3 1RJ
>>>>     VAT No: 860 2173 47
>>> _______________________________________________
>>> Intel-gfx mailing list
>>> Intel-gfx@lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>
>
> --
>     Peter Antoine (Android Graphics Driver Software Engineer)
>     ---------------------------------------------------------------------
>     Intel Corporation (UK) Limited
>     Registered No. 1134945 (England)
>     Registered Office: Pipers Way, Swindon SN3 1RJ
>     VAT No: 860 2173 47
Peter Antoine July 1, 2015, 1:53 p.m. UTC | #19
On Wed, 1 Jul 2015, Francisco Jerez wrote:

> Peter Antoine <peter.antoine@intel.com> writes:
>
>> On Tue, 30 Jun 2015, Francisco Jerez wrote:
>>
>>> Francisco Jerez <currojerez@riseup.net> writes:
>>>
>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>
>>>>> On Mon, 29 Jun 2015, Peter Antoine wrote:
>>>>>
>>>>>> On Thu, 25 Jun 2015, Francisco Jerez wrote:
>>>>>>
>>>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>>>
>>>>>>>> This change adds the programming of the MOCS registers to the gen 9+
>>>>>>>> platforms. This change set programs the MOCS register values to a set
>>>>>>>> of values that are defined to be optimal.
>>>>>>>>
>>>>>>>> It creates a fixed register set that is programmed across the different
>>>>>>>> engines so that all engines have the same table. This is done as the
>>>>>>>> main RCS context only holds the registers for itself and the shared
>>>>>>>> L3 values. By trying to keep the registers consistent across the
>>>>>>>> different engines it should make the programming for the registers
>>>>>>>> consistent.
>>>>>>>>
>>>>>>>> v2:
>>>>>>>> -'static const' for private data structures and style changes.(Matt
>>>>>> Turner)
>>>>>>>> v3:
>>>>>>>> - Make the tables "slightly" more readable. (Damien Lespiau)
>>>>>>>> - Updated tables fix performance regression.
>>>>>>>> v4:
>>>>>>>> - Code formatting. (Chris Wilson)
>>>>>>>> - re-privatised mocs code. (Daniel Vetter)
>>>>>>>>
>>>>>>>> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
>>>>>>>> ---
>>>>>>>>  drivers/gpu/drm/i915/Makefile     |   1 +
>>>>>>>>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>>>>>>>>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>>>>>>>>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>>>>>>>>  drivers/gpu/drm/i915/intel_mocs.c | 373
>>>>>> ++++++++++++++++++++++++++++++++++++++
>>>>>>>>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>>>>>>>>  6 files changed, 460 insertions(+), 1 deletion(-)
>>>>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>>
>>>>>>>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>>>>>>>> index b7ddf48..c781e19 100644
>>>>>>>> --- a/drivers/gpu/drm/i915/Makefile
>>>>>>>> +++ b/drivers/gpu/drm/i915/Makefile
>>>>>>>> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>>>>>>>>  	  i915_irq.o \
>>>>>>>>  	  i915_trace_points.o \
>>>>>>>>  	  intel_lrc.o \
>>>>>>>> +	  intel_mocs.o \
>>>>>>>>  	  intel_ringbuffer.o \
>>>>>>>>  	  intel_uncore.o
>>>>>>>>
>>>>>>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h
>>>>>> b/drivers/gpu/drm/i915/i915_reg.h
>>>>>>>> index 7213224..3a435b5 100644
>>>>>>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>>>>>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>>>>>>> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>>>>>>>>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>>>>>>>>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>>>>>>>>
>>>>>>>> +/* MOCS (Memory Object Control State) registers */
>>>>>>>> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control
>>>>>> base */
>>>>>>>> +
>>>>>>>> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base
>>>>>> register*/
>>>>>>>> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base
>>>>>> register*/
>>>>>>>> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base
>>>>>> register*/
>>>>>>>> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
>>>>>>>> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base
>>>>>> register*/
>>>>>>>> +
>>>>>>>>  #endif /* _I915_REG_H_ */
>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c
>>>>>> b/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>>> index 9f5485d..73b919d 100644
>>>>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>>> @@ -135,6 +135,7 @@
>>>>>>>>  #include <drm/drmP.h>
>>>>>>>>  #include <drm/i915_drm.h>
>>>>>>>>  #include "i915_drv.h"
>>>>>>>> +#include "intel_mocs.h"
>>>>>>>>
>>>>>>>>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>>>>>>>>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
>>>>>>>> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct
>>>>>> intel_ringbuffer *ringbuf,
>>>>>>>>   *
>>>>>>>>   * Return: non-zero if the ringbuffer is not ready to be written to.
>>>>>>>>   */
>>>>>>>> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>>>  				    struct intel_context *ctx, int
>>>>>> num_dwords)
>>>>>>>>  {
>>>>>>>>  	struct intel_engine_cs *ring = ringbuf->ring;
>>>>>>>> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct
>>>>>> intel_engine_cs *ring,
>>>>>>>>  	if (ret)
>>>>>>>>  		return ret;
>>>>>>>>
>>>>>>>> +	/*
>>>>>>>> +	 * Failing to program the MOCS is non-fatal.The system will not
>>>>>>>> +	 * run at peak performance. So generate a warning and carry on.
>>>>>>>> +	 */
>>>>>>>> +	if (gen9_program_mocs(ring, ctx) != 0)
>>>>>>>> +		DRM_ERROR("MOCS failed to program: expect performance
>>>>>> issues.");
>>>>>>>> +
>>>>>>>>  	return intel_lr_context_render_state_init(ring, ctx);
>>>>>>>>  }
>>>>>>>>
>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.h
>>>>>> b/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>>> index 04d3a6d..dbbd6af 100644
>>>>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>>> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>>>>>>>>
>>>>>>>>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>>>>>>>>  				  struct intel_context *ctx);
>>>>>>>> +
>>>>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>>> +				    struct intel_context *ctx, int
>>>>>> num_dwords);
>>>>>>>> +
>>>>>>>>  /**
>>>>>>>>   * intel_logical_ring_advance() - advance the ringbuffer tail
>>>>>>>>   * @ringbuf: Ringbuffer to advance.
>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.c
>>>>>> b/drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..7c09e67
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>> @@ -0,0 +1,373 @@
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>>>>> + *
>>>>>>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>>>>> a
>>>>>>>> + * copy of this software and associated documentation files (the
>>>>>> "Software"),
>>>>>>>> + * to deal in the Software without restriction, including without
>>>>>> limitation
>>>>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>>>> sublicense,
>>>>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>>>>> + * Software is furnished to do so, subject to the following conditions: *
>>>>>>>> + * The above copyright notice and this permission notice (including the
>>>>>> next
>>>>>>>> + * paragraph) shall be included in all copies or substantial portions of
>>>>>> the
>>>>>>>> + * Software.
>>>>>>>> + *
>>>>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>>>> EXPRESS OR
>>>>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>>>> MERCHANTABILITY,
>>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>>>>>> SHALL
>>>>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>>>> OTHER
>>>>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>>>> ARISING FROM,
>>>>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>>>>> IN THE
>>>>>>>> + * SOFTWARE.
>>>>>>>> + *
>>>>>>>> + * Authors:
>>>>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +#include "intel_mocs.h"
>>>>>>>> +#include "intel_lrc.h"
>>>>>>>> +#include "intel_ringbuffer.h"
>>>>>>>> +
>>>>>>>> +/* structures required */
>>>>>>>> +struct drm_i915_mocs_entry {
>>>>>>>> +	u32	control_value;
>>>>>>>> +	u16	l3cc_value;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +struct drm_i915_mocs_table {
>>>>>>>> +	u32					size;
>>>>>>>> +	const struct drm_i915_mocs_entry	*table;
>>>>>>>> +};
>>>>>>>> +
>>>>>>>> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
>>>>>>>> +#define	MOCS_CACHEABILITY(value)	(value << 0)
>>>>>>>> +#define	MOCS_TGT_CACHE(value)		(value << 2)
>>>>>>>> +#define	MOCS_LRUM(value)		(value << 4)
>>>>>>>> +#define	MOCS_AOM(value)			(value << 6)
>>>>>>>> +#define	MOCS_LECC_ESC(value)		(value << 7)
>>>>>>>> +#define	MOCS_LECC_SCC(value)		(value << 8)
>>>>>>>> +#define	MOC_PFM(value)			(value << 11)
>>>>>>>> +#define	MOCS_SCF(value)			(value << 14)
>>>>>>>> +
>>>>>>>> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word
>>>>>> */
>>>>>>>> +#define	MOCS_ESC(value)			(value << 0)
>>>>>>>> +#define	MOCS_SCC(value)			(value << 1)
>>>>>>>> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
>>>>>>>> +
>>>>>>>> +/* Helper defines */
>>>>>>>> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program
>>>>>> */
>>>>>>>> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd
>>>>>> */
>>>>>>>> +
>>>>>>>> +/* EDRAM Caching options */
>>>>>>>> +#define EDRAM_PAGETABLE		(0)
>>>>>>>> +#define EDRAM_UC		(1)
>>>>>>>> +#define EDRAM_RESERVED		(2)
>>>>>>>
>>>>>>> According to the BSpec this is WT rather than reserved?a
>>>>>> Just checked the Bspec and you are correct, changing the text.
>>>>>> As well as for the items below.
>>>>> Just to add - I was looking at the wrong gen.
>>>>>>>
>>>>>>>> +#define EDRAM_WB		(3)
>>>>>>>> +
>>>>>>>> +/* L3 Caching options */
>>>>>>>> +#define L3_DIRECT		(0)
>>>>>>>> +#define L3_UC			(1)
>>>>>>>> +#define L3_RESERVED		(2)
>>>>>>>> +#define L3_WB			(3)
>>>>>>>> +
>>>>>>>> +/* target cache */
>>>>>>>> +#define ELLC			(0)
>>>>>>>
>>>>>>> BSpec says that this is "Use TC/LRU controls from page table", but upon
>>>>>>> a closer look it seems like the BSpec is wrong and your patch is
>>>>>>> correct.  Can you confirm that this is what you intended?
>>>>>> These values look good, they are bits 3:2 for the XXX_MOCS_N registers
>>>>>> (c800) and friends.
>>>>>>>
>>>>>>>> +#define LLC			(1)
>>>>>>>> +#define LLC_ELLC		(2)
>>>>>>>> +
>>>>>>>> +/*
>>>>>>>> + * MOCS tables
>>>>>>>> + *
>>>>>>>> + * These are the MOCS tables that are programmed across all the rings.
>>>>>>>> + * The control value is programmed to all the rings that support the
>>>>>>>> + * MOCS registers. While the l3cc_values are only programmed to the
>>>>>>>> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
>>>>>>>> + *
>>>>>>>> + * NOTE: These tables MUST start with being uncached and the length MUST
>>>>>> be
>>>>>>>> + *       less than 63 as the last two registers are reserved by the
>>>>>> hardware.
>>>>>>>> + */
>>>>>>>> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
>>>>>>>> +	 /* {0x00000009, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +	 /* {0x0000003b, 0x0030} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>> +	 /* {0x00000039, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +	 /* {0x00000017, 0x0030} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>> +	 /* {0x00000017, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +	 /* {0x00000019, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +	 /* {0x00000037, 0x0030} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>> +	 /* {0x00000037, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +};
>>>>>>>
>>>>>>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE, L3CC=WB,
>>>>>>> everything else unset, I'll reply with a userspace patch making use of
>>>>>>> your change if you add such an entry.
>>>>> Ok. I think what you want is, same as entry two, but use the underlying
>>>>> pagetable settings and not specify the EDRAM settings. Please confirm in
>>>>> the new patchset.
>>>>
>>>> Yeah, that sounds good.
>>>>
>>>>>>>
>>>>>>> Another thing worth mentioning is that entries 0, 2 and 5 seem to do the
>>>>>>> same thing suspiciously, the only difference is the LRUM field which
>>>>>>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding correct?
>>>>>>>
>>>>>> These tables are generated via requests and then boiled down to the above.
>>>>>> So some of the entries are by request. Swings and roundabouts, can remove
>>>>>> the ones that look redundant but then the tuning that has been done wont
>>>>>> match. I'll add the new entry at the end of the table.
>>>
>>> Are you planning to propagate the entry you just added back to the
>>> original table this was generated from?  What about new entries we may
>>> need to add in the future?  What should be the process to make sure that
>>> our table and the master table don't diverge and end up with conflicting
>>> entries we cannot remove because of ABI compatibility?  I guess there
>>> should be a comment on the top warning that the table is part of the
>>> kernel ABI and supposed to be kept in sync with your table, so other
>>> people don't change it unknowingly?
>>>
>>> Thanks.
>> I am talking to the team that handles this and see if they will add this
>> (so future gens this is baked in) but it is unlikely that the other tables
>> will stay in step as getting in changes will cause too much grief getting
>> them upstreamed and as the table is auto-generated we will not be able to
>> guarantee the ordering. It will have to be manual job for anyone doing
>> this. It is required for other platforms for the tables to match the
>> userspace for performance reasons, but on Linux it will be by request if
>> there is a problem. We will see what happens.
>>
> I think it only makes sense for Linux to maintain compatibility with
> Android's tables if we agree on some straightforward process for us to
> allocate new entries without causing conflicts (otherwise people are
> likely to ignore the issue completely and let the tables diverge, as you
> mentioned yourself), and have some guarantee that any entries ever
> contributed by your team to the Linux kernel (and therefore part of our
> stable ABI) will never be changed or reordered in the future.
>
I think internally (and informally) that we cannot keep sync between Android
and Linux. We need to keep compatibility with userspace and there is no
guarantee of ordering as these tables are generated at runtime. The tables
that are in Linux are a snapshot. These changes are supposed to stabilise at
PV so they don't change in the future, but if a bug or good performance
enhancement occurs I can't imagine that they wont make the changes.

> I have the impression that because of your development model you have
> far more freedom to make changes in your kernel ABI after the fact than
> we do -- OTOH we would be locked in if we accept to import Android's
> tables now, what brings me to the next question: How would you feel
> about reversing the roles of our tables?  The workflow could be as
> follows:
The Android kernel is more flexible, in what it accepts, and secondly (and
more importantly) you should be using the userspace drivers as this is
the API and is tuned, so changing the tables are less of a problem.
>
>
> - The MOCS tables part of the Linux kernel would be developed and
>   discussed publicly in this mailing list, independently from your team
>   (which doesn't mean that your contributions and feed-back regarding
>   future changes in the MOCS tables wouldn't be very much welcome).
>
This is fine. But be aware the RFC for the MOCS was first floated in March and
teams were directly contacted when this happened and not a lot of response
was received. MOCS ain't sexy and people only get interested when they
feel that they maybe a performance problem - then they look to caching.

But, I think this is the sensible model. For the new tables (new gens) a drop
from the internal cache models as these will have had some form of tuning from
different teams and requirements (OpenCL, OpenGL, Media, Security, etc...) then
these can be discussed on the mailing list as required.

I am not sure if that is acceptable to everyone. As we are going to have to
carry some patches in Android and drop any upstream MOCS changes.

> - If you wish you may maintain compatibility with Linux by sync'ing
>   your tables periodically.  If you do you may still have the choice to
>   break compatibility in the future and start from scratch with clean
>   tables if this turns out to become a burden for you.  (Note that the
>   converse statement doesn't work if the tables part of the Linux
>   kernel were to be considered downstream, because we have the
>   requirement of keeping backwards compatibility with previous
>   revisions of the ABI).
This is not really possible. As mentioned above ordering may change.
>
> - If you choose to keep compatibility the process for you to allocate
>   new entries avoiding conflicts should be relatively straightforward:
>   Send a patch to this mailing list and once it's ACK'ed you would have
>   the guarantee that the same index wouldn't ever be reused for any
>   other purpose in the future, and you could start making use of it in
>   the Android stack right away.
It would be possible to allocate a high number say in the 60's as the current
table is generated from 270+ policies and only spits out 8 or 9 entries. So the
chance of the tables getting into the 60's is quite low. That could be an
option, but I can see that being poo-pooed upstream with the simple question
of why not start at 0.

Like you, it would be nice too see what others think.

Peter.

>
> How do you feel about this proposal?  It would also be nice to hear the
> opinion of other people from the Linux side.  Ben?  Jesse?
>
>> Peter.
>>
>>>
>>>>>>>> +
>>>>>>>> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
>>>>>>>> +	 /* {0x00000001, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +	 /* {0x00000005, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +	 /* {0x00000005, 0x0030} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>> +	 /* {0x00000017, 0x0030} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>> +	 /* {0x00000017, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +	 /* {0x00000019, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +	 /* {0x00000037, 0x0030} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>> +	 /* {0x00000037, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>> +};
>>>>>>>> +
>>>>>>>
>>>>>>> Wouldn't it be a good idea to have BXT's entries match SKL's for a given
>>>>>>> index?  The TC, LeCC and LRUM settings you do here arguably don't have
>>>>>>> any effect on BXT, L3CC does but it doesn't match SKL's setting for
>>>>>>> entries 1 and 2.  Is there any reason for this?
>>>>>> As mentioned above this table is auto-generated and matches another tuned
>>>>>> table, simply keeping them the same allows for the tuning to be consistent
>>>>>> across platforms.
>>>>>>
>>>>>> Peter.
>>>>>>>
>>>>>>> Other than that looks good.
>>>>>>>
>>>>>>>> +/**
>>>>>>>> + * get_mocs_settings
>>>>>>>> + *
>>>>>>>> + * 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
>>>>>>>> + * to be programmed and if they need to be programmed.
>>>>>>>> + *
>>>>>>>> + * If the return values is false then the registers do not need
>>>>>> programming.
>>>>>>>> + */
>>>>>>>> +static bool get_mocs_settings(struct drm_device *dev,
>>>>>>>> +			      struct drm_i915_mocs_table *table) {
>>>>>>>> +	bool	result = false;
>>>>>>>> +
>>>>>>>> +	if (IS_SKYLAKE(dev)) {
>>>>>>>> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
>>>>>>>> +		table->table = skylake_mocs_table;
>>>>>>>> +		result = true;
>>>>>>>> +	} else if (IS_BROXTON(dev)) {
>>>>>>>> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
>>>>>>>> +		table->table = broxton_mocs_table;
>>>>>>>> +		result = true;
>>>>>>>> +	} else {
>>>>>>>> +		/* Platform that should have a MOCS table does not */
>>>>>>>> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	return result;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * emit_mocs_control_table() - emit the mocs control table
>>>>>>>> + * @ringbuf:	DRM device.
>>>>>>>> + * @table:	The values to program into the control regs.
>>>>>>>> + * @reg_base:	The base for the Engine that needs to be programmed.
>>>>>>>> + *
>>>>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>>>>> + * given table starting at the given address.
>>>>>>>> + *
>>>>>>>> + * Return: Nothing.
>>>>>>>> + */
>>>>>>>> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
>>>>>>>> +				    struct drm_i915_mocs_table *table,
>>>>>>>> +				    u32 reg_base)
>>>>>>>> +{
>>>>>>>> +	unsigned int index;
>>>>>>>> +
>>>>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
>>>>>>>> +
>>>>>>>> +	for (index = 0; index < table->size; index++) {
>>>>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>>>>> +		intel_logical_ring_emit(ringbuf,
>>>>>>>> +					table->table[index].control_value);
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	/*
>>>>>>>> +	 * Ok, now set the unused entries to uncached. These entries are
>>>>>>>> +	 * officially undefined and no contact is given for the contents and
>>>>>>>> +	 * settings is given for these entries.
>>>>>>>> +	 *
>>>>>>>> +	 * Entry 0 in the table is uncached - so we are just written that
>>>>>>>> +	 * value to all the used entries.
>>>>>>>> +	 */
>>>>>>>> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
>>>>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>>>>> +		intel_logical_ring_emit(ringbuf,
>>>>>> table->table[0].control_value);
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * emit_mocs_l3cc_table() - emit the mocs control table
>>>>>>>> + * @ringbuf:	DRM device.
>>>>>>>> + * @table:	The values to program into the control regs.
>>>>>>>> + *
>>>>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>>>>> + * given table starting at the given address. This register set is
>>>>>> programmed
>>>>>>>> + * in pairs.
>>>>>>>> + *
>>>>>>>> + * Return: Nothing.
>>>>>>>> + */
>>>>>>>> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
>>>>>>>> +			 struct drm_i915_mocs_table *table) {
>>>>>>>> +	unsigned int count;
>>>>>>>> +	unsigned int i;
>>>>>>>> +	u32 value;
>>>>>>>> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
>>>>>>>> +			((table->table[0].l3cc_value & 0xffff) << 16);
>>>>>>>> +
>>>>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
>>>>>>>> +
>>>>>>>> +	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);
>>>>>>>> +
>>>>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>>>>> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
>>>>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>>>>> +		intel_logical_ring_emit(ringbuf, value);
>>>>>>>> +
>>>>>>>> +		value = filler;
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/*
>>>>>>>> + * gen9_program_mocs() - program the MOCS register.
>>>>>>>> + *
>>>>>>>> + * ring:	The ring that the programming batch will be run in.
>>>>>>>> + * ctx:		The intel_context to be used.
>>>>>>>> + *
>>>>>>>> + * This function will emit a batch buffer with the values required for
>>>>>>>> + * programming the MOCS register values for all the currently supported
>>>>>>>> + * rings.
>>>>>>>> + *
>>>>>>>> + * These registers are partially stored in the RCS context, so they are
>>>>>>>> + * emitted at the same time so that when a context is created these
>>>>>> registers
>>>>>>>> + * are set up. These registers have to be emitted into the start of the
>>>>>>>> + * context as setting the ELSP will re-init some of these registers back
>>>>>>>> + * to the hw values.
>>>>>>>> + *
>>>>>>>> + * Return: 0 on success, otherwise the error status.
>>>>>>>> + */
>>>>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>>>>> +			  struct intel_context *ctx)
>>>>>>>> +{
>>>>>>>> +	int ret = 0;
>>>>>>>> +
>>>>>>>> +	struct drm_i915_mocs_table t;
>>>>>>>> +	struct drm_device *dev = ring->dev;
>>>>>>>> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
>>>>>>>> +
>>>>>>>> +	if (get_mocs_settings(dev, &t)) {
>>>>>>>> +		u32 table_size;
>>>>>>>> +
>>>>>>>> +		/*
>>>>>>>> +		 * OK. For each supported ring:
>>>>>>>> +		 *  number of mocs entries * 2 dwords for each control_value
>>>>>>>> +		 *  plus number of mocs entries /2 dwords for l3cc values.
>>>>>>>> +		 *
>>>>>>>> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
>>>>>>>> +		 *  and the l3cc programming.
>>>>>>>> +		 */
>>>>>>>> +		table_size = GEN9_NUM_MOCS_RINGS *
>>>>>>>> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
>>>>>>>> +				GEN9_NUM_MOCS_ENTRIES + 2;
>>>>>>>> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
>>>>>>>> +		if (ret) {
>>>>>>>> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n",
>>>>>> ret);
>>>>>>>> +			return ret;
>>>>>>>> +		}
>>>>>>>> +
>>>>>>>> +		/* program the control registers */
>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
>>>>>>>> +
>>>>>>>> +		/* now program the l3cc registers */
>>>>>>>> +		emit_mocs_l3cc_table(ringbuf, &t);
>>>>>>>> +
>>>>>>>> +		intel_logical_ring_advance(ringbuf);
>>>>>>>> +
>>>>>>>> +		DRM_DEBUG("MOCS: Table set in Context\n");
>>>>>>>> +	} else {
>>>>>>>> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	return ret;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.h
>>>>>> b/drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000..e2780ce
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>> @@ -0,0 +1,64 @@
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>>>>> + *
>>>>>>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>>>>> a
>>>>>>>> + * copy of this software and associated documentation files (the
>>>>>> "Software"),
>>>>>>>> + * to deal in the Software without restriction, including without
>>>>>> limitation
>>>>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>>>> sublicense,
>>>>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>>>>> + * Software is furnished to do so, subject to the following conditions:
>>>>>>>> + *
>>>>>>>> + * The above copyright notice and this permission notice (including the
>>>>>> next
>>>>>>>> + * paragraph) shall be included in all copies or substantial portions of
>>>>>> the
>>>>>>>> + * Software.
>>>>>>>> + *
>>>>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>>>> EXPRESS OR
>>>>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>>>> MERCHANTABILITY,
>>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>>>>>> SHALL
>>>>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>>>> OTHER
>>>>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>>>> ARISING FROM,
>>>>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>>>>> IN THE
>>>>>>>> + * SOFTWARE.
>>>>>>>> + *
>>>>>>>> + * Authors:
>>>>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +#ifndef INTEL_MOCS_H
>>>>>>>> +#define INTEL_MOCS_H
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * DOC: Memory Objects Control State (MOCS)
>>>>>>>> + *
>>>>>>>> + * Motivation:
>>>>>>>> + * In previous Gens the MOCS settings was a value that was set by user
>>>>>> land as
>>>>>>>> + * part of the batch. In Gen9 this has changed to be a single table (per
>>>>>> ring)
>>>>>>>> + * that all batches now reference by index instead of programming the
>>>>>> MOCS
>>>>>>>> + * directly.
>>>>>>>> + *
>>>>>>>> + * The one wrinkle in this is that only PART of the MOCS tables are
>>>>>> included
>>>>>>>> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 -
>>>>>> LNCFCMOCS32
>>>>>>>> + * registers). The rest are not (the settings for the other rings).
>>>>>>>> + *
>>>>>>>> + * This table needs to be set at system start-up because the way the
>>>>>> table
>>>>>>>> + * interacts with the contexts and the GmmLib interface.
>>>>>>>> + *
>>>>>>>> + *
>>>>>>>> + * Implementation:
>>>>>>>> + *
>>>>>>>> + * The table is programmed on a platform basis from a table that is
>>>>>> generated
>>>>>>>> + * from the one that has been agreed by the different responsible
>>>>>> parties. This
>>>>>>>> + * tables (one per supported platform) is defined in intel_mocs.c and is
>>>>>>>> + * programmed in the first batch after the context is loaded (with the
>>>>>> hardware
>>>>>>>> + * workarounds). This will then let the usual context handling keep the
>>>>>> MOCS in
>>>>>>>> + * step.
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +#include <drm/drmP.h>
>>>>>>>> +#include "i915_drv.h"
>>>>>>>> +
>>>>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>>>>> +			struct intel_context *ctx);
>>>>>>>> +
>>>>>>>> +#endif
>>>>>>>> +
>>>>>>>> --
>>>>>>>> 1.9.1
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> Intel-gfx mailing list
>>>>>>>> Intel-gfx@lists.freedesktop.org
>>>>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>>>>
>>>>>>
>>>>>> --
>>>>>>    Peter Antoine (Android Graphics Driver Software Engineer)
>>>>>>    ---------------------------------------------------------------------
>>>>>>    Intel Corporation (UK) Limited
>>>>>>    Registered No. 1134945 (England)
>>>>>>    Registered Office: Pipers Way, Swindon SN3 1RJ
>>>>>>    VAT No: 860 2173 47
>>>>>> _______________________________________________
>>>>>> Intel-gfx mailing list
>>>>>> Intel-gfx@lists.freedesktop.org
>>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>>>
>>>>>
>>>>> --
>>>>>     Peter Antoine (Android Graphics Driver Software Engineer)
>>>>>     ---------------------------------------------------------------------
>>>>>     Intel Corporation (UK) Limited
>>>>>     Registered No. 1134945 (England)
>>>>>     Registered Office: Pipers Way, Swindon SN3 1RJ
>>>>>     VAT No: 860 2173 47
>>>> _______________________________________________
>>>> Intel-gfx mailing list
>>>> Intel-gfx@lists.freedesktop.org
>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>
>>
>> --
>>     Peter Antoine (Android Graphics Driver Software Engineer)
>>     ---------------------------------------------------------------------
>>     Intel Corporation (UK) Limited
>>     Registered No. 1134945 (England)
>>     Registered Office: Pipers Way, Swindon SN3 1RJ
>>     VAT No: 860 2173 47
>

--
    Peter Antoine (Android Graphics Driver Software Engineer)
    ---------------------------------------------------------------------
    Intel Corporation (UK) Limited
    Registered No. 1134945 (England)
    Registered Office: Pipers Way, Swindon SN3 1RJ
    VAT No: 860 2173 47
Francisco Jerez July 1, 2015, 3:04 p.m. UTC | #20
Peter Antoine <peter.antoine@intel.com> writes:

> On Wed, 1 Jul 2015, Francisco Jerez wrote:
>
>> Peter Antoine <peter.antoine@intel.com> writes:
>>
>>> On Tue, 30 Jun 2015, Francisco Jerez wrote:
>>>
>>>> Francisco Jerez <currojerez@riseup.net> writes:
>>>>
>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>
>>>>>> On Mon, 29 Jun 2015, Peter Antoine wrote:
>>>>>>
>>>>>>> On Thu, 25 Jun 2015, Francisco Jerez wrote:
>>>>>>>
>>>>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>>>>
>>>>>>>>> This change adds the programming of the MOCS registers to the gen 9+
>>>>>>>>> platforms. This change set programs the MOCS register values to a set
>>>>>>>>> of values that are defined to be optimal.
>>>>>>>>>
>>>>>>>>> It creates a fixed register set that is programmed across the different
>>>>>>>>> engines so that all engines have the same table. This is done as the
>>>>>>>>> main RCS context only holds the registers for itself and the shared
>>>>>>>>> L3 values. By trying to keep the registers consistent across the
>>>>>>>>> different engines it should make the programming for the registers
>>>>>>>>> consistent.
>>>>>>>>>
>>>>>>>>> v2:
>>>>>>>>> -'static const' for private data structures and style changes.(Matt
>>>>>>> Turner)
>>>>>>>>> v3:
>>>>>>>>> - Make the tables "slightly" more readable. (Damien Lespiau)
>>>>>>>>> - Updated tables fix performance regression.
>>>>>>>>> v4:
>>>>>>>>> - Code formatting. (Chris Wilson)
>>>>>>>>> - re-privatised mocs code. (Daniel Vetter)
>>>>>>>>>
>>>>>>>>> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
>>>>>>>>> ---
>>>>>>>>>  drivers/gpu/drm/i915/Makefile     |   1 +
>>>>>>>>>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>>>>>>>>>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>>>>>>>>>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>>>>>>>>>  drivers/gpu/drm/i915/intel_mocs.c | 373
>>>>>>> ++++++++++++++++++++++++++++++++++++++
>>>>>>>>>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>>>>>>>>>  6 files changed, 460 insertions(+), 1 deletion(-)
>>>>>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>>>>>>>>> index b7ddf48..c781e19 100644
>>>>>>>>> --- a/drivers/gpu/drm/i915/Makefile
>>>>>>>>> +++ b/drivers/gpu/drm/i915/Makefile
>>>>>>>>> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>>>>>>>>>  	  i915_irq.o \
>>>>>>>>>  	  i915_trace_points.o \
>>>>>>>>>  	  intel_lrc.o \
>>>>>>>>> +	  intel_mocs.o \
>>>>>>>>>  	  intel_ringbuffer.o \
>>>>>>>>>  	  intel_uncore.o
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h
>>>>>>> b/drivers/gpu/drm/i915/i915_reg.h
>>>>>>>>> index 7213224..3a435b5 100644
>>>>>>>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>>>>>>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>>>>>>>> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>>>>>>>>>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>>>>>>>>>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>>>>>>>>>
>>>>>>>>> +/* MOCS (Memory Object Control State) registers */
>>>>>>>>> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control
>>>>>>> base */
>>>>>>>>> +
>>>>>>>>> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base
>>>>>>> register*/
>>>>>>>>> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base
>>>>>>> register*/
>>>>>>>>> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base
>>>>>>> register*/
>>>>>>>>> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
>>>>>>>>> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base
>>>>>>> register*/
>>>>>>>>> +
>>>>>>>>>  #endif /* _I915_REG_H_ */
>>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>> b/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>>>> index 9f5485d..73b919d 100644
>>>>>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>>>> @@ -135,6 +135,7 @@
>>>>>>>>>  #include <drm/drmP.h>
>>>>>>>>>  #include <drm/i915_drm.h>
>>>>>>>>>  #include "i915_drv.h"
>>>>>>>>> +#include "intel_mocs.h"
>>>>>>>>>
>>>>>>>>>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>>>>>>>>>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
>>>>>>>>> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct
>>>>>>> intel_ringbuffer *ringbuf,
>>>>>>>>>   *
>>>>>>>>>   * Return: non-zero if the ringbuffer is not ready to be written to.
>>>>>>>>>   */
>>>>>>>>> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>>>>  				    struct intel_context *ctx, int
>>>>>>> num_dwords)
>>>>>>>>>  {
>>>>>>>>>  	struct intel_engine_cs *ring = ringbuf->ring;
>>>>>>>>> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct
>>>>>>> intel_engine_cs *ring,
>>>>>>>>>  	if (ret)
>>>>>>>>>  		return ret;
>>>>>>>>>
>>>>>>>>> +	/*
>>>>>>>>> +	 * Failing to program the MOCS is non-fatal.The system will not
>>>>>>>>> +	 * run at peak performance. So generate a warning and carry on.
>>>>>>>>> +	 */
>>>>>>>>> +	if (gen9_program_mocs(ring, ctx) != 0)
>>>>>>>>> +		DRM_ERROR("MOCS failed to program: expect performance
>>>>>>> issues.");
>>>>>>>>> +
>>>>>>>>>  	return intel_lr_context_render_state_init(ring, ctx);
>>>>>>>>>  }
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>> b/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>>>> index 04d3a6d..dbbd6af 100644
>>>>>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>>>> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>>>>>>>>>
>>>>>>>>>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>>>>>>>>>  				  struct intel_context *ctx);
>>>>>>>>> +
>>>>>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>>>> +				    struct intel_context *ctx, int
>>>>>>> num_dwords);
>>>>>>>>> +
>>>>>>>>>  /**
>>>>>>>>>   * intel_logical_ring_advance() - advance the ringbuffer tail
>>>>>>>>>   * @ringbuf: Ringbuffer to advance.
>>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.c
>>>>>>> b/drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>>> new file mode 100644
>>>>>>>>> index 0000000..7c09e67
>>>>>>>>> --- /dev/null
>>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>>> @@ -0,0 +1,373 @@
>>>>>>>>> +/*
>>>>>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>>>>>> + *
>>>>>>>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>>>>>> a
>>>>>>>>> + * copy of this software and associated documentation files (the
>>>>>>> "Software"),
>>>>>>>>> + * to deal in the Software without restriction, including without
>>>>>>> limitation
>>>>>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>>>>> sublicense,
>>>>>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>>>>>> + * Software is furnished to do so, subject to the following conditions: *
>>>>>>>>> + * The above copyright notice and this permission notice (including the
>>>>>>> next
>>>>>>>>> + * paragraph) shall be included in all copies or substantial portions of
>>>>>>> the
>>>>>>>>> + * Software.
>>>>>>>>> + *
>>>>>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>>>>> EXPRESS OR
>>>>>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>>>>> MERCHANTABILITY,
>>>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>>>>>>> SHALL
>>>>>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>>>>> OTHER
>>>>>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>>>>> ARISING FROM,
>>>>>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>>>>>> IN THE
>>>>>>>>> + * SOFTWARE.
>>>>>>>>> + *
>>>>>>>>> + * Authors:
>>>>>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>>>>>> + */
>>>>>>>>> +
>>>>>>>>> +#include "intel_mocs.h"
>>>>>>>>> +#include "intel_lrc.h"
>>>>>>>>> +#include "intel_ringbuffer.h"
>>>>>>>>> +
>>>>>>>>> +/* structures required */
>>>>>>>>> +struct drm_i915_mocs_entry {
>>>>>>>>> +	u32	control_value;
>>>>>>>>> +	u16	l3cc_value;
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +struct drm_i915_mocs_table {
>>>>>>>>> +	u32					size;
>>>>>>>>> +	const struct drm_i915_mocs_entry	*table;
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
>>>>>>>>> +#define	MOCS_CACHEABILITY(value)	(value << 0)
>>>>>>>>> +#define	MOCS_TGT_CACHE(value)		(value << 2)
>>>>>>>>> +#define	MOCS_LRUM(value)		(value << 4)
>>>>>>>>> +#define	MOCS_AOM(value)			(value << 6)
>>>>>>>>> +#define	MOCS_LECC_ESC(value)		(value << 7)
>>>>>>>>> +#define	MOCS_LECC_SCC(value)		(value << 8)
>>>>>>>>> +#define	MOC_PFM(value)			(value << 11)
>>>>>>>>> +#define	MOCS_SCF(value)			(value << 14)
>>>>>>>>> +
>>>>>>>>> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word
>>>>>>> */
>>>>>>>>> +#define	MOCS_ESC(value)			(value << 0)
>>>>>>>>> +#define	MOCS_SCC(value)			(value << 1)
>>>>>>>>> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
>>>>>>>>> +
>>>>>>>>> +/* Helper defines */
>>>>>>>>> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program
>>>>>>> */
>>>>>>>>> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd
>>>>>>> */
>>>>>>>>> +
>>>>>>>>> +/* EDRAM Caching options */
>>>>>>>>> +#define EDRAM_PAGETABLE		(0)
>>>>>>>>> +#define EDRAM_UC		(1)
>>>>>>>>> +#define EDRAM_RESERVED		(2)
>>>>>>>>
>>>>>>>> According to the BSpec this is WT rather than reserved?a
>>>>>>> Just checked the Bspec and you are correct, changing the text.
>>>>>>> As well as for the items below.
>>>>>> Just to add - I was looking at the wrong gen.
>>>>>>>>
>>>>>>>>> +#define EDRAM_WB		(3)
>>>>>>>>> +
>>>>>>>>> +/* L3 Caching options */
>>>>>>>>> +#define L3_DIRECT		(0)
>>>>>>>>> +#define L3_UC			(1)
>>>>>>>>> +#define L3_RESERVED		(2)
>>>>>>>>> +#define L3_WB			(3)
>>>>>>>>> +
>>>>>>>>> +/* target cache */
>>>>>>>>> +#define ELLC			(0)
>>>>>>>>
>>>>>>>> BSpec says that this is "Use TC/LRU controls from page table", but upon
>>>>>>>> a closer look it seems like the BSpec is wrong and your patch is
>>>>>>>> correct.  Can you confirm that this is what you intended?
>>>>>>> These values look good, they are bits 3:2 for the XXX_MOCS_N registers
>>>>>>> (c800) and friends.
>>>>>>>>
>>>>>>>>> +#define LLC			(1)
>>>>>>>>> +#define LLC_ELLC		(2)
>>>>>>>>> +
>>>>>>>>> +/*
>>>>>>>>> + * MOCS tables
>>>>>>>>> + *
>>>>>>>>> + * These are the MOCS tables that are programmed across all the rings.
>>>>>>>>> + * The control value is programmed to all the rings that support the
>>>>>>>>> + * MOCS registers. While the l3cc_values are only programmed to the
>>>>>>>>> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
>>>>>>>>> + *
>>>>>>>>> + * NOTE: These tables MUST start with being uncached and the length MUST
>>>>>>> be
>>>>>>>>> + *       less than 63 as the last two registers are reserved by the
>>>>>>> hardware.
>>>>>>>>> + */
>>>>>>>>> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
>>>>>>>>> +	 /* {0x00000009, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +	 /* {0x0000003b, 0x0030} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>> +	 /* {0x00000039, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +	 /* {0x00000017, 0x0030} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>> +	 /* {0x00000017, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +	 /* {0x00000019, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +	 /* {0x00000037, 0x0030} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>> +	 /* {0x00000037, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +};
>>>>>>>>
>>>>>>>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE, L3CC=WB,
>>>>>>>> everything else unset, I'll reply with a userspace patch making use of
>>>>>>>> your change if you add such an entry.
>>>>>> Ok. I think what you want is, same as entry two, but use the underlying
>>>>>> pagetable settings and not specify the EDRAM settings. Please confirm in
>>>>>> the new patchset.
>>>>>
>>>>> Yeah, that sounds good.
>>>>>
>>>>>>>>
>>>>>>>> Another thing worth mentioning is that entries 0, 2 and 5 seem to do the
>>>>>>>> same thing suspiciously, the only difference is the LRUM field which
>>>>>>>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding correct?
>>>>>>>>
>>>>>>> These tables are generated via requests and then boiled down to the above.
>>>>>>> So some of the entries are by request. Swings and roundabouts, can remove
>>>>>>> the ones that look redundant but then the tuning that has been done wont
>>>>>>> match. I'll add the new entry at the end of the table.
>>>>
>>>> Are you planning to propagate the entry you just added back to the
>>>> original table this was generated from?  What about new entries we may
>>>> need to add in the future?  What should be the process to make sure that
>>>> our table and the master table don't diverge and end up with conflicting
>>>> entries we cannot remove because of ABI compatibility?  I guess there
>>>> should be a comment on the top warning that the table is part of the
>>>> kernel ABI and supposed to be kept in sync with your table, so other
>>>> people don't change it unknowingly?
>>>>
>>>> Thanks.
>>> I am talking to the team that handles this and see if they will add this
>>> (so future gens this is baked in) but it is unlikely that the other tables
>>> will stay in step as getting in changes will cause too much grief getting
>>> them upstreamed and as the table is auto-generated we will not be able to
>>> guarantee the ordering. It will have to be manual job for anyone doing
>>> this. It is required for other platforms for the tables to match the
>>> userspace for performance reasons, but on Linux it will be by request if
>>> there is a problem. We will see what happens.
>>>
>> I think it only makes sense for Linux to maintain compatibility with
>> Android's tables if we agree on some straightforward process for us to
>> allocate new entries without causing conflicts (otherwise people are
>> likely to ignore the issue completely and let the tables diverge, as you
>> mentioned yourself), and have some guarantee that any entries ever
>> contributed by your team to the Linux kernel (and therefore part of our
>> stable ABI) will never be changed or reordered in the future.
>>
> I think internally (and informally) that we cannot keep sync between Android
> and Linux. We need to keep compatibility with userspace and there is no
> guarantee of ordering as these tables are generated at runtime. The tables
> that are in Linux are a snapshot. These changes are supposed to stabilise at
> PV so they don't change in the future, but if a bug or good performance
> enhancement occurs I can't imagine that they wont make the changes.
>
Right...  In that case I believe that if we import the Android driver's
tables now and pretend that we are compatible we will just be delaying
the inevitable.  We could just as well start over with clean tables and
save us some unnecessary pain.  I propose we start off with the
following minimal table that should be sufficient to suit the current
needs of Mesa, Beignet and the DDX:

    LeCC  TC        LRUM  L3CC
 0: UC    LLC_ELLC  3     UC   
 1: PTE   LLC_ELLC  3     WB
 2: WB    LLC_ELLC  3     WB

All other parameters unset.  The same three entries would be used in
SKL's and BXT's table to avoid making userspace's life unnecessarily
more difficult.  I'd understand if you consider redefining the tables to
be no longer your business, in that case please let me know and I'll
make the change myself as a follow-up on top of your patch.

Thanks.

>> I have the impression that because of your development model you have
>> far more freedom to make changes in your kernel ABI after the fact than
>> we do -- OTOH we would be locked in if we accept to import Android's
>> tables now, what brings me to the next question: How would you feel
>> about reversing the roles of our tables?  The workflow could be as
>> follows:
> The Android kernel is more flexible, in what it accepts, and secondly (and
> more importantly) you should be using the userspace drivers as this is
> the API and is tuned, so changing the tables are less of a problem.
>>
>>
>> - The MOCS tables part of the Linux kernel would be developed and
>>   discussed publicly in this mailing list, independently from your team
>>   (which doesn't mean that your contributions and feed-back regarding
>>   future changes in the MOCS tables wouldn't be very much welcome).
>>
> This is fine. But be aware the RFC for the MOCS was first floated in March and
> teams were directly contacted when this happened and not a lot of response
> was received. MOCS ain't sexy and people only get interested when they
> feel that they maybe a performance problem - then they look to caching.
>
> But, I think this is the sensible model. For the new tables (new gens) a drop
> from the internal cache models as these will have had some form of tuning from
> different teams and requirements (OpenCL, OpenGL, Media, Security, etc...) then
> these can be discussed on the mailing list as required.
>
> I am not sure if that is acceptable to everyone. As we are going to have to
> carry some patches in Android and drop any upstream MOCS changes.
>
>> - If you wish you may maintain compatibility with Linux by sync'ing
>>   your tables periodically.  If you do you may still have the choice to
>>   break compatibility in the future and start from scratch with clean
>>   tables if this turns out to become a burden for you.  (Note that the
>>   converse statement doesn't work if the tables part of the Linux
>>   kernel were to be considered downstream, because we have the
>>   requirement of keeping backwards compatibility with previous
>>   revisions of the ABI).
> This is not really possible. As mentioned above ordering may change.
>>
>> - If you choose to keep compatibility the process for you to allocate
>>   new entries avoiding conflicts should be relatively straightforward:
>>   Send a patch to this mailing list and once it's ACK'ed you would have
>>   the guarantee that the same index wouldn't ever be reused for any
>>   other purpose in the future, and you could start making use of it in
>>   the Android stack right away.
> It would be possible to allocate a high number say in the 60's as the current
> table is generated from 270+ policies and only spits out 8 or 9 entries. So the
> chance of the tables getting into the 60's is quite low. That could be an
> option, but I can see that being poo-pooed upstream with the simple question
> of why not start at 0.
>
> Like you, it would be nice too see what others think.
>
> Peter.
>
>>
>> How do you feel about this proposal?  It would also be nice to hear the
>> opinion of other people from the Linux side.  Ben?  Jesse?
>>
>>> Peter.
>>>
>>>>
>>>>>>>>> +
>>>>>>>>> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
>>>>>>>>> +	 /* {0x00000001, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
>>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +	 /* {0x00000005, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +	 /* {0x00000005, 0x0030} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>> +	 /* {0x00000017, 0x0030} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>> +	 /* {0x00000017, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +	 /* {0x00000019, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +	 /* {0x00000037, 0x0030} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>> +	 /* {0x00000037, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>
>>>>>>>> Wouldn't it be a good idea to have BXT's entries match SKL's for a given
>>>>>>>> index?  The TC, LeCC and LRUM settings you do here arguably don't have
>>>>>>>> any effect on BXT, L3CC does but it doesn't match SKL's setting for
>>>>>>>> entries 1 and 2.  Is there any reason for this?
>>>>>>> As mentioned above this table is auto-generated and matches another tuned
>>>>>>> table, simply keeping them the same allows for the tuning to be consistent
>>>>>>> across platforms.
>>>>>>>
>>>>>>> Peter.
>>>>>>>>
>>>>>>>> Other than that looks good.
>>>>>>>>
>>>>>>>>> +/**
>>>>>>>>> + * get_mocs_settings
>>>>>>>>> + *
>>>>>>>>> + * 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
>>>>>>>>> + * to be programmed and if they need to be programmed.
>>>>>>>>> + *
>>>>>>>>> + * If the return values is false then the registers do not need
>>>>>>> programming.
>>>>>>>>> + */
>>>>>>>>> +static bool get_mocs_settings(struct drm_device *dev,
>>>>>>>>> +			      struct drm_i915_mocs_table *table) {
>>>>>>>>> +	bool	result = false;
>>>>>>>>> +
>>>>>>>>> +	if (IS_SKYLAKE(dev)) {
>>>>>>>>> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
>>>>>>>>> +		table->table = skylake_mocs_table;
>>>>>>>>> +		result = true;
>>>>>>>>> +	} else if (IS_BROXTON(dev)) {
>>>>>>>>> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
>>>>>>>>> +		table->table = broxton_mocs_table;
>>>>>>>>> +		result = true;
>>>>>>>>> +	} else {
>>>>>>>>> +		/* Platform that should have a MOCS table does not */
>>>>>>>>> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
>>>>>>>>> +	}
>>>>>>>>> +
>>>>>>>>> +	return result;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * emit_mocs_control_table() - emit the mocs control table
>>>>>>>>> + * @ringbuf:	DRM device.
>>>>>>>>> + * @table:	The values to program into the control regs.
>>>>>>>>> + * @reg_base:	The base for the Engine that needs to be programmed.
>>>>>>>>> + *
>>>>>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>>>>>> + * given table starting at the given address.
>>>>>>>>> + *
>>>>>>>>> + * Return: Nothing.
>>>>>>>>> + */
>>>>>>>>> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
>>>>>>>>> +				    struct drm_i915_mocs_table *table,
>>>>>>>>> +				    u32 reg_base)
>>>>>>>>> +{
>>>>>>>>> +	unsigned int index;
>>>>>>>>> +
>>>>>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
>>>>>>>>> +
>>>>>>>>> +	for (index = 0; index < table->size; index++) {
>>>>>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>>>>>> +		intel_logical_ring_emit(ringbuf,
>>>>>>>>> +					table->table[index].control_value);
>>>>>>>>> +	}
>>>>>>>>> +
>>>>>>>>> +	/*
>>>>>>>>> +	 * Ok, now set the unused entries to uncached. These entries are
>>>>>>>>> +	 * officially undefined and no contact is given for the contents and
>>>>>>>>> +	 * settings is given for these entries.
>>>>>>>>> +	 *
>>>>>>>>> +	 * Entry 0 in the table is uncached - so we are just written that
>>>>>>>>> +	 * value to all the used entries.
>>>>>>>>> +	 */
>>>>>>>>> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
>>>>>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>>>>>> +		intel_logical_ring_emit(ringbuf,
>>>>>>> table->table[0].control_value);
>>>>>>>>> +	}
>>>>>>>>> +
>>>>>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * emit_mocs_l3cc_table() - emit the mocs control table
>>>>>>>>> + * @ringbuf:	DRM device.
>>>>>>>>> + * @table:	The values to program into the control regs.
>>>>>>>>> + *
>>>>>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>>>>>> + * given table starting at the given address. This register set is
>>>>>>> programmed
>>>>>>>>> + * in pairs.
>>>>>>>>> + *
>>>>>>>>> + * Return: Nothing.
>>>>>>>>> + */
>>>>>>>>> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
>>>>>>>>> +			 struct drm_i915_mocs_table *table) {
>>>>>>>>> +	unsigned int count;
>>>>>>>>> +	unsigned int i;
>>>>>>>>> +	u32 value;
>>>>>>>>> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
>>>>>>>>> +			((table->table[0].l3cc_value & 0xffff) << 16);
>>>>>>>>> +
>>>>>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
>>>>>>>>> +
>>>>>>>>> +	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);
>>>>>>>>> +
>>>>>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>>>>>> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
>>>>>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>>>>>> +		intel_logical_ring_emit(ringbuf, value);
>>>>>>>>> +
>>>>>>>>> +		value = filler;
>>>>>>>>> +	}
>>>>>>>>> +
>>>>>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +/*
>>>>>>>>> + * gen9_program_mocs() - program the MOCS register.
>>>>>>>>> + *
>>>>>>>>> + * ring:	The ring that the programming batch will be run in.
>>>>>>>>> + * ctx:		The intel_context to be used.
>>>>>>>>> + *
>>>>>>>>> + * This function will emit a batch buffer with the values required for
>>>>>>>>> + * programming the MOCS register values for all the currently supported
>>>>>>>>> + * rings.
>>>>>>>>> + *
>>>>>>>>> + * These registers are partially stored in the RCS context, so they are
>>>>>>>>> + * emitted at the same time so that when a context is created these
>>>>>>> registers
>>>>>>>>> + * are set up. These registers have to be emitted into the start of the
>>>>>>>>> + * context as setting the ELSP will re-init some of these registers back
>>>>>>>>> + * to the hw values.
>>>>>>>>> + *
>>>>>>>>> + * Return: 0 on success, otherwise the error status.
>>>>>>>>> + */
>>>>>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>>>>>> +			  struct intel_context *ctx)
>>>>>>>>> +{
>>>>>>>>> +	int ret = 0;
>>>>>>>>> +
>>>>>>>>> +	struct drm_i915_mocs_table t;
>>>>>>>>> +	struct drm_device *dev = ring->dev;
>>>>>>>>> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
>>>>>>>>> +
>>>>>>>>> +	if (get_mocs_settings(dev, &t)) {
>>>>>>>>> +		u32 table_size;
>>>>>>>>> +
>>>>>>>>> +		/*
>>>>>>>>> +		 * OK. For each supported ring:
>>>>>>>>> +		 *  number of mocs entries * 2 dwords for each control_value
>>>>>>>>> +		 *  plus number of mocs entries /2 dwords for l3cc values.
>>>>>>>>> +		 *
>>>>>>>>> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
>>>>>>>>> +		 *  and the l3cc programming.
>>>>>>>>> +		 */
>>>>>>>>> +		table_size = GEN9_NUM_MOCS_RINGS *
>>>>>>>>> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
>>>>>>>>> +				GEN9_NUM_MOCS_ENTRIES + 2;
>>>>>>>>> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
>>>>>>>>> +		if (ret) {
>>>>>>>>> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n",
>>>>>>> ret);
>>>>>>>>> +			return ret;
>>>>>>>>> +		}
>>>>>>>>> +
>>>>>>>>> +		/* program the control registers */
>>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
>>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
>>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
>>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
>>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
>>>>>>>>> +
>>>>>>>>> +		/* now program the l3cc registers */
>>>>>>>>> +		emit_mocs_l3cc_table(ringbuf, &t);
>>>>>>>>> +
>>>>>>>>> +		intel_logical_ring_advance(ringbuf);
>>>>>>>>> +
>>>>>>>>> +		DRM_DEBUG("MOCS: Table set in Context\n");
>>>>>>>>> +	} else {
>>>>>>>>> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
>>>>>>>>> +	}
>>>>>>>>> +
>>>>>>>>> +	return ret;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.h
>>>>>>> b/drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>>> new file mode 100644
>>>>>>>>> index 0000000..e2780ce
>>>>>>>>> --- /dev/null
>>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>>> @@ -0,0 +1,64 @@
>>>>>>>>> +/*
>>>>>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>>>>>> + *
>>>>>>>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>>>>>> a
>>>>>>>>> + * copy of this software and associated documentation files (the
>>>>>>> "Software"),
>>>>>>>>> + * to deal in the Software without restriction, including without
>>>>>>> limitation
>>>>>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>>>>> sublicense,
>>>>>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>>>>>> + * Software is furnished to do so, subject to the following conditions:
>>>>>>>>> + *
>>>>>>>>> + * The above copyright notice and this permission notice (including the
>>>>>>> next
>>>>>>>>> + * paragraph) shall be included in all copies or substantial portions of
>>>>>>> the
>>>>>>>>> + * Software.
>>>>>>>>> + *
>>>>>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>>>>> EXPRESS OR
>>>>>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>>>>> MERCHANTABILITY,
>>>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>>>>>>> SHALL
>>>>>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>>>>> OTHER
>>>>>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>>>>> ARISING FROM,
>>>>>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>>>>>> IN THE
>>>>>>>>> + * SOFTWARE.
>>>>>>>>> + *
>>>>>>>>> + * Authors:
>>>>>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>>>>>> + */
>>>>>>>>> +
>>>>>>>>> +#ifndef INTEL_MOCS_H
>>>>>>>>> +#define INTEL_MOCS_H
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * DOC: Memory Objects Control State (MOCS)
>>>>>>>>> + *
>>>>>>>>> + * Motivation:
>>>>>>>>> + * In previous Gens the MOCS settings was a value that was set by user
>>>>>>> land as
>>>>>>>>> + * part of the batch. In Gen9 this has changed to be a single table (per
>>>>>>> ring)
>>>>>>>>> + * that all batches now reference by index instead of programming the
>>>>>>> MOCS
>>>>>>>>> + * directly.
>>>>>>>>> + *
>>>>>>>>> + * The one wrinkle in this is that only PART of the MOCS tables are
>>>>>>> included
>>>>>>>>> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 -
>>>>>>> LNCFCMOCS32
>>>>>>>>> + * registers). The rest are not (the settings for the other rings).
>>>>>>>>> + *
>>>>>>>>> + * This table needs to be set at system start-up because the way the
>>>>>>> table
>>>>>>>>> + * interacts with the contexts and the GmmLib interface.
>>>>>>>>> + *
>>>>>>>>> + *
>>>>>>>>> + * Implementation:
>>>>>>>>> + *
>>>>>>>>> + * The table is programmed on a platform basis from a table that is
>>>>>>> generated
>>>>>>>>> + * from the one that has been agreed by the different responsible
>>>>>>> parties. This
>>>>>>>>> + * tables (one per supported platform) is defined in intel_mocs.c and is
>>>>>>>>> + * programmed in the first batch after the context is loaded (with the
>>>>>>> hardware
>>>>>>>>> + * workarounds). This will then let the usual context handling keep the
>>>>>>> MOCS in
>>>>>>>>> + * step.
>>>>>>>>> + */
>>>>>>>>> +
>>>>>>>>> +#include <drm/drmP.h>
>>>>>>>>> +#include "i915_drv.h"
>>>>>>>>> +
>>>>>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>>>>>> +			struct intel_context *ctx);
>>>>>>>>> +
>>>>>>>>> +#endif
>>>>>>>>> +
>>>>>>>>> --
>>>>>>>>> 1.9.1
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> Intel-gfx mailing list
>>>>>>>>> Intel-gfx@lists.freedesktop.org
>>>>>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>>    Peter Antoine (Android Graphics Driver Software Engineer)
>>>>>>>    ---------------------------------------------------------------------
>>>>>>>    Intel Corporation (UK) Limited
>>>>>>>    Registered No. 1134945 (England)
>>>>>>>    Registered Office: Pipers Way, Swindon SN3 1RJ
>>>>>>>    VAT No: 860 2173 47
>>>>>>> _______________________________________________
>>>>>>> Intel-gfx mailing list
>>>>>>> Intel-gfx@lists.freedesktop.org
>>>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>>>>
>>>>>>
>>>>>> --
>>>>>>     Peter Antoine (Android Graphics Driver Software Engineer)
>>>>>>     ---------------------------------------------------------------------
>>>>>>     Intel Corporation (UK) Limited
>>>>>>     Registered No. 1134945 (England)
>>>>>>     Registered Office: Pipers Way, Swindon SN3 1RJ
>>>>>>     VAT No: 860 2173 47
>>>>> _______________________________________________
>>>>> Intel-gfx mailing list
>>>>> Intel-gfx@lists.freedesktop.org
>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>
>>>
>>> --
>>>     Peter Antoine (Android Graphics Driver Software Engineer)
>>>     ---------------------------------------------------------------------
>>>     Intel Corporation (UK) Limited
>>>     Registered No. 1134945 (England)
>>>     Registered Office: Pipers Way, Swindon SN3 1RJ
>>>     VAT No: 860 2173 47
>>
>
> --
>     Peter Antoine (Android Graphics Driver Software Engineer)
>     ---------------------------------------------------------------------
>     Intel Corporation (UK) Limited
>     Registered No. 1134945 (England)
>     Registered Office: Pipers Way, Swindon SN3 1RJ
>     VAT No: 860 2173 47
Jesse Barnes July 1, 2015, 3:14 p.m. UTC | #21
On 07/01/2015 06:53 AM, Peter Antoine wrote:
> On Wed, 1 Jul 2015, Francisco Jerez wrote:
> 
>> Peter Antoine <peter.antoine@intel.com> writes:
>>
>>> On Tue, 30 Jun 2015, Francisco Jerez wrote:
>>>
>>>> Francisco Jerez <currojerez@riseup.net> writes:
>>>>
>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>
>>>>>> On Mon, 29 Jun 2015, Peter Antoine wrote:
>>>>>>
>>>>>>> On Thu, 25 Jun 2015, Francisco Jerez wrote:
>>>>>>>
>>>>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>>>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE,
>>>>>>>> L3CC=WB,
>>>>>>>> everything else unset, I'll reply with a userspace patch making
>>>>>>>> use of
>>>>>>>> your change if you add such an entry.
>>>>>> Ok. I think what you want is, same as entry two, but use the
>>>>>> underlying
>>>>>> pagetable settings and not specify the EDRAM settings. Please
>>>>>> confirm in
>>>>>> the new patchset.
>>>>>
>>>>> Yeah, that sounds good.
>>>>>
>>>>>>>>
>>>>>>>> Another thing worth mentioning is that entries 0, 2 and 5 seem
>>>>>>>> to do the
>>>>>>>> same thing suspiciously, the only difference is the LRUM field
>>>>>>>> which
>>>>>>>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding
>>>>>>>> correct?
>>>>>>>>
>>>>>>> These tables are generated via requests and then boiled down to
>>>>>>> the above.
>>>>>>> So some of the entries are by request. Swings and roundabouts,
>>>>>>> can remove
>>>>>>> the ones that look redundant but then the tuning that has been
>>>>>>> done wont
>>>>>>> match. I'll add the new entry at the end of the table.
>>>>
>>>> Are you planning to propagate the entry you just added back to the
>>>> original table this was generated from?  What about new entries we may
>>>> need to add in the future?  What should be the process to make sure
>>>> that
>>>> our table and the master table don't diverge and end up with
>>>> conflicting
>>>> entries we cannot remove because of ABI compatibility?  I guess there
>>>> should be a comment on the top warning that the table is part of the
>>>> kernel ABI and supposed to be kept in sync with your table, so other
>>>> people don't change it unknowingly?
>>>>
>>>> Thanks.
>>> I am talking to the team that handles this and see if they will add this
>>> (so future gens this is baked in) but it is unlikely that the other
>>> tables
>>> will stay in step as getting in changes will cause too much grief
>>> getting
>>> them upstreamed and as the table is auto-generated we will not be
>>> able to
>>> guarantee the ordering. It will have to be manual job for anyone doing
>>> this. It is required for other platforms for the tables to match the
>>> userspace for performance reasons, but on Linux it will be by request if
>>> there is a problem. We will see what happens.
>>>
>> I think it only makes sense for Linux to maintain compatibility with
>> Android's tables if we agree on some straightforward process for us to
>> allocate new entries without causing conflicts (otherwise people are
>> likely to ignore the issue completely and let the tables diverge, as you
>> mentioned yourself), and have some guarantee that any entries ever
>> contributed by your team to the Linux kernel (and therefore part of our
>> stable ABI) will never be changed or reordered in the future.
>>
> I think internally (and informally) that we cannot keep sync between
> Android
> and Linux. We need to keep compatibility with userspace and there is no
> guarantee of ordering as these tables are generated at runtime. The tables
> that are in Linux are a snapshot. These changes are supposed to
> stabilise at
> PV so they don't change in the future, but if a bug or good performance
> enhancement occurs I can't imagine that they wont make the changes.

Wow this discussion just keeps going.  Who'd have thought such a simple
table would cause so much trouble? :)

What you mention above is a key point: "these tables are generated at
runtime. The tables that are in Linux are a snapshot. These changes are
supposed to stabilise at PV so they don't change in the future, but if a
bug or good performance enhancement occurs I can't imagine that they
wont make the changes."

That really argues for a runtime API that allows the userland drivers to
load in MOCS values.  I'm not sure if it's practical to make the table
effectively part of the context (lazily applying new values if we detect
a change vs the defaults), but that would at least let the different
user level drivers do whatever they think is ideal...

>> I have the impression that because of your development model you have
>> far more freedom to make changes in your kernel ABI after the fact than
>> we do -- OTOH we would be locked in if we accept to import Android's
>> tables now, what brings me to the next question: How would you feel
>> about reversing the roles of our tables?  The workflow could be as
>> follows:
> The Android kernel is more flexible, in what it accepts, and secondly (and
> more importantly) you should be using the userspace drivers as this is
> the API and is tuned, so changing the tables are less of a problem.
>>
>>
>> - The MOCS tables part of the Linux kernel would be developed and
>>   discussed publicly in this mailing list, independently from your team
>>   (which doesn't mean that your contributions and feed-back regarding
>>   future changes in the MOCS tables wouldn't be very much welcome).
>>
> This is fine. But be aware the RFC for the MOCS was first floated in
> March and
> teams were directly contacted when this happened and not a lot of response
> was received. MOCS ain't sexy and people only get interested when they
> feel that they maybe a performance problem - then they look to caching.
> 
> But, I think this is the sensible model. For the new tables (new gens) a
> drop
> from the internal cache models as these will have had some form of
> tuning from
> different teams and requirements (OpenCL, OpenGL, Media, Security,
> etc...) then
> these can be discussed on the mailing list as required.
> 
> I am not sure if that is acceptable to everyone. As we are going to have to
> carry some patches in Android and drop any upstream MOCS changes.

Yeah given the potential for changes coming from the Android side, it
seems like this is the way to go for upstream.  I guess that means we
just need a couple of entries to start with in upstream, and we can add
to them in an ordered and compatible way as needed (unless we decide to
pursue a runtime interface anyway).

> Like you, it would be nice too see what others think.

I guess I'd prefer the simple approach of just adding a few entries at a
time after discussion, and a runtime interface if we need it.  It's too
bad the Android side can't commit to a stable set of entries with
specific ordering, with just additions as needed.  That would let us
just merge your patch as a baseline...

Jesse
Francisco Jerez July 1, 2015, 3:17 p.m. UTC | #22
Francisco Jerez <currojerez@riseup.net> writes:

> Peter Antoine <peter.antoine@intel.com> writes:
>
>> On Wed, 1 Jul 2015, Francisco Jerez wrote:
>>
>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>
>>>> On Tue, 30 Jun 2015, Francisco Jerez wrote:
>>>>
>>>>> Francisco Jerez <currojerez@riseup.net> writes:
>>>>>
>>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>>
>>>>>>> On Mon, 29 Jun 2015, Peter Antoine wrote:
>>>>>>>
>>>>>>>> On Thu, 25 Jun 2015, Francisco Jerez wrote:
>>>>>>>>
>>>>>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>>>>>
>>>>>>>>>> This change adds the programming of the MOCS registers to the gen 9+
>>>>>>>>>> platforms. This change set programs the MOCS register values to a set
>>>>>>>>>> of values that are defined to be optimal.
>>>>>>>>>>
>>>>>>>>>> It creates a fixed register set that is programmed across the different
>>>>>>>>>> engines so that all engines have the same table. This is done as the
>>>>>>>>>> main RCS context only holds the registers for itself and the shared
>>>>>>>>>> L3 values. By trying to keep the registers consistent across the
>>>>>>>>>> different engines it should make the programming for the registers
>>>>>>>>>> consistent.
>>>>>>>>>>
>>>>>>>>>> v2:
>>>>>>>>>> -'static const' for private data structures and style changes.(Matt
>>>>>>>> Turner)
>>>>>>>>>> v3:
>>>>>>>>>> - Make the tables "slightly" more readable. (Damien Lespiau)
>>>>>>>>>> - Updated tables fix performance regression.
>>>>>>>>>> v4:
>>>>>>>>>> - Code formatting. (Chris Wilson)
>>>>>>>>>> - re-privatised mocs code. (Daniel Vetter)
>>>>>>>>>>
>>>>>>>>>> Signed-off-by: Peter Antoine <peter.antoine@intel.com>
>>>>>>>>>> ---
>>>>>>>>>>  drivers/gpu/drm/i915/Makefile     |   1 +
>>>>>>>>>>  drivers/gpu/drm/i915/i915_reg.h   |   9 +
>>>>>>>>>>  drivers/gpu/drm/i915/intel_lrc.c  |  10 +-
>>>>>>>>>>  drivers/gpu/drm/i915/intel_lrc.h  |   4 +
>>>>>>>>>>  drivers/gpu/drm/i915/intel_mocs.c | 373
>>>>>>>> ++++++++++++++++++++++++++++++++++++++
>>>>>>>>>>  drivers/gpu/drm/i915/intel_mocs.h |  64 +++++++
>>>>>>>>>>  6 files changed, 460 insertions(+), 1 deletion(-)
>>>>>>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>>>>  create mode 100644 drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>>>>
>>>>>>>>>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>>>>>>>>>> index b7ddf48..c781e19 100644
>>>>>>>>>> --- a/drivers/gpu/drm/i915/Makefile
>>>>>>>>>> +++ b/drivers/gpu/drm/i915/Makefile
>>>>>>>>>> @@ -35,6 +35,7 @@ i915-y += i915_cmd_parser.o \
>>>>>>>>>>  	  i915_irq.o \
>>>>>>>>>>  	  i915_trace_points.o \
>>>>>>>>>>  	  intel_lrc.o \
>>>>>>>>>> +	  intel_mocs.o \
>>>>>>>>>>  	  intel_ringbuffer.o \
>>>>>>>>>>  	  intel_uncore.o
>>>>>>>>>>
>>>>>>>>>> diff --git a/drivers/gpu/drm/i915/i915_reg.h
>>>>>>>> b/drivers/gpu/drm/i915/i915_reg.h
>>>>>>>>>> index 7213224..3a435b5 100644
>>>>>>>>>> --- a/drivers/gpu/drm/i915/i915_reg.h
>>>>>>>>>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>>>>>>>>>> @@ -7829,4 +7829,13 @@ enum skl_disp_power_wells {
>>>>>>>>>>  #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
>>>>>>>>>>  #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
>>>>>>>>>>
>>>>>>>>>> +/* MOCS (Memory Object Control State) registers */
>>>>>>>>>> +#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control
>>>>>>>> base */
>>>>>>>>>> +
>>>>>>>>>> +#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base
>>>>>>>> register*/
>>>>>>>>>> +#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base
>>>>>>>> register*/
>>>>>>>>>> +#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base
>>>>>>>> register*/
>>>>>>>>>> +#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
>>>>>>>>>> +#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base
>>>>>>>> register*/
>>>>>>>>>> +
>>>>>>>>>>  #endif /* _I915_REG_H_ */
>>>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>>> b/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>>>>> index 9f5485d..73b919d 100644
>>>>>>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.c
>>>>>>>>>> @@ -135,6 +135,7 @@
>>>>>>>>>>  #include <drm/drmP.h>
>>>>>>>>>>  #include <drm/i915_drm.h>
>>>>>>>>>>  #include "i915_drv.h"
>>>>>>>>>> +#include "intel_mocs.h"
>>>>>>>>>>
>>>>>>>>>>  #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
>>>>>>>>>>  #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
>>>>>>>>>> @@ -796,7 +797,7 @@ static int logical_ring_prepare(struct
>>>>>>>> intel_ringbuffer *ringbuf,
>>>>>>>>>>   *
>>>>>>>>>>   * Return: non-zero if the ringbuffer is not ready to be written to.
>>>>>>>>>>   */
>>>>>>>>>> -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>>>>>  				    struct intel_context *ctx, int
>>>>>>>> num_dwords)
>>>>>>>>>>  {
>>>>>>>>>>  	struct intel_engine_cs *ring = ringbuf->ring;
>>>>>>>>>> @@ -1379,6 +1380,13 @@ static int gen8_init_rcs_context(struct
>>>>>>>> intel_engine_cs *ring,
>>>>>>>>>>  	if (ret)
>>>>>>>>>>  		return ret;
>>>>>>>>>>
>>>>>>>>>> +	/*
>>>>>>>>>> +	 * Failing to program the MOCS is non-fatal.The system will not
>>>>>>>>>> +	 * run at peak performance. So generate a warning and carry on.
>>>>>>>>>> +	 */
>>>>>>>>>> +	if (gen9_program_mocs(ring, ctx) != 0)
>>>>>>>>>> +		DRM_ERROR("MOCS failed to program: expect performance
>>>>>>>> issues.");
>>>>>>>>>> +
>>>>>>>>>>  	return intel_lr_context_render_state_init(ring, ctx);
>>>>>>>>>>  }
>>>>>>>>>>
>>>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>>> b/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>>>>> index 04d3a6d..dbbd6af 100644
>>>>>>>>>> --- a/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_lrc.h
>>>>>>>>>> @@ -44,6 +44,10 @@ int intel_logical_rings_init(struct drm_device *dev);
>>>>>>>>>>
>>>>>>>>>>  int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
>>>>>>>>>>  				  struct intel_context *ctx);
>>>>>>>>>> +
>>>>>>>>>> +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
>>>>>>>>>> +				    struct intel_context *ctx, int
>>>>>>>> num_dwords);
>>>>>>>>>> +
>>>>>>>>>>  /**
>>>>>>>>>>   * intel_logical_ring_advance() - advance the ringbuffer tail
>>>>>>>>>>   * @ringbuf: Ringbuffer to advance.
>>>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>> b/drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>>>> new file mode 100644
>>>>>>>>>> index 0000000..7c09e67
>>>>>>>>>> --- /dev/null
>>>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.c
>>>>>>>>>> @@ -0,0 +1,373 @@
>>>>>>>>>> +/*
>>>>>>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>>>>>>> + *
>>>>>>>>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>>>>>>> a
>>>>>>>>>> + * copy of this software and associated documentation files (the
>>>>>>>> "Software"),
>>>>>>>>>> + * to deal in the Software without restriction, including without
>>>>>>>> limitation
>>>>>>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>>>>>> sublicense,
>>>>>>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>>>>>>> + * Software is furnished to do so, subject to the following conditions: *
>>>>>>>>>> + * The above copyright notice and this permission notice (including the
>>>>>>>> next
>>>>>>>>>> + * paragraph) shall be included in all copies or substantial portions of
>>>>>>>> the
>>>>>>>>>> + * Software.
>>>>>>>>>> + *
>>>>>>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>>>>>> EXPRESS OR
>>>>>>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>>>>>> MERCHANTABILITY,
>>>>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>>>>>>>> SHALL
>>>>>>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>>>>>> OTHER
>>>>>>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>>>>>> ARISING FROM,
>>>>>>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>>>>>>> IN THE
>>>>>>>>>> + * SOFTWARE.
>>>>>>>>>> + *
>>>>>>>>>> + * Authors:
>>>>>>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>>>>>>> + */
>>>>>>>>>> +
>>>>>>>>>> +#include "intel_mocs.h"
>>>>>>>>>> +#include "intel_lrc.h"
>>>>>>>>>> +#include "intel_ringbuffer.h"
>>>>>>>>>> +
>>>>>>>>>> +/* structures required */
>>>>>>>>>> +struct drm_i915_mocs_entry {
>>>>>>>>>> +	u32	control_value;
>>>>>>>>>> +	u16	l3cc_value;
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +struct drm_i915_mocs_table {
>>>>>>>>>> +	u32					size;
>>>>>>>>>> +	const struct drm_i915_mocs_entry	*table;
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>> +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
>>>>>>>>>> +#define	MOCS_CACHEABILITY(value)	(value << 0)
>>>>>>>>>> +#define	MOCS_TGT_CACHE(value)		(value << 2)
>>>>>>>>>> +#define	MOCS_LRUM(value)		(value << 4)
>>>>>>>>>> +#define	MOCS_AOM(value)			(value << 6)
>>>>>>>>>> +#define	MOCS_LECC_ESC(value)		(value << 7)
>>>>>>>>>> +#define	MOCS_LECC_SCC(value)		(value << 8)
>>>>>>>>>> +#define	MOC_PFM(value)			(value << 11)
>>>>>>>>>> +#define	MOCS_SCF(value)			(value << 14)
>>>>>>>>>> +
>>>>>>>>>> +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word
>>>>>>>> */
>>>>>>>>>> +#define	MOCS_ESC(value)			(value << 0)
>>>>>>>>>> +#define	MOCS_SCC(value)			(value << 1)
>>>>>>>>>> +#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
>>>>>>>>>> +
>>>>>>>>>> +/* Helper defines */
>>>>>>>>>> +#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program
>>>>>>>> */
>>>>>>>>>> +#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd
>>>>>>>> */
>>>>>>>>>> +
>>>>>>>>>> +/* EDRAM Caching options */
>>>>>>>>>> +#define EDRAM_PAGETABLE		(0)
>>>>>>>>>> +#define EDRAM_UC		(1)
>>>>>>>>>> +#define EDRAM_RESERVED		(2)
>>>>>>>>>
>>>>>>>>> According to the BSpec this is WT rather than reserved?a
>>>>>>>> Just checked the Bspec and you are correct, changing the text.
>>>>>>>> As well as for the items below.
>>>>>>> Just to add - I was looking at the wrong gen.
>>>>>>>>>
>>>>>>>>>> +#define EDRAM_WB		(3)
>>>>>>>>>> +
>>>>>>>>>> +/* L3 Caching options */
>>>>>>>>>> +#define L3_DIRECT		(0)
>>>>>>>>>> +#define L3_UC			(1)
>>>>>>>>>> +#define L3_RESERVED		(2)
>>>>>>>>>> +#define L3_WB			(3)
>>>>>>>>>> +
>>>>>>>>>> +/* target cache */
>>>>>>>>>> +#define ELLC			(0)
>>>>>>>>>
>>>>>>>>> BSpec says that this is "Use TC/LRU controls from page table", but upon
>>>>>>>>> a closer look it seems like the BSpec is wrong and your patch is
>>>>>>>>> correct.  Can you confirm that this is what you intended?
>>>>>>>> These values look good, they are bits 3:2 for the XXX_MOCS_N registers
>>>>>>>> (c800) and friends.
>>>>>>>>>
>>>>>>>>>> +#define LLC			(1)
>>>>>>>>>> +#define LLC_ELLC		(2)
>>>>>>>>>> +
>>>>>>>>>> +/*
>>>>>>>>>> + * MOCS tables
>>>>>>>>>> + *
>>>>>>>>>> + * These are the MOCS tables that are programmed across all the rings.
>>>>>>>>>> + * The control value is programmed to all the rings that support the
>>>>>>>>>> + * MOCS registers. While the l3cc_values are only programmed to the
>>>>>>>>>> + * LNCFCMOCS0 - LNCFCMOCS32 registers.
>>>>>>>>>> + *
>>>>>>>>>> + * NOTE: These tables MUST start with being uncached and the length MUST
>>>>>>>> be
>>>>>>>>>> + *       less than 63 as the last two registers are reserved by the
>>>>>>>> hardware.
>>>>>>>>>> + */
>>>>>>>>>> +static struct drm_i915_mocs_entry skylake_mocs_table[] = {
>>>>>>>>>> +	 /* {0x00000009, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +	 /* {0x0000003b, 0x0030} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>>> +	 /* {0x00000039, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +	 /* {0x00000017, 0x0030} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>>> +	 /* {0x00000017, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +	 /* {0x00000019, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +	 /* {0x00000037, 0x0030} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>>> +	 /* {0x00000037, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +};
>>>>>>>>>
>>>>>>>>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE, L3CC=WB,
>>>>>>>>> everything else unset, I'll reply with a userspace patch making use of
>>>>>>>>> your change if you add such an entry.
>>>>>>> Ok. I think what you want is, same as entry two, but use the underlying
>>>>>>> pagetable settings and not specify the EDRAM settings. Please confirm in
>>>>>>> the new patchset.
>>>>>>
>>>>>> Yeah, that sounds good.
>>>>>>
>>>>>>>>>
>>>>>>>>> Another thing worth mentioning is that entries 0, 2 and 5 seem to do the
>>>>>>>>> same thing suspiciously, the only difference is the LRUM field which
>>>>>>>>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding correct?
>>>>>>>>>
>>>>>>>> These tables are generated via requests and then boiled down to the above.
>>>>>>>> So some of the entries are by request. Swings and roundabouts, can remove
>>>>>>>> the ones that look redundant but then the tuning that has been done wont
>>>>>>>> match. I'll add the new entry at the end of the table.
>>>>>
>>>>> Are you planning to propagate the entry you just added back to the
>>>>> original table this was generated from?  What about new entries we may
>>>>> need to add in the future?  What should be the process to make sure that
>>>>> our table and the master table don't diverge and end up with conflicting
>>>>> entries we cannot remove because of ABI compatibility?  I guess there
>>>>> should be a comment on the top warning that the table is part of the
>>>>> kernel ABI and supposed to be kept in sync with your table, so other
>>>>> people don't change it unknowingly?
>>>>>
>>>>> Thanks.
>>>> I am talking to the team that handles this and see if they will add this
>>>> (so future gens this is baked in) but it is unlikely that the other tables
>>>> will stay in step as getting in changes will cause too much grief getting
>>>> them upstreamed and as the table is auto-generated we will not be able to
>>>> guarantee the ordering. It will have to be manual job for anyone doing
>>>> this. It is required for other platforms for the tables to match the
>>>> userspace for performance reasons, but on Linux it will be by request if
>>>> there is a problem. We will see what happens.
>>>>
>>> I think it only makes sense for Linux to maintain compatibility with
>>> Android's tables if we agree on some straightforward process for us to
>>> allocate new entries without causing conflicts (otherwise people are
>>> likely to ignore the issue completely and let the tables diverge, as you
>>> mentioned yourself), and have some guarantee that any entries ever
>>> contributed by your team to the Linux kernel (and therefore part of our
>>> stable ABI) will never be changed or reordered in the future.
>>>
>> I think internally (and informally) that we cannot keep sync between Android
>> and Linux. We need to keep compatibility with userspace and there is no
>> guarantee of ordering as these tables are generated at runtime. The tables
>> that are in Linux are a snapshot. These changes are supposed to stabilise at
>> PV so they don't change in the future, but if a bug or good performance
>> enhancement occurs I can't imagine that they wont make the changes.
>>
> Right...  In that case I believe that if we import the Android driver's
> tables now and pretend that we are compatible we will just be delaying
> the inevitable.  We could just as well start over with clean tables and
> save us some unnecessary pain.  I propose we start off with the
> following minimal table that should be sufficient to suit the current
> needs of Mesa, Beignet and the DDX:
>
>     LeCC  TC        LRUM  L3CC
>  0: UC    LLC_ELLC  3     UC   

Oh, the 0-th entry may as well have LRUM=0 to match your current tables,
it shouldn't make much of a difference for an uncacheable entry anyway
AFAIK.

>  1: PTE   LLC_ELLC  3     WB
>  2: WB    LLC_ELLC  3     WB
>
> All other parameters unset.  The same three entries would be used in
> SKL's and BXT's table to avoid making userspace's life unnecessarily
> more difficult.  I'd understand if you consider redefining the tables to
> be no longer your business, in that case please let me know and I'll
> make the change myself as a follow-up on top of your patch.
>
> Thanks.
>
>>> I have the impression that because of your development model you have
>>> far more freedom to make changes in your kernel ABI after the fact than
>>> we do -- OTOH we would be locked in if we accept to import Android's
>>> tables now, what brings me to the next question: How would you feel
>>> about reversing the roles of our tables?  The workflow could be as
>>> follows:
>> The Android kernel is more flexible, in what it accepts, and secondly (and
>> more importantly) you should be using the userspace drivers as this is
>> the API and is tuned, so changing the tables are less of a problem.
>>>
>>>
>>> - The MOCS tables part of the Linux kernel would be developed and
>>>   discussed publicly in this mailing list, independently from your team
>>>   (which doesn't mean that your contributions and feed-back regarding
>>>   future changes in the MOCS tables wouldn't be very much welcome).
>>>
>> This is fine. But be aware the RFC for the MOCS was first floated in March and
>> teams were directly contacted when this happened and not a lot of response
>> was received. MOCS ain't sexy and people only get interested when they
>> feel that they maybe a performance problem - then they look to caching.
>>
>> But, I think this is the sensible model. For the new tables (new gens) a drop
>> from the internal cache models as these will have had some form of tuning from
>> different teams and requirements (OpenCL, OpenGL, Media, Security, etc...) then
>> these can be discussed on the mailing list as required.
>>
>> I am not sure if that is acceptable to everyone. As we are going to have to
>> carry some patches in Android and drop any upstream MOCS changes.
>>
>>> - If you wish you may maintain compatibility with Linux by sync'ing
>>>   your tables periodically.  If you do you may still have the choice to
>>>   break compatibility in the future and start from scratch with clean
>>>   tables if this turns out to become a burden for you.  (Note that the
>>>   converse statement doesn't work if the tables part of the Linux
>>>   kernel were to be considered downstream, because we have the
>>>   requirement of keeping backwards compatibility with previous
>>>   revisions of the ABI).
>> This is not really possible. As mentioned above ordering may change.
>>>
>>> - If you choose to keep compatibility the process for you to allocate
>>>   new entries avoiding conflicts should be relatively straightforward:
>>>   Send a patch to this mailing list and once it's ACK'ed you would have
>>>   the guarantee that the same index wouldn't ever be reused for any
>>>   other purpose in the future, and you could start making use of it in
>>>   the Android stack right away.
>> It would be possible to allocate a high number say in the 60's as the current
>> table is generated from 270+ policies and only spits out 8 or 9 entries. So the
>> chance of the tables getting into the 60's is quite low. That could be an
>> option, but I can see that being poo-pooed upstream with the simple question
>> of why not start at 0.
>>
>> Like you, it would be nice too see what others think.
>>
>> Peter.
>>
>>>
>>> How do you feel about this proposal?  It would also be nice to hear the
>>> opinion of other people from the Linux side.  Ben?  Jesse?
>>>
>>>> Peter.
>>>>
>>>>>
>>>>>>>>>> +
>>>>>>>>>> +static struct drm_i915_mocs_entry broxton_mocs_table[] = {
>>>>>>>>>> +	 /* {0x00000001, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
>>>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +	 /* {0x00000005, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +	 /* {0x00000005, 0x0030} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>>> +		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>>> +	 /* {0x00000017, 0x0030} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>>> +	 /* {0x00000017, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +	 /* {0x00000019, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>>> +		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +	 /* {0x00000037, 0x0030} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
>>>>>>>>>> +	 /* {0x00000037, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
>>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +	 /* {0x0000003b, 0x0010} */
>>>>>>>>>> +	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
>>>>>>>>>> +		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
>>>>>>>>>> +		MOC_PFM(0) | MOCS_SCF(0)),
>>>>>>>>>> +		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
>>>>>>>>>> +};
>>>>>>>>>> +
>>>>>>>>>
>>>>>>>>> Wouldn't it be a good idea to have BXT's entries match SKL's for a given
>>>>>>>>> index?  The TC, LeCC and LRUM settings you do here arguably don't have
>>>>>>>>> any effect on BXT, L3CC does but it doesn't match SKL's setting for
>>>>>>>>> entries 1 and 2.  Is there any reason for this?
>>>>>>>> As mentioned above this table is auto-generated and matches another tuned
>>>>>>>> table, simply keeping them the same allows for the tuning to be consistent
>>>>>>>> across platforms.
>>>>>>>>
>>>>>>>> Peter.
>>>>>>>>>
>>>>>>>>> Other than that looks good.
>>>>>>>>>
>>>>>>>>>> +/**
>>>>>>>>>> + * get_mocs_settings
>>>>>>>>>> + *
>>>>>>>>>> + * 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
>>>>>>>>>> + * to be programmed and if they need to be programmed.
>>>>>>>>>> + *
>>>>>>>>>> + * If the return values is false then the registers do not need
>>>>>>>> programming.
>>>>>>>>>> + */
>>>>>>>>>> +static bool get_mocs_settings(struct drm_device *dev,
>>>>>>>>>> +			      struct drm_i915_mocs_table *table) {
>>>>>>>>>> +	bool	result = false;
>>>>>>>>>> +
>>>>>>>>>> +	if (IS_SKYLAKE(dev)) {
>>>>>>>>>> +		table->size  = ARRAY_SIZE(skylake_mocs_table);
>>>>>>>>>> +		table->table = skylake_mocs_table;
>>>>>>>>>> +		result = true;
>>>>>>>>>> +	} else if (IS_BROXTON(dev)) {
>>>>>>>>>> +		table->size  = ARRAY_SIZE(broxton_mocs_table);
>>>>>>>>>> +		table->table = broxton_mocs_table;
>>>>>>>>>> +		result = true;
>>>>>>>>>> +	} else {
>>>>>>>>>> +		/* Platform that should have a MOCS table does not */
>>>>>>>>>> +		WARN_ON(INTEL_INFO(dev)->gen >= 9);
>>>>>>>>>> +	}
>>>>>>>>>> +
>>>>>>>>>> +	return result;
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +/**
>>>>>>>>>> + * emit_mocs_control_table() - emit the mocs control table
>>>>>>>>>> + * @ringbuf:	DRM device.
>>>>>>>>>> + * @table:	The values to program into the control regs.
>>>>>>>>>> + * @reg_base:	The base for the Engine that needs to be programmed.
>>>>>>>>>> + *
>>>>>>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>>>>>>> + * given table starting at the given address.
>>>>>>>>>> + *
>>>>>>>>>> + * Return: Nothing.
>>>>>>>>>> + */
>>>>>>>>>> +static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
>>>>>>>>>> +				    struct drm_i915_mocs_table *table,
>>>>>>>>>> +				    u32 reg_base)
>>>>>>>>>> +{
>>>>>>>>>> +	unsigned int index;
>>>>>>>>>> +
>>>>>>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>>>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
>>>>>>>>>> +
>>>>>>>>>> +	for (index = 0; index < table->size; index++) {
>>>>>>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>>>>>>> +		intel_logical_ring_emit(ringbuf,
>>>>>>>>>> +					table->table[index].control_value);
>>>>>>>>>> +	}
>>>>>>>>>> +
>>>>>>>>>> +	/*
>>>>>>>>>> +	 * Ok, now set the unused entries to uncached. These entries are
>>>>>>>>>> +	 * officially undefined and no contact is given for the contents and
>>>>>>>>>> +	 * settings is given for these entries.
>>>>>>>>>> +	 *
>>>>>>>>>> +	 * Entry 0 in the table is uncached - so we are just written that
>>>>>>>>>> +	 * value to all the used entries.
>>>>>>>>>> +	 */
>>>>>>>>>> +	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
>>>>>>>>>> +		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
>>>>>>>>>> +		intel_logical_ring_emit(ringbuf,
>>>>>>>> table->table[0].control_value);
>>>>>>>>>> +	}
>>>>>>>>>> +
>>>>>>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +/**
>>>>>>>>>> + * emit_mocs_l3cc_table() - emit the mocs control table
>>>>>>>>>> + * @ringbuf:	DRM device.
>>>>>>>>>> + * @table:	The values to program into the control regs.
>>>>>>>>>> + *
>>>>>>>>>> + * This function simply emits a MI_LOAD_REGISTER_IMM command for the
>>>>>>>>>> + * given table starting at the given address. This register set is
>>>>>>>> programmed
>>>>>>>>>> + * in pairs.
>>>>>>>>>> + *
>>>>>>>>>> + * Return: Nothing.
>>>>>>>>>> + */
>>>>>>>>>> +static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
>>>>>>>>>> +			 struct drm_i915_mocs_table *table) {
>>>>>>>>>> +	unsigned int count;
>>>>>>>>>> +	unsigned int i;
>>>>>>>>>> +	u32 value;
>>>>>>>>>> +	u32 filler = (table->table[0].l3cc_value & 0xffff) |
>>>>>>>>>> +			((table->table[0].l3cc_value & 0xffff) << 16);
>>>>>>>>>> +
>>>>>>>>>> +	intel_logical_ring_emit(ringbuf,
>>>>>>>>>> +			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
>>>>>>>>>> +
>>>>>>>>>> +	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);
>>>>>>>>>> +
>>>>>>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>>>>>>> +		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
>>>>>>>>>> +		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
>>>>>>>>>> +		intel_logical_ring_emit(ringbuf, value);
>>>>>>>>>> +
>>>>>>>>>> +		value = filler;
>>>>>>>>>> +	}
>>>>>>>>>> +
>>>>>>>>>> +	intel_logical_ring_emit(ringbuf, MI_NOOP);
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +/*
>>>>>>>>>> + * gen9_program_mocs() - program the MOCS register.
>>>>>>>>>> + *
>>>>>>>>>> + * ring:	The ring that the programming batch will be run in.
>>>>>>>>>> + * ctx:		The intel_context to be used.
>>>>>>>>>> + *
>>>>>>>>>> + * This function will emit a batch buffer with the values required for
>>>>>>>>>> + * programming the MOCS register values for all the currently supported
>>>>>>>>>> + * rings.
>>>>>>>>>> + *
>>>>>>>>>> + * These registers are partially stored in the RCS context, so they are
>>>>>>>>>> + * emitted at the same time so that when a context is created these
>>>>>>>> registers
>>>>>>>>>> + * are set up. These registers have to be emitted into the start of the
>>>>>>>>>> + * context as setting the ELSP will re-init some of these registers back
>>>>>>>>>> + * to the hw values.
>>>>>>>>>> + *
>>>>>>>>>> + * Return: 0 on success, otherwise the error status.
>>>>>>>>>> + */
>>>>>>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>>>>>>> +			  struct intel_context *ctx)
>>>>>>>>>> +{
>>>>>>>>>> +	int ret = 0;
>>>>>>>>>> +
>>>>>>>>>> +	struct drm_i915_mocs_table t;
>>>>>>>>>> +	struct drm_device *dev = ring->dev;
>>>>>>>>>> +	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
>>>>>>>>>> +
>>>>>>>>>> +	if (get_mocs_settings(dev, &t)) {
>>>>>>>>>> +		u32 table_size;
>>>>>>>>>> +
>>>>>>>>>> +		/*
>>>>>>>>>> +		 * OK. For each supported ring:
>>>>>>>>>> +		 *  number of mocs entries * 2 dwords for each control_value
>>>>>>>>>> +		 *  plus number of mocs entries /2 dwords for l3cc values.
>>>>>>>>>> +		 *
>>>>>>>>>> +		 *  Plus 1 for the load command and 1 for the NOOP per ring
>>>>>>>>>> +		 *  and the l3cc programming.
>>>>>>>>>> +		 */
>>>>>>>>>> +		table_size = GEN9_NUM_MOCS_RINGS *
>>>>>>>>>> +				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
>>>>>>>>>> +				GEN9_NUM_MOCS_ENTRIES + 2;
>>>>>>>>>> +		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
>>>>>>>>>> +		if (ret) {
>>>>>>>>>> +			DRM_DEBUG("intel_logical_ring_begin failed %d\n",
>>>>>>>> ret);
>>>>>>>>>> +			return ret;
>>>>>>>>>> +		}
>>>>>>>>>> +
>>>>>>>>>> +		/* program the control registers */
>>>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
>>>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
>>>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
>>>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
>>>>>>>>>> +		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
>>>>>>>>>> +
>>>>>>>>>> +		/* now program the l3cc registers */
>>>>>>>>>> +		emit_mocs_l3cc_table(ringbuf, &t);
>>>>>>>>>> +
>>>>>>>>>> +		intel_logical_ring_advance(ringbuf);
>>>>>>>>>> +
>>>>>>>>>> +		DRM_DEBUG("MOCS: Table set in Context\n");
>>>>>>>>>> +	} else {
>>>>>>>>>> +		DRM_DEBUG("MOCS: Table Not supported on platform\n");
>>>>>>>>>> +	}
>>>>>>>>>> +
>>>>>>>>>> +	return ret;
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>> b/drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>>>> new file mode 100644
>>>>>>>>>> index 0000000..e2780ce
>>>>>>>>>> --- /dev/null
>>>>>>>>>> +++ b/drivers/gpu/drm/i915/intel_mocs.h
>>>>>>>>>> @@ -0,0 +1,64 @@
>>>>>>>>>> +/*
>>>>>>>>>> + * Copyright (c) 2015 Intel Corporation
>>>>>>>>>> + *
>>>>>>>>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>>>>>>> a
>>>>>>>>>> + * copy of this software and associated documentation files (the
>>>>>>>> "Software"),
>>>>>>>>>> + * to deal in the Software without restriction, including without
>>>>>>>> limitation
>>>>>>>>>> + * the rights to use, copy, modify, merge, publish, distribute,
>>>>>>>> sublicense,
>>>>>>>>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>>>>>>>>> + * Software is furnished to do so, subject to the following conditions:
>>>>>>>>>> + *
>>>>>>>>>> + * The above copyright notice and this permission notice (including the
>>>>>>>> next
>>>>>>>>>> + * paragraph) shall be included in all copies or substantial portions of
>>>>>>>> the
>>>>>>>>>> + * Software.
>>>>>>>>>> + *
>>>>>>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>>>>>> EXPRESS OR
>>>>>>>>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>>>>>>> MERCHANTABILITY,
>>>>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
>>>>>>>> SHALL
>>>>>>>>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>>>>>>> OTHER
>>>>>>>>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>>>>>>> ARISING FROM,
>>>>>>>>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>>>>>>> IN THE
>>>>>>>>>> + * SOFTWARE.
>>>>>>>>>> + *
>>>>>>>>>> + * Authors:
>>>>>>>>>> + *    Peter Antoine <peter.antoine@intel.com>
>>>>>>>>>> + */
>>>>>>>>>> +
>>>>>>>>>> +#ifndef INTEL_MOCS_H
>>>>>>>>>> +#define INTEL_MOCS_H
>>>>>>>>>> +
>>>>>>>>>> +/**
>>>>>>>>>> + * DOC: Memory Objects Control State (MOCS)
>>>>>>>>>> + *
>>>>>>>>>> + * Motivation:
>>>>>>>>>> + * In previous Gens the MOCS settings was a value that was set by user
>>>>>>>> land as
>>>>>>>>>> + * part of the batch. In Gen9 this has changed to be a single table (per
>>>>>>>> ring)
>>>>>>>>>> + * that all batches now reference by index instead of programming the
>>>>>>>> MOCS
>>>>>>>>>> + * directly.
>>>>>>>>>> + *
>>>>>>>>>> + * The one wrinkle in this is that only PART of the MOCS tables are
>>>>>>>> included
>>>>>>>>>> + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 -
>>>>>>>> LNCFCMOCS32
>>>>>>>>>> + * registers). The rest are not (the settings for the other rings).
>>>>>>>>>> + *
>>>>>>>>>> + * This table needs to be set at system start-up because the way the
>>>>>>>> table
>>>>>>>>>> + * interacts with the contexts and the GmmLib interface.
>>>>>>>>>> + *
>>>>>>>>>> + *
>>>>>>>>>> + * Implementation:
>>>>>>>>>> + *
>>>>>>>>>> + * The table is programmed on a platform basis from a table that is
>>>>>>>> generated
>>>>>>>>>> + * from the one that has been agreed by the different responsible
>>>>>>>> parties. This
>>>>>>>>>> + * tables (one per supported platform) is defined in intel_mocs.c and is
>>>>>>>>>> + * programmed in the first batch after the context is loaded (with the
>>>>>>>> hardware
>>>>>>>>>> + * workarounds). This will then let the usual context handling keep the
>>>>>>>> MOCS in
>>>>>>>>>> + * step.
>>>>>>>>>> + */
>>>>>>>>>> +
>>>>>>>>>> +#include <drm/drmP.h>
>>>>>>>>>> +#include "i915_drv.h"
>>>>>>>>>> +
>>>>>>>>>> +int gen9_program_mocs(struct intel_engine_cs *ring,
>>>>>>>>>> +			struct intel_context *ctx);
>>>>>>>>>> +
>>>>>>>>>> +#endif
>>>>>>>>>> +
>>>>>>>>>> --
>>>>>>>>>> 1.9.1
>>>>>>>>>>
>>>>>>>>>> _______________________________________________
>>>>>>>>>> Intel-gfx mailing list
>>>>>>>>>> Intel-gfx@lists.freedesktop.org
>>>>>>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>>    Peter Antoine (Android Graphics Driver Software Engineer)
>>>>>>>>    ---------------------------------------------------------------------
>>>>>>>>    Intel Corporation (UK) Limited
>>>>>>>>    Registered No. 1134945 (England)
>>>>>>>>    Registered Office: Pipers Way, Swindon SN3 1RJ
>>>>>>>>    VAT No: 860 2173 47
>>>>>>>> _______________________________________________
>>>>>>>> Intel-gfx mailing list
>>>>>>>> Intel-gfx@lists.freedesktop.org
>>>>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>>     Peter Antoine (Android Graphics Driver Software Engineer)
>>>>>>>     ---------------------------------------------------------------------
>>>>>>>     Intel Corporation (UK) Limited
>>>>>>>     Registered No. 1134945 (England)
>>>>>>>     Registered Office: Pipers Way, Swindon SN3 1RJ
>>>>>>>     VAT No: 860 2173 47
>>>>>> _______________________________________________
>>>>>> Intel-gfx mailing list
>>>>>> Intel-gfx@lists.freedesktop.org
>>>>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>>>
>>>>
>>>> --
>>>>     Peter Antoine (Android Graphics Driver Software Engineer)
>>>>     ---------------------------------------------------------------------
>>>>     Intel Corporation (UK) Limited
>>>>     Registered No. 1134945 (England)
>>>>     Registered Office: Pipers Way, Swindon SN3 1RJ
>>>>     VAT No: 860 2173 47
>>>
>>
>> --
>>     Peter Antoine (Android Graphics Driver Software Engineer)
>>     ---------------------------------------------------------------------
>>     Intel Corporation (UK) Limited
>>     Registered No. 1134945 (England)
>>     Registered Office: Pipers Way, Swindon SN3 1RJ
>>     VAT No: 860 2173 47
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Daniel Vetter July 1, 2015, 3:41 p.m. UTC | #23
On Wed, Jul 01, 2015 at 08:14:30AM -0700, Jesse Barnes wrote:
> On 07/01/2015 06:53 AM, Peter Antoine wrote:
> > On Wed, 1 Jul 2015, Francisco Jerez wrote:
> > 
> >> Peter Antoine <peter.antoine@intel.com> writes:
> >>
> >>> On Tue, 30 Jun 2015, Francisco Jerez wrote:
> >>>
> >>>> Francisco Jerez <currojerez@riseup.net> writes:
> >>>>
> >>>>> Peter Antoine <peter.antoine@intel.com> writes:
> >>>>>
> >>>>>> On Mon, 29 Jun 2015, Peter Antoine wrote:
> >>>>>>
> >>>>>>> On Thu, 25 Jun 2015, Francisco Jerez wrote:
> >>>>>>>
> >>>>>>>> Peter Antoine <peter.antoine@intel.com> writes:
> >>>>>>>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE,
> >>>>>>>> L3CC=WB,
> >>>>>>>> everything else unset, I'll reply with a userspace patch making
> >>>>>>>> use of
> >>>>>>>> your change if you add such an entry.
> >>>>>> Ok. I think what you want is, same as entry two, but use the
> >>>>>> underlying
> >>>>>> pagetable settings and not specify the EDRAM settings. Please
> >>>>>> confirm in
> >>>>>> the new patchset.
> >>>>>
> >>>>> Yeah, that sounds good.
> >>>>>
> >>>>>>>>
> >>>>>>>> Another thing worth mentioning is that entries 0, 2 and 5 seem
> >>>>>>>> to do the
> >>>>>>>> same thing suspiciously, the only difference is the LRUM field
> >>>>>>>> which
> >>>>>>>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding
> >>>>>>>> correct?
> >>>>>>>>
> >>>>>>> These tables are generated via requests and then boiled down to
> >>>>>>> the above.
> >>>>>>> So some of the entries are by request. Swings and roundabouts,
> >>>>>>> can remove
> >>>>>>> the ones that look redundant but then the tuning that has been
> >>>>>>> done wont
> >>>>>>> match. I'll add the new entry at the end of the table.
> >>>>
> >>>> Are you planning to propagate the entry you just added back to the
> >>>> original table this was generated from?  What about new entries we may
> >>>> need to add in the future?  What should be the process to make sure
> >>>> that
> >>>> our table and the master table don't diverge and end up with
> >>>> conflicting
> >>>> entries we cannot remove because of ABI compatibility?  I guess there
> >>>> should be a comment on the top warning that the table is part of the
> >>>> kernel ABI and supposed to be kept in sync with your table, so other
> >>>> people don't change it unknowingly?
> >>>>
> >>>> Thanks.
> >>> I am talking to the team that handles this and see if they will add this
> >>> (so future gens this is baked in) but it is unlikely that the other
> >>> tables
> >>> will stay in step as getting in changes will cause too much grief
> >>> getting
> >>> them upstreamed and as the table is auto-generated we will not be
> >>> able to
> >>> guarantee the ordering. It will have to be manual job for anyone doing
> >>> this. It is required for other platforms for the tables to match the
> >>> userspace for performance reasons, but on Linux it will be by request if
> >>> there is a problem. We will see what happens.
> >>>
> >> I think it only makes sense for Linux to maintain compatibility with
> >> Android's tables if we agree on some straightforward process for us to
> >> allocate new entries without causing conflicts (otherwise people are
> >> likely to ignore the issue completely and let the tables diverge, as you
> >> mentioned yourself), and have some guarantee that any entries ever
> >> contributed by your team to the Linux kernel (and therefore part of our
> >> stable ABI) will never be changed or reordered in the future.
> >>
> > I think internally (and informally) that we cannot keep sync between
> > Android
> > and Linux. We need to keep compatibility with userspace and there is no
> > guarantee of ordering as these tables are generated at runtime. The tables
> > that are in Linux are a snapshot. These changes are supposed to
> > stabilise at
> > PV so they don't change in the future, but if a bug or good performance
> > enhancement occurs I can't imagine that they wont make the changes.
> 
> Wow this discussion just keeps going.  Who'd have thought such a simple
> table would cause so much trouble? :)
> 
> What you mention above is a key point: "these tables are generated at
> runtime. The tables that are in Linux are a snapshot. These changes are
> supposed to stabilise at PV so they don't change in the future, but if a
> bug or good performance enhancement occurs I can't imagine that they
> wont make the changes."
> 
> That really argues for a runtime API that allows the userland drivers to
> load in MOCS values.  I'm not sure if it's practical to make the table
> effectively part of the context (lazily applying new values if we detect
> a change vs the defaults), but that would at least let the different
> user level drivers do whatever they think is ideal...

runtime api needs an open-source user. And it sounds like mesa will be
happy for a long time with just 3 fixed entries.

I guess this mocs upstreaming went nowhere unfortunately :( Imo better to
concentrate efforts in areas where we can get somewhere (guc, preempt,
tdr, whatever).
-Daniel
Peter Antoine July 2, 2015, 9:15 a.m. UTC | #24
Francisco,

I have had a quick chat here with people and we are good to not upstream 
our version of the MOCS. We will handle the updates that we require for 
Android separately from the upstream kernel.

Thanks,
Peter.


On Wed, 1 Jul 2015, Daniel Vetter wrote:

> On Wed, Jul 01, 2015 at 08:14:30AM -0700, Jesse Barnes wrote:
>> On 07/01/2015 06:53 AM, Peter Antoine wrote:
>>> On Wed, 1 Jul 2015, Francisco Jerez wrote:
>>>
>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>
>>>>> On Tue, 30 Jun 2015, Francisco Jerez wrote:
>>>>>
>>>>>> Francisco Jerez <currojerez@riseup.net> writes:
>>>>>>
>>>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>>>
>>>>>>>> On Mon, 29 Jun 2015, Peter Antoine wrote:
>>>>>>>>
>>>>>>>>> On Thu, 25 Jun 2015, Francisco Jerez wrote:
>>>>>>>>>
>>>>>>>>>> Peter Antoine <peter.antoine@intel.com> writes:
>>>>>>>>>> Mesa will want an additional entry with TC=LLC/eLLC, LeCC=PTE,
>>>>>>>>>> L3CC=WB,
>>>>>>>>>> everything else unset, I'll reply with a userspace patch making
>>>>>>>>>> use of
>>>>>>>>>> your change if you add such an entry.
>>>>>>>> Ok. I think what you want is, same as entry two, but use the
>>>>>>>> underlying
>>>>>>>> pagetable settings and not specify the EDRAM settings. Please
>>>>>>>> confirm in
>>>>>>>> the new patchset.
>>>>>>>
>>>>>>> Yeah, that sounds good.
>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Another thing worth mentioning is that entries 0, 2 and 5 seem
>>>>>>>>>> to do the
>>>>>>>>>> same thing suspiciously, the only difference is the LRUM field
>>>>>>>>>> which
>>>>>>>>>> AFAIK doesn't have any effect for LeCC=UC.  Is my understanding
>>>>>>>>>> correct?
>>>>>>>>>>
>>>>>>>>> These tables are generated via requests and then boiled down to
>>>>>>>>> the above.
>>>>>>>>> So some of the entries are by request. Swings and roundabouts,
>>>>>>>>> can remove
>>>>>>>>> the ones that look redundant but then the tuning that has been
>>>>>>>>> done wont
>>>>>>>>> match. I'll add the new entry at the end of the table.
>>>>>>
>>>>>> Are you planning to propagate the entry you just added back to the
>>>>>> original table this was generated from?  What about new entries we may
>>>>>> need to add in the future?  What should be the process to make sure
>>>>>> that
>>>>>> our table and the master table don't diverge and end up with
>>>>>> conflicting
>>>>>> entries we cannot remove because of ABI compatibility?  I guess there
>>>>>> should be a comment on the top warning that the table is part of the
>>>>>> kernel ABI and supposed to be kept in sync with your table, so other
>>>>>> people don't change it unknowingly?
>>>>>>
>>>>>> Thanks.
>>>>> I am talking to the team that handles this and see if they will add this
>>>>> (so future gens this is baked in) but it is unlikely that the other
>>>>> tables
>>>>> will stay in step as getting in changes will cause too much grief
>>>>> getting
>>>>> them upstreamed and as the table is auto-generated we will not be
>>>>> able to
>>>>> guarantee the ordering. It will have to be manual job for anyone doing
>>>>> this. It is required for other platforms for the tables to match the
>>>>> userspace for performance reasons, but on Linux it will be by request if
>>>>> there is a problem. We will see what happens.
>>>>>
>>>> I think it only makes sense for Linux to maintain compatibility with
>>>> Android's tables if we agree on some straightforward process for us to
>>>> allocate new entries without causing conflicts (otherwise people are
>>>> likely to ignore the issue completely and let the tables diverge, as you
>>>> mentioned yourself), and have some guarantee that any entries ever
>>>> contributed by your team to the Linux kernel (and therefore part of our
>>>> stable ABI) will never be changed or reordered in the future.
>>>>
>>> I think internally (and informally) that we cannot keep sync between
>>> Android
>>> and Linux. We need to keep compatibility with userspace and there is no
>>> guarantee of ordering as these tables are generated at runtime. The tables
>>> that are in Linux are a snapshot. These changes are supposed to
>>> stabilise at
>>> PV so they don't change in the future, but if a bug or good performance
>>> enhancement occurs I can't imagine that they wont make the changes.
>>
>> Wow this discussion just keeps going.  Who'd have thought such a simple
>> table would cause so much trouble? :)
>>
>> What you mention above is a key point: "these tables are generated at
>> runtime. The tables that are in Linux are a snapshot. These changes are
>> supposed to stabilise at PV so they don't change in the future, but if a
>> bug or good performance enhancement occurs I can't imagine that they
>> wont make the changes."
>>
>> That really argues for a runtime API that allows the userland drivers to
>> load in MOCS values.  I'm not sure if it's practical to make the table
>> effectively part of the context (lazily applying new values if we detect
>> a change vs the defaults), but that would at least let the different
>> user level drivers do whatever they think is ideal...
>
> runtime api needs an open-source user. And it sounds like mesa will be
> happy for a long time with just 3 fixed entries.
>
> I guess this mocs upstreaming went nowhere unfortunately :( Imo better to
> concentrate efforts in areas where we can get somewhere (guc, preempt,
> tdr, whatever).
> -Daniel
>

--
    Peter Antoine (Android Graphics Driver Software Engineer)
    ---------------------------------------------------------------------
    Intel Corporation (UK) Limited
    Registered No. 1134945 (England)
    Registered Office: Pipers Way, Swindon SN3 1RJ
    VAT No: 860 2173 47

Patch
diff mbox

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index b7ddf48..c781e19 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -35,6 +35,7 @@  i915-y += i915_cmd_parser.o \
 	  i915_irq.o \
 	  i915_trace_points.o \
 	  intel_lrc.o \
+	  intel_mocs.o \
 	  intel_ringbuffer.o \
 	  intel_uncore.o
 
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 7213224..3a435b5 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7829,4 +7829,13 @@  enum skl_disp_power_wells {
 #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
 #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
 
+/* MOCS (Memory Object Control State) registers */
+#define GEN9_LNCFCMOCS0		(0xB020)	/* L3 Cache Control base */
+
+#define GEN9_GFX_MOCS_0		(0xc800)	/* Graphics MOCS base register*/
+#define GEN9_MFX0_MOCS_0	(0xc900)	/* Media 0 MOCS base register*/
+#define GEN9_MFX1_MOCS_0	(0xcA00)	/* Media 1 MOCS base register*/
+#define GEN9_VEBOX_MOCS_0	(0xcB00)	/* Video MOCS base register*/
+#define GEN9_BLT_MOCS_0		(0xcc00)	/* Blitter MOCS base register*/
+
 #endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 9f5485d..73b919d 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -135,6 +135,7 @@ 
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
+#include "intel_mocs.h"
 
 #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE)
 #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
@@ -796,7 +797,7 @@  static int logical_ring_prepare(struct intel_ringbuffer *ringbuf,
  *
  * Return: non-zero if the ringbuffer is not ready to be written to.
  */
-static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
 				    struct intel_context *ctx, int num_dwords)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
@@ -1379,6 +1380,13 @@  static int gen8_init_rcs_context(struct intel_engine_cs *ring,
 	if (ret)
 		return ret;
 
+	/*
+	 * Failing to program the MOCS is non-fatal.The system will not
+	 * run at peak performance. So generate a warning and carry on.
+	 */
+	if (gen9_program_mocs(ring, ctx) != 0)
+		DRM_ERROR("MOCS failed to program: expect performance issues.");
+
 	return intel_lr_context_render_state_init(ring, ctx);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 04d3a6d..dbbd6af 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -44,6 +44,10 @@  int intel_logical_rings_init(struct drm_device *dev);
 
 int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
 				  struct intel_context *ctx);
+
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
+				    struct intel_context *ctx, int num_dwords);
+
 /**
  * intel_logical_ring_advance() - advance the ringbuffer tail
  * @ringbuf: Ringbuffer to advance.
diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c
new file mode 100644
index 0000000..7c09e67
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_mocs.c
@@ -0,0 +1,373 @@ 
+/*
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions: *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Peter Antoine <peter.antoine@intel.com>
+ */
+
+#include "intel_mocs.h"
+#include "intel_lrc.h"
+#include "intel_ringbuffer.h"
+
+/* structures required */
+struct drm_i915_mocs_entry {
+	u32	control_value;
+	u16	l3cc_value;
+};
+
+struct drm_i915_mocs_table {
+	u32					size;
+	const struct drm_i915_mocs_entry	*table;
+};
+
+/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
+#define	MOCS_CACHEABILITY(value)	(value << 0)
+#define	MOCS_TGT_CACHE(value)		(value << 2)
+#define	MOCS_LRUM(value)		(value << 4)
+#define	MOCS_AOM(value)			(value << 6)
+#define	MOCS_LECC_ESC(value)		(value << 7)
+#define	MOCS_LECC_SCC(value)		(value << 8)
+#define	MOC_PFM(value)			(value << 11)
+#define	MOCS_SCF(value)			(value << 14)
+
+/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */
+#define	MOCS_ESC(value)			(value << 0)
+#define	MOCS_SCC(value)			(value << 1)
+#define	MOCS_L3_CACHEABILITY(value)	(value << 4)
+
+/* Helper defines */
+#define GEN9_NUM_MOCS_RINGS	(5)	/* Number of mocs engines to program */
+#define GEN9_NUM_MOCS_ENTRIES	(63)	/* 63 out of 64 - 64 is rsvrd */
+
+/* EDRAM Caching options */
+#define EDRAM_PAGETABLE		(0)
+#define EDRAM_UC		(1)
+#define EDRAM_RESERVED		(2)
+#define EDRAM_WB		(3)
+
+/* L3 Caching options */
+#define L3_DIRECT		(0)
+#define L3_UC			(1)
+#define L3_RESERVED		(2)
+#define L3_WB			(3)
+
+/* target cache */
+#define ELLC			(0)
+#define LLC			(1)
+#define LLC_ELLC		(2)
+
+/*
+ * MOCS tables
+ *
+ * These are the MOCS tables that are programmed across all the rings.
+ * The control value is programmed to all the rings that support the
+ * MOCS registers. While the l3cc_values are only programmed to the
+ * LNCFCMOCS0 - LNCFCMOCS32 registers.
+ *
+ * NOTE: These tables MUST start with being uncached and the length MUST be
+ *       less than 63 as the last two registers are reserved by the hardware.
+ */
+static struct drm_i915_mocs_entry skylake_mocs_table[] = {
+	 /* {0x00000009, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
+		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+	 /* {0x0000003b, 0x0030} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
+		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
+	 /* {0x00000039, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
+		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+	 /* {0x00000017, 0x0030} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
+		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
+	 /* {0x00000017, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
+		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+	 /* {0x00000019, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
+		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+	 /* {0x00000037, 0x0030} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
+		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
+	 /* {0x00000037, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
+		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+	 /* {0x0000003b, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
+		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+};
+
+static struct drm_i915_mocs_entry broxton_mocs_table[] = {
+	 /* {0x00000001, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(ELLC) |
+		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+	 /* {0x00000005, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
+		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+	 /* {0x00000005, 0x0030} */
+	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC) |
+		MOCS_LRUM(0) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
+	 /* {0x00000017, 0x0030} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
+		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
+	 /* {0x00000017, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
+		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+	 /* {0x00000019, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_UC) | MOCS_TGT_CACHE(LLC_ELLC) |
+		MOCS_LRUM(1) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+	 /* {0x00000037, 0x0030} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
+		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_WB))},
+	 /* {0x00000037, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC) |
+		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+	 /* {0x0000003b, 0x0010} */
+	{(MOCS_CACHEABILITY(EDRAM_WB) | MOCS_TGT_CACHE(LLC_ELLC) |
+		MOCS_LRUM(3) | MOCS_AOM(0) | MOCS_LECC_ESC(0) | MOCS_SCC(0) |
+		MOC_PFM(0) | MOCS_SCF(0)),
+		(MOCS_ESC(0) | MOCS_SCC(0) | MOCS_L3_CACHEABILITY(L3_UC))},
+};
+
+/**
+ * get_mocs_settings
+ *
+ * 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
+ * to be programmed and if they need to be programmed.
+ *
+ * If the return values is false then the registers do not need programming.
+ */
+static bool get_mocs_settings(struct drm_device *dev,
+			      struct drm_i915_mocs_table *table) {
+	bool	result = false;
+
+	if (IS_SKYLAKE(dev)) {
+		table->size  = ARRAY_SIZE(skylake_mocs_table);
+		table->table = skylake_mocs_table;
+		result = true;
+	} else if (IS_BROXTON(dev)) {
+		table->size  = ARRAY_SIZE(broxton_mocs_table);
+		table->table = broxton_mocs_table;
+		result = true;
+	} else {
+		/* Platform that should have a MOCS table does not */
+		WARN_ON(INTEL_INFO(dev)->gen >= 9);
+	}
+
+	return result;
+}
+
+/**
+ * emit_mocs_control_table() - emit the mocs control table
+ * @ringbuf:	DRM device.
+ * @table:	The values to program into the control regs.
+ * @reg_base:	The base for the Engine that needs to be programmed.
+ *
+ * This function simply emits a MI_LOAD_REGISTER_IMM command for the
+ * given table starting at the given address.
+ *
+ * Return: Nothing.
+ */
+static void emit_mocs_control_table(struct intel_ringbuffer *ringbuf,
+				    struct drm_i915_mocs_table *table,
+				    u32 reg_base)
+{
+	unsigned int index;
+
+	intel_logical_ring_emit(ringbuf,
+			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
+
+	for (index = 0; index < table->size; index++) {
+		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
+		intel_logical_ring_emit(ringbuf,
+					table->table[index].control_value);
+	}
+
+	/*
+	 * Ok, now set the unused entries to uncached. These entries are
+	 * officially undefined and no contact is given for the contents and
+	 * settings is given for these entries.
+	 *
+	 * Entry 0 in the table is uncached - so we are just written that
+	 * value to all the used entries.
+	 */
+	for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
+		intel_logical_ring_emit(ringbuf, reg_base + (index * 4));
+		intel_logical_ring_emit(ringbuf, table->table[0].control_value);
+	}
+
+	intel_logical_ring_emit(ringbuf, MI_NOOP);
+}
+
+/**
+ * emit_mocs_l3cc_table() - emit the mocs control table
+ * @ringbuf:	DRM device.
+ * @table:	The values to program into the control regs.
+ *
+ * This function simply emits a MI_LOAD_REGISTER_IMM command for the
+ * given table starting at the given address. This register set is  programmed
+ * in pairs.
+ *
+ * Return: Nothing.
+ */
+static void emit_mocs_l3cc_table(struct intel_ringbuffer *ringbuf,
+			 struct drm_i915_mocs_table *table) {
+	unsigned int count;
+	unsigned int i;
+	u32 value;
+	u32 filler = (table->table[0].l3cc_value & 0xffff) |
+			((table->table[0].l3cc_value & 0xffff) << 16);
+
+	intel_logical_ring_emit(ringbuf,
+			MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
+
+	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);
+
+		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
+		intel_logical_ring_emit(ringbuf, 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) - 1; i++) {
+		intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + (i * 4));
+		intel_logical_ring_emit(ringbuf, value);
+
+		value = filler;
+	}
+
+	intel_logical_ring_emit(ringbuf, MI_NOOP);
+}
+
+/*
+ * gen9_program_mocs() - program the MOCS register.
+ *
+ * ring:	The ring that the programming batch will be run in.
+ * ctx:		The intel_context to be used.
+ *
+ * This function will emit a batch buffer with the values required for
+ * programming the MOCS register values for all the currently supported
+ * rings.
+ *
+ * These registers are partially stored in the RCS context, so they are
+ * emitted at the same time so that when a context is created these registers
+ * are set up. These registers have to be emitted into the start of the
+ * context as setting the ELSP will re-init some of these registers back
+ * to the hw values.
+ *
+ * Return: 0 on success, otherwise the error status.
+ */
+int gen9_program_mocs(struct intel_engine_cs *ring,
+			  struct intel_context *ctx)
+{
+	int ret = 0;
+
+	struct drm_i915_mocs_table t;
+	struct drm_device *dev = ring->dev;
+	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+
+	if (get_mocs_settings(dev, &t)) {
+		u32 table_size;
+
+		/*
+		 * OK. For each supported ring:
+		 *  number of mocs entries * 2 dwords for each control_value
+		 *  plus number of mocs entries /2 dwords for l3cc values.
+		 *
+		 *  Plus 1 for the load command and 1 for the NOOP per ring
+		 *  and the l3cc programming.
+		 */
+		table_size = GEN9_NUM_MOCS_RINGS *
+				((2 * GEN9_NUM_MOCS_ENTRIES) + 2) +
+				GEN9_NUM_MOCS_ENTRIES + 2;
+		ret = intel_logical_ring_begin(ringbuf, ctx, table_size);
+		if (ret) {
+			DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret);
+			return ret;
+		}
+
+		/* program the control registers */
+		emit_mocs_control_table(ringbuf, &t, GEN9_GFX_MOCS_0);
+		emit_mocs_control_table(ringbuf, &t, GEN9_MFX0_MOCS_0);
+		emit_mocs_control_table(ringbuf, &t, GEN9_MFX1_MOCS_0);
+		emit_mocs_control_table(ringbuf, &t, GEN9_VEBOX_MOCS_0);
+		emit_mocs_control_table(ringbuf, &t, GEN9_BLT_MOCS_0);
+
+		/* now program the l3cc registers */
+		emit_mocs_l3cc_table(ringbuf, &t);
+
+		intel_logical_ring_advance(ringbuf);
+
+		DRM_DEBUG("MOCS: Table set in Context\n");
+	} else {
+		DRM_DEBUG("MOCS: Table Not supported on platform\n");
+	}
+
+	return ret;
+}
+
diff --git a/drivers/gpu/drm/i915/intel_mocs.h b/drivers/gpu/drm/i915/intel_mocs.h
new file mode 100644
index 0000000..e2780ce
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_mocs.h
@@ -0,0 +1,64 @@ 
+/*
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Peter Antoine <peter.antoine@intel.com>
+ */
+
+#ifndef INTEL_MOCS_H
+#define INTEL_MOCS_H
+
+/**
+ * DOC: Memory Objects Control State (MOCS)
+ *
+ * Motivation:
+ * In previous Gens the MOCS settings was a value that was set by user land as
+ * part of the batch. In Gen9 this has changed to be a single table (per ring)
+ * that all batches now reference by index instead of programming the MOCS
+ * directly.
+ *
+ * The one wrinkle in this is that only PART of the MOCS tables are included
+ * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - LNCFCMOCS32
+ * registers). The rest are not (the settings for the other rings).
+ *
+ * This table needs to be set at system start-up because the way the table
+ * interacts with the contexts and the GmmLib interface.
+ *
+ *
+ * Implementation:
+ *
+ * The table is programmed on a platform basis from a table that is generated
+ * from the one that has been agreed by the different responsible parties. This
+ * tables (one per supported platform) is defined in intel_mocs.c and is
+ * programmed in the first batch after the context is loaded (with the hardware
+ * workarounds). This will then let the usual context handling keep the MOCS in
+ * step.
+ */
+
+#include <drm/drmP.h>
+#include "i915_drv.h"
+
+int gen9_program_mocs(struct intel_engine_cs *ring,
+			struct intel_context *ctx);
+
+#endif
+