diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index a7c9e8c..663bc8f 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -5920,11 +5920,21 @@ enum skl_disp_power_wells {
 # define CHV_HZ_8X8_MODE_IN_1X				(1<<15)
 # define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE	(1<<3)
 
+#define GEN8_L3CNTLREG				0x7034
+#define  GEN8_L3CNTLREG_URB_ALLOC(n)		((n) << 1)
+#define  GEN8_L3CNTLREG_RO_ALLOC(n)		((n) << 11)
+#define  GEN8_L3CNTLREG_DC_ALLOC(n)		((n) << 18)
+#define  GEN8_L3CNTLREG_ALL_ALLOC(n)		((n) << 25)
+
 #define GEN9_SLICE_COMMON_ECO_CHICKEN0		0x7308
 #define  DISABLE_PIXEL_MASK_CAMMING		(1<<14)
 
 #define GEN7_L3SQCREG1				0xB010
 #define  VLV_B0_WA_L3SQCREG1_VALUE		0x00D30000
+#define  IVB_L3SQCREG1_SQGHPCI_DEFAULT		0x00730000
+#define  VLV_L3SQCREG1_SQGHPCI_DEFAULT		0x00D30000
+#define  HSW_L3SQCREG1_SQGHPCI_DEFAULT		0x00610000
+#define  GEN7_L3SQCREG1_CONV_DC_UC		(1 << 24)
 
 #define GEN8_L3SQCREG1				0xB100
 #define  BDW_WA_L3SQCREG1_DEFAULT		0x784000
@@ -5933,6 +5943,9 @@ enum skl_disp_power_wells {
 #define  GEN7_WA_FOR_GEN7_L3_CONTROL			0x3C47FF8C
 #define  GEN7_L3AGDIS				(1<<19)
 #define GEN7_L3CNTLREG2				0xB020
+#define  GEN7_L3CNTLREG2_URB_ALLOC(n)		((n) << 1)
+#define  GEN7_L3CNTLREG2_RO_ALLOC(n)		((n) << 14)
+#define  GEN7_L3CNTLREG2_DC_ALLOC(n)		((n) << 21)
 #define GEN7_L3CNTLREG3				0xB024
 
 #define GEN7_L3_CHICKEN_MODE_REGISTER		0xB030
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 9035f8c..54ca344 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -800,6 +800,86 @@ static int wa_add(struct drm_i915_private *dev_priv,
 
 #define WA_WRITE(addr, val) WA_REG(addr, 0xffffffff, val)
 
+/**
+ * init_l3_partitioning_workarounds - Add L3 partitioning set-up to the WA list.
+ *
+ * @ring - Ring to program the L3 partitioning for.
+ * @n_urb - Number of ways to allocate for the URB.
+ * @n_ro - Number of ways to allocate for read-only L3 clients.
+ * @n_dc - Number of ways to allocate for the DC read-write L3 client.
+ * @n_all - Number of ways to allocate for the common pool shared
+ *          among all L3 clients.
+ *
+ * Note that for this to work correctly the L3 cache must be
+ * completely flushed whenever the workaround list is applied to a
+ * context.
+ */
+static int init_l3_partitioning_workarounds(struct intel_engine_cs *ring,
+					    unsigned int n_urb,
+					    unsigned int n_ro,
+					    unsigned int n_dc,
+					    unsigned int n_all)
+{
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (INTEL_INFO(dev)->gen >= 8) {
+		/*
+		 * The ALL partition may not be used simultaneously
+		 * with RO and DC.
+		 */
+		BUG_ON(n_all && (n_ro || n_dc));
+
+		/* Just need to set up the L3 partitioning. */
+		WA_WRITE(GEN8_L3CNTLREG,
+			 GEN8_L3CNTLREG_URB_ALLOC(n_urb) |
+			 GEN8_L3CNTLREG_RO_ALLOC(n_ro) |
+			 GEN8_L3CNTLREG_DC_ALLOC(n_dc) |
+			 GEN8_L3CNTLREG_ALL_ALLOC(n_all));
+
+	} else if (INTEL_INFO(dev)->gen >= 7) {
+		/*
+		 * Offset applied by the hardware to the number of
+		 * ways allocated to the URB, which is also the
+		 * minimum legal URB allocation.
+		 */
+		const unsigned int n0_urb = (IS_VALLEYVIEW(dev) ? 32 : 0);
+		BUG_ON(n_urb < n0_urb);
+
+		/* The ALL partition is not supported on Gen7. */
+		BUG_ON(n_all);
+
+		/*
+		 * Init the L3SQ General and high priority credit
+		 * initialization value to the hardware defaults
+		 * (except for VLV B0 which supposedly defaults to a
+		 * value different to the one we set here), and demote
+		 * the DC to LLC if it has no ways assigned.
+		 *
+		 * WaIncreaseL3CreditsForVLVB0:vlv
+		 */
+		WA_WRITE(GEN7_L3SQCREG1,
+			 (IS_HASWELL(dev) ? HSW_L3SQCREG1_SQGHPCI_DEFAULT :
+			  IS_VALLEYVIEW(dev) ? VLV_L3SQCREG1_SQGHPCI_DEFAULT :
+			  IVB_L3SQCREG1_SQGHPCI_DEFAULT) |
+			 (n_dc ? 0 : GEN7_L3SQCREG1_CONV_DC_UC));
+
+		/* Set up the L3 partitioning. */
+		WA_WRITE(GEN7_L3CNTLREG2,
+			 GEN7_L3CNTLREG2_URB_ALLOC(n_urb - n0_urb) |
+			 GEN7_L3CNTLREG2_RO_ALLOC(n_ro) |
+			 GEN7_L3CNTLREG2_DC_ALLOC(n_dc));
+
+		WA_WRITE(GEN7_L3CNTLREG3, 0);
+
+	} else {
+		/* No L3 on pre-Gen7 hardware. */
+		BUG();
+	}
+
+	return 0;
+}
+
 static int gen8_init_workarounds(struct intel_engine_cs *ring)
 {
 	struct drm_device *dev = ring->dev;
