return 0;
 }
 
-static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
-                         struct drm_i915_gem_request *req)
+static int gen8_legacy_mm_switch(struct i915_hw_ppgtt *ppgtt,
+                                struct drm_i915_gem_request *req)
 {
        int i, ret;
 
        return 0;
 }
 
+static int gen8_48b_mm_switch(struct i915_hw_ppgtt *ppgtt,
+                             struct drm_i915_gem_request *req)
+{
+       return gen8_write_pdp(req, 0, px_dma(&ppgtt->pml4));
+}
+
 static void gen8_ppgtt_clear_pte_range(struct i915_address_space *vm,
                                       struct i915_page_directory_pointer *pdp,
                                       uint64_t start,
        ppgtt->base.unbind_vma = ppgtt_unbind_vma;
        ppgtt->base.bind_vma = ppgtt_bind_vma;
 
-       ppgtt->switch_mm = gen8_mm_switch;
-
        if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
                ret = setup_px(ppgtt->base.dev, &ppgtt->pml4);
                if (ret)
                        goto free_scratch;
 
                ppgtt->base.total = 1ULL << 48;
+               ppgtt->switch_mm = gen8_48b_mm_switch;
        } else {
                ret = __pdp_init(false, &ppgtt->pdp);
                if (ret)
                         */
                        ppgtt->base.total = to_i915(ppgtt->base.dev)->gtt.base.total;
 
+               ppgtt->switch_mm = gen8_legacy_mm_switch;
                trace_i915_page_directory_pointer_entry_alloc(&ppgtt->base,
                                                              0, 0,
                                                              GEN8_PML4E_SHIFT);
        int j;
 
        for_each_ring(ring, dev_priv, j) {
+               u32 four_level = USES_FULL_48BIT_PPGTT(dev) ? GEN8_GFX_PPGTT_48B : 0;
                I915_WRITE(RING_MODE_GEN7(ring),
-                          _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+                          _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE | four_level));
        }
 }
 
 
        reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \
 }
 
+#define ASSIGN_CTX_PML4(ppgtt, reg_state) { \
+       reg_state[CTX_PDP0_UDW + 1] = upper_32_bits(px_dma(&ppgtt->pml4)); \
+       reg_state[CTX_PDP0_LDW + 1] = lower_32_bits(px_dma(&ppgtt->pml4)); \
+}
+
 enum {
        ADVANCED_CONTEXT = 0,
-       LEGACY_CONTEXT,
+       LEGACY_32B_CONTEXT,
        ADVANCED_AD_CONTEXT,
        LEGACY_64B_CONTEXT
 };
-#define GEN8_CTX_MODE_SHIFT 3
+#define GEN8_CTX_ADDRESSING_MODE_SHIFT 3
+#define GEN8_CTX_ADDRESSING_MODE(dev)  (USES_FULL_48BIT_PPGTT(dev) ?\
+               LEGACY_64B_CONTEXT :\
+               LEGACY_32B_CONTEXT)
 enum {
        FAULT_AND_HANG = 0,
        FAULT_AND_HALT, /* Debug only */
        WARN_ON(lrca & 0xFFFFFFFF00000FFFULL);
 
        desc = GEN8_CTX_VALID;
-       desc |= LEGACY_CONTEXT << GEN8_CTX_MODE_SHIFT;
+       desc |= GEN8_CTX_ADDRESSING_MODE(dev) << GEN8_CTX_ADDRESSING_MODE_SHIFT;
        if (IS_GEN8(ctx_obj->base.dev))
                desc |= GEN8_CTX_L3LLC_COHERENT;
        desc |= GEN8_CTX_PRIVILEGE;
        reg_state[CTX_RING_TAIL+1] = rq->tail;
        reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(rb_obj);
 
-       /* True PPGTT with dynamic page allocation: update PDP registers and
-        * point the unallocated PDPs to the scratch page
-        */
-       if (ppgtt) {
+       if (ppgtt && !USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
+               /* True 32b PPGTT with dynamic page allocation: update PDP
+                * registers and point the unallocated PDPs to scratch page.
+                * PML4 is allocated during ppgtt init, so this is not needed
+                * in 48-bit mode.
+                */
                ASSIGN_CTX_PDP(ppgtt, reg_state, 3);
                ASSIGN_CTX_PDP(ppgtt, reg_state, 2);
                ASSIGN_CTX_PDP(ppgtt, reg_state, 1);
         * Ideally, we should set Force PD Restore in ctx descriptor,
         * but we can't. Force Restore would be a second option, but
         * it is unsafe in case of lite-restore (because the ctx is
-        * not idle). */
+        * not idle). PML4 is allocated during ppgtt init so this is
+        * not needed in 48-bit.*/
        if (req->ctx->ppgtt &&
            (intel_ring_flag(req->ring) & req->ctx->ppgtt->pd_dirty_rings)) {
-               ret = intel_logical_ring_emit_pdps(req);
-               if (ret)
-                       return ret;
+               if (!USES_FULL_48BIT_PPGTT(req->i915)) {
+                       ret = intel_logical_ring_emit_pdps(req);
+                       if (ret)
+                               return ret;
+               }
 
                req->ctx->ppgtt->pd_dirty_rings &= ~intel_ring_flag(req->ring);
        }
        reg_state[CTX_PDP0_UDW] = GEN8_RING_PDP_UDW(ring, 0);
        reg_state[CTX_PDP0_LDW] = GEN8_RING_PDP_LDW(ring, 0);
 
-       /* With dynamic page allocation, PDPs may not be allocated at this point,
-        * Point the unallocated PDPs to the scratch page
-        */
-       ASSIGN_CTX_PDP(ppgtt, reg_state, 3);
-       ASSIGN_CTX_PDP(ppgtt, reg_state, 2);
-       ASSIGN_CTX_PDP(ppgtt, reg_state, 1);
-       ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
+       if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
+               /* 64b PPGTT (48bit canonical)
+                * PDP0_DESCRIPTOR contains the base address to PML4 and
+                * other PDP Descriptors are ignored.
+                */
+               ASSIGN_CTX_PML4(ppgtt, reg_state);
+       } else {
+               /* 32b PPGTT
+                * PDP*_DESCRIPTOR contains the base address of space supported.
+                * With dynamic page allocation, PDPs may not be allocated at
+                * this point. Point the unallocated PDPs to the scratch page
+                */
+               ASSIGN_CTX_PDP(ppgtt, reg_state, 3);
+               ASSIGN_CTX_PDP(ppgtt, reg_state, 2);
+               ASSIGN_CTX_PDP(ppgtt, reg_state, 1);
+               ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
+       }
+
        if (ring->id == RCS) {
                reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1);
                reg_state[CTX_R_PWR_CLK_STATE] = GEN8_R_PWR_CLK_STATE;