diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 0f2a552..7a6dcb3 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2129,6 +2129,12 @@ struct i915_oa_ops {
 	 */
 	u32 (*oa_buffer_num_reports)(struct drm_i915_private *dev_priv,
 					u32 *last_ts);
+
+	/**
+	 * @get_ctx_id: Retrieve the ctx_id associated with the (periodic) OA
+	 * report.
+	 */
+	u32 (*get_ctx_id)(struct i915_perf_stream *stream, const u8 *report);
 };
 
 /*
@@ -2613,6 +2619,7 @@ struct drm_i915_private {
 			u32 status;
 		} command_stream_buf;
 
+		u32 last_cmd_stream_ctx_id;
 		struct list_head cs_samples;
 		spinlock_t sample_lock;
 	} perf;
diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index 2841d0a..208179f 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -850,6 +850,46 @@ static u32 gen7_oa_buffer_num_reports_unlocked(
 	return aged_tail == INVALID_TAIL_PTR ? 0 : num_reports;
 }
 
+static u32 gen7_oa_buffer_get_ctx_id(struct i915_perf_stream *stream,
+				    const u8 *report)
+{
+	struct drm_i915_private *dev_priv = stream->dev_priv;
+
+	if (!stream->cs_mode)
+		WARN_ONCE(1,
+			"CTX ID can't be retrieved if command stream mode not enabled");
+
+	/*
+	 * OA reports generated in Gen7 don't have the ctx ID information.
+	 * Therefore, just rely on the ctx ID information from the last CS
+	 * sample forwarded
+	 */
+	return dev_priv->perf.last_cmd_stream_ctx_id;
+}
+
+static u32 gen8_oa_buffer_get_ctx_id(struct i915_perf_stream *stream,
+				    const u8 *report)
+{
+	struct drm_i915_private *dev_priv = stream->dev_priv;
+
+	/* The ctx ID present in the OA reports have intel_context::hw_id
+	 * present, since this is programmed into the ELSP in execlist mode.
+	 * In non-execlist mode, fall back to retrieving the ctx ID from the
+	 * last saved ctx ID from command stream mode.
+	 */
+	if (i915.enable_execlists) {
+		u32 *report32 = (void *)report;
+		u32 ctx_id = report32[2] & 0x1fffff;
+		return ctx_id;
+	} else {
+		if (!stream->cs_mode)
+		WARN_ONCE(1,
+			"CTX ID can't be retrieved if command stream mode not enabled");
+
+		return dev_priv->perf.last_cmd_stream_ctx_id;
+	}
+}
+
 /**
  * append_oa_status - Appends a status record to a userspace read() buffer.
  * @stream: An i915-perf stream opened for OA metrics
@@ -963,18 +1003,15 @@ static int append_oa_buffer_sample(struct i915_perf_stream *stream,
 				char __user *buf, size_t count,
 				size_t *offset,	const u8 *report)
 {
+	struct drm_i915_private *dev_priv =  stream->dev_priv;
 	u32 sample_flags = stream->sample_flags;
 	struct oa_sample_data data = { 0 };
 
 	if (sample_flags & SAMPLE_OA_SOURCE_INFO)
 		data.source = I915_PERF_OA_EVENT_SOURCE_PERIODIC;
 
-	/*
-	 * FIXME: append_oa_buffer_sample: read ctx ID from report and map
-	 * that to a intel_context::hw_id"
-	 */
 	if (sample_flags & SAMPLE_CTX_ID)
-		data.ctx_id = 0;
+		data.ctx_id = dev_priv->perf.oa.ops.get_ctx_id(stream, report);
 
 	if (sample_flags & SAMPLE_OA_REPORT)
 		data.report = report;
@@ -1547,8 +1584,10 @@ static int append_oa_rcs_sample(struct i915_perf_stream *stream,
 	if (sample_flags & SAMPLE_OA_SOURCE_INFO)
 		data.source = I915_PERF_OA_EVENT_SOURCE_RCS;
 
-	if (sample_flags & SAMPLE_CTX_ID)
+	if (sample_flags & SAMPLE_CTX_ID) {
 		data.ctx_id = node->ctx_id;
+		dev_priv->perf.last_cmd_stream_ctx_id = node->ctx_id;
+	}
 
 	if (sample_flags & SAMPLE_OA_REPORT)
 		data.report = report;
@@ -3794,6 +3833,7 @@ void i915_perf_init(struct drm_i915_private *dev_priv)
 		dev_priv->perf.oa.ops.read = gen7_oa_read;
 		dev_priv->perf.oa.ops.oa_buffer_num_reports =
 			gen7_oa_buffer_num_reports_unlocked;
+		dev_priv->perf.oa.ops.get_ctx_id = gen7_oa_buffer_get_ctx_id;
 
 		dev_priv->perf.oa.oa_formats = hsw_oa_formats;
 
@@ -3859,6 +3899,7 @@ void i915_perf_init(struct drm_i915_private *dev_priv)
 			dev_priv->perf.oa.ops.read = gen8_oa_read;
 			dev_priv->perf.oa.ops.oa_buffer_num_reports =
 				gen8_oa_buffer_num_reports_unlocked;
+		dev_priv->perf.oa.ops.get_ctx_id = gen8_oa_buffer_get_ctx_id;
 
 			dev_priv->perf.oa.oa_formats = gen8_plus_oa_formats;
 		}
