All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rodrigo Vivi <rodrigo.vivi@intel.com>
To: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
Cc: <intel-xe@lists.freedesktop.org>,
	Lucas De Marchi <lucas.demarchi@intel.com>
Subject: Re: [PATCH v12 3/4] drm/xe/pmu: Add GT C6 events
Date: Thu, 9 Jan 2025 18:24:09 -0500	[thread overview]
Message-ID: <Z4BamWHv320vP5FW@intel.com> (raw)
In-Reply-To: <20250108175923.2160130-4-vinay.belgaumkar@intel.com>

On Wed, Jan 08, 2025 at 09:59:22AM -0800, Vinay Belgaumkar wrote:
> Provide a PMU interface for GT C6 residency counters. The implementation
> is ported over from the i915 PMU code. Residency is provided in units of
> ms(like sysfs entry in - /sys/class/drm/card0/device/tile0/gt0/gtidle).
> 
> Sample usage and output-
> 
> $ perf list | grep c6
> 
>   xe_0000_00_02.0/gt-c6-residency/                 [Kernel PMU event]
> 
> $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/format/
>   event  gt_id
> $ cat /sys/bus/event_source/devices/xe_0000_00_02.0/format/*
>   config:0-11
>   config:60-63
> 
> $ perf stat -e xe_0000_00_02.0/gt-c6-residency,gt_id=0/ -I1000
> 
> $           time     counts unit events
>      1.001183454       1001 ms   xe_0000_00_02.0/gt-c6-residency,gt_id=0/
>      2.004434757       1002 ms   xe_0000_00_02.0/gt-c6-residency,gt_id=0/
> 
> v2: Checkpatch fix, move timer code to next patch
> v3: Fix kunit issue
> v4: Fix for locking issue, fix review comments (Riana)
> v5: Add xe_pmu_disable() function to reset enable_count
> v6: Change rc6 to c6 (Riana)
> v7: Fix another comment format
> v8: Replace RC6 with C6 (Riana)
> v9: Define sampling freq in next patch
> v10: Use raw_spin_lock* instead of spin_lock* (Lucas)
> v11: Use gt-c6 to avoid confusion with CPU (Rodrigo). Use

I still see some 'c6' references below.. in code and in function names.
we should be consistent and entirely avoid that in favor of the gt-c6.

> xe_pm_runtime_suspended() and format attr def cleanup (Riana)
> 
> Cc: Lucas De Marchi <lucas.demarchi@intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> #v5
> Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
> ---
>  drivers/gpu/drm/xe/xe_gt.c        |   3 +
>  drivers/gpu/drm/xe/xe_pmu.c       | 236 +++++++++++++++++++++++++++---
>  drivers/gpu/drm/xe/xe_pmu.h       |   2 +
>  drivers/gpu/drm/xe/xe_pmu_types.h |  53 ++++++-
>  4 files changed, 272 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c
> index 41ab7fbebc19..64e60bcf131a 100644
> --- a/drivers/gpu/drm/xe/xe_gt.c
> +++ b/drivers/gpu/drm/xe/xe_gt.c
> @@ -47,6 +47,7 @@
>  #include "xe_mmio.h"
>  #include "xe_pat.h"
>  #include "xe_pm.h"
> +#include "xe_pmu.h"
>  #include "xe_mocs.h"
>  #include "xe_reg_sr.h"
>  #include "xe_ring_ops.h"
> @@ -875,6 +876,8 @@ int xe_gt_suspend(struct xe_gt *gt)
>  
>  	xe_gt_idle_disable_pg(gt);
>  
> +	xe_pmu_suspend(gt);
> +
>  	xe_gt_disable_host_l2_vram(gt);
>  
>  	xe_force_wake_put(gt_to_fw(gt), fw_ref);
> diff --git a/drivers/gpu/drm/xe/xe_pmu.c b/drivers/gpu/drm/xe/xe_pmu.c
> index 5ff830e66ed3..3afb2b1b533b 100644
> --- a/drivers/gpu/drm/xe/xe_pmu.c
> +++ b/drivers/gpu/drm/xe/xe_pmu.c
> @@ -11,8 +11,11 @@
>  #include "xe_device.h"
>  #include "xe_force_wake.h"
>  #include "xe_gt_clock.h"
> +#include "xe_gt_idle.h"
> +#include "xe_guc_pc.h"
>  #include "xe_mmio.h"
>  #include "xe_macros.h"
> +#include "xe_module.h"
>  #include "xe_pm.h"
>  #include "xe_pmu.h"
>  
> @@ -41,13 +44,34 @@ static unsigned int xe_pmu_target_cpu = -1;
>   * The format directory has info regarding the configs that can be used.
>   *
>   * The standard perf tool can be used to grep for a certain event as well-
> - * $ perf list | grep c6
> + * $ perf list | grep gt-c6
>   *
>   * To list a specific event for a GT at regular intervals-
>   * $ perf stat -e <event_name,xe_gt_id=> -I <interval>
>   *
> + * For C6, following command will give GT residency per second-
> + * $ perf stat -e xe_0000_00_02.0/c6-residency,gt_id=0/ -I 1000
> + *            time             counts unit events
> + *     1.001183454               1001 ms   xe_0000_00_02.0/gt-c6-residency,gt_id=0/
> + *     2.004434757               1002 ms   xe_0000_00_02.0/gt-c6-residency,gt_id=0/
> + *     3.005854217               1000 ms   xe_0000_00_02.0/gt-c6-residency,gt_id=0/
> + *
> + * To verify this matches with sysfs values of c6, you can run following command-
> + * $ for i in {1..10} ; do cat /sys/class/drm/card0/device/tile0/gt0/gtidle/idle_residency_ms;
> + *   sleep 1; done
> + *      2348877
> + *      2349901
> + *      2350917
> + *      2352945
> + *
> + * Each value is roughly a 1000ms increment here as well. This is expected GT residency when idle.
>   */
>  
> +static struct xe_pmu *event_to_pmu(struct perf_event *event)
> +{
> +	return container_of(event->pmu, struct xe_pmu, base);
> +}
> +
>  static unsigned int config_gt_id(const u64 config)
>  {
>  	return config >> __XE_PMU_GT_SHIFT;
> @@ -58,6 +82,35 @@ static u64 config_counter(const u64 config)
>  	return config & ~(~0ULL << __XE_PMU_GT_SHIFT);
>  }
>  
> +static unsigned int pm_bit(const u64 config)
> +{
> +	unsigned int val;
> +
> +	switch (config_counter(config)) {
> +	case XE_PMU_C6_RESIDENCY:
> +		val = __XE_PMU_C6_RESIDENCY_ENABLED;
> +		break;
> +	default:
> +		/*
> +		 * Events that do not require sampling, or tracking state
> +		 * transitions between enabled and disabled can be ignored.
> +		 */
> +		return -1;
> +	}
> +
> +	return config_gt_id(config) * __XE_PMU_TRACKED_EVENT_COUNT + val;
> +}
> +
> +static unsigned int config_bit(const u64 config)
> +{
> +	return pm_bit(config);
> +}
> +
> +static unsigned int event_bit(struct perf_event *event)
> +{
> +	return config_bit(event->attr.config);
> +}
> +
>  static void xe_pmu_event_destroy(struct perf_event *event)
>  {
>  	struct xe_device *xe =
> @@ -77,6 +130,10 @@ config_status(struct xe_device *xe, u64 config)
>  		return -ENOENT;
>  
>  	switch (config_counter(config)) {
> +	case XE_PMU_C6_RESIDENCY:
> +		if (xe->info.skip_guc_pc)
> +			return -ENODEV;
> +		break;
>  	default:
>  		return -ENOENT;
>  	}
> @@ -125,6 +182,57 @@ static int xe_pmu_event_init(struct perf_event *event)
>  	return 0;
>  }
>  
> +static inline s64 ktime_since_raw(const ktime_t kt)
> +{
> +	return ktime_to_ms(ktime_sub(ktime_get_raw(), kt));
> +}
> +
> +static u64 read_sample(struct xe_pmu *pmu, unsigned int gt_id, int sample)
> +{
> +	return pmu->event_sample[gt_id][sample].cur;
> +}
> +
> +static void
> +store_sample(struct xe_pmu *pmu, unsigned int gt_id, int sample, u64 val)
> +{
> +	pmu->event_sample[gt_id][sample].cur = val;
> +}
> +
> +static u64 get_c6(struct xe_gt *gt)
> +{
> +	struct xe_device *xe = gt_to_xe(gt);
> +	const unsigned int gt_id = gt->info.id;
> +	struct xe_pmu *pmu = &xe->pmu;
> +	unsigned long flags;
> +	u64 val;
> +
> +	raw_spin_lock_irqsave(&pmu->lock, flags);
> +
> +	if (!xe_pm_runtime_suspended(xe)) {
> +		val = xe_gt_idle_residency_msec(&gt->gtidle);
> +		store_sample(pmu, gt_id, __XE_SAMPLE_C6, val);
> +	} else {
> +		/*
> +		 * We think we are runtime suspended.
> +		 *
> +		 * Report the delta from when the device was suspended to now,
> +		 * on top of the last known real value, as the approximated C6
> +		 * counter value.
> +		 */
> +		val = ktime_since_raw(pmu->sleep_last[gt_id]);
> +		val += read_sample(pmu, gt_id, __XE_SAMPLE_C6);
> +	}
> +
> +	if (val < read_sample(pmu, gt_id, __XE_SAMPLE_C6_LAST_REPORTED))
> +		val = read_sample(pmu, gt_id, __XE_SAMPLE_C6_LAST_REPORTED);
> +	else
> +		store_sample(pmu, gt_id, __XE_SAMPLE_C6_LAST_REPORTED, val);
> +
> +	raw_spin_unlock_irqrestore(&pmu->lock, flags);
> +
> +	return val;
> +}
> +
>  static u64 __xe_pmu_event_read(struct perf_event *event)
>  {
>  	struct xe_device *xe =
> @@ -135,6 +243,9 @@ static u64 __xe_pmu_event_read(struct perf_event *event)
>  	u64 val = 0;
>  
>  	switch (config_counter(config)) {
> +	case XE_PMU_C6_RESIDENCY:
> +		val = get_c6(gt);
> +		break;
>  	default:
>  		drm_warn(&gt->tile->xe->drm, "unknown pmu event\n");
>  	}
> @@ -165,6 +276,28 @@ static void xe_pmu_event_read(struct perf_event *event)
>  
>  static void xe_pmu_enable(struct perf_event *event)
>  {
> +	struct xe_pmu *pmu = event_to_pmu(event);
> +	const unsigned int bit = event_bit(event);
> +	unsigned long flags;
> +
> +	if (bit == -1)
> +		goto update;
> +
> +	raw_spin_lock_irqsave(&pmu->lock, flags);
> +
> +	/*
> +	 * Update the bitmask of enabled events and increment
> +	 * the event reference counter.
> +	 */
> +	BUILD_BUG_ON(ARRAY_SIZE(pmu->enable_count) != XE_PMU_MASK_BITS);
> +	XE_WARN_ON(bit >= ARRAY_SIZE(pmu->enable_count));
> +	XE_WARN_ON(pmu->enable_count[bit] == ~0);
> +
> +	pmu->enable |= BIT(bit);
> +	pmu->enable_count[bit]++;
> +
> +	raw_spin_unlock_irqrestore(&pmu->lock, flags);
> +update:
>  	/*
>  	 * Store the current counter value so we can report the correct delta
>  	 * for all listeners. Even when the event was already enabled and has
> @@ -173,6 +306,31 @@ static void xe_pmu_enable(struct perf_event *event)
>  	local64_set(&event->hw.prev_count, __xe_pmu_event_read(event));
>  }
>  
> +static void xe_pmu_disable(struct perf_event *event)
> +{
> +	struct xe_device *xe =
> +		container_of(event->pmu, typeof(*xe), pmu.base);
> +	struct xe_pmu *pmu = &xe->pmu;
> +	const unsigned int bit = event_bit(event);
> +	unsigned long flags;
> +
> +	if (bit == -1)
> +		return;
> +
> +	raw_spin_lock_irqsave(&pmu->lock, flags);
> +
> +	XE_WARN_ON(bit >= ARRAY_SIZE(pmu->enable_count));
> +	XE_WARN_ON(pmu->enable_count[bit] == 0);
> +	/*
> +	 * Decrement the reference count and clear the enabled
> +	 * bitmask when the last listener on an event goes away.
> +	 */
> +	if (--pmu->enable_count[bit] == 0)
> +		pmu->enable &= ~BIT(bit);
> +
> +	raw_spin_unlock_irqrestore(&pmu->lock, flags);
> +}
> +
>  static void xe_pmu_event_start(struct perf_event *event, int flags)
>  {
>  	struct xe_device *xe =
> @@ -192,9 +350,11 @@ static void xe_pmu_event_stop(struct perf_event *event, int flags)
>  		container_of(event->pmu, typeof(*xe), pmu.base);
>  	struct xe_pmu *pmu = &xe->pmu;
>  
> -	if (pmu->registered)
> +	if (pmu->registered) {
>  		if (flags & PERF_EF_UPDATE)
>  			xe_pmu_event_read(event);
> +		xe_pmu_disable(event);
> +	}
>  
>  	event->hw.state = PERF_HES_STOPPED;
>  }
> @@ -229,24 +389,12 @@ struct xe_str_attribute {
>  	const char *str;
>  };
>  
> -static ssize_t xe_pmu_format_show(struct device *dev,
> -				  struct device_attribute *attr, char *buf)
> -{
> -	struct xe_str_attribute *eattr;
> -
> -	eattr = container_of(attr, struct xe_str_attribute, attr);
> -	return sprintf(buf, "%s\n", eattr->str);
> -}
> -
> -#define XE_PMU_FORMAT_ATTR(_name, _config) \
> -	(&((struct xe_str_attribute[]) { \
> -		{ .attr = __ATTR(_name, 0444, xe_pmu_format_show, NULL), \
> -		.str = _config, } \
> -	})[0].attr.attr)
> +PMU_FORMAT_ATTR(event, "config:0-11");
> +PMU_FORMAT_ATTR(gt_id, "config:60-63");
>  
>  static struct attribute *xe_pmu_format_attrs[] = {
> -	XE_PMU_FORMAT_ATTR(event_id, "config:0-20"),
> -	XE_PMU_FORMAT_ATTR(gt_id, "config:60-63"),
> +	&format_attr_event.attr,
> +	&format_attr_gt_id.attr,
>  	NULL,
>  };
>  
> @@ -327,6 +475,7 @@ create_event_attributes(struct xe_pmu *pmu)
>  		const char *name;
>  		const char *unit;
>  	} events[] = {
> +		__event(0, "gt-c6-residency", "ms"),
>  	};
>  
>  	struct perf_pmu_events_attr *pmu_attr = NULL, *pmu_iter;
> @@ -337,7 +486,7 @@ create_event_attributes(struct xe_pmu *pmu)
>  
>  	/* Count how many counters we will be exposing. */
>  	for (i = 0; i < ARRAY_SIZE(events); i++) {
> -		u64 config = __XE_PMU_PM(events[i].counter);
> +		u64 config = __XE_PMU_EVENT(events[i].counter);
>  
>  		if (!config_status(xe, config))
>  			count++;
> @@ -362,7 +511,7 @@ create_event_attributes(struct xe_pmu *pmu)
>  	attr_iter = attr;
>  
>  	for (i = 0; i < ARRAY_SIZE(events); i++) {
> -		u64 config = __XE_PMU_PM(events[i].counter);
> +		u64 config = __XE_PMU_EVENT(events[i].counter);
>  		char *str;
>  
>  		if (config_status(xe, config))
> @@ -508,6 +657,33 @@ static void xe_pmu_unregister_cpuhp_state(struct xe_pmu *pmu)
>  	cpuhp_state_remove_instance(cpuhp_state, &pmu->cpuhp.node);
>  }
>  
> +static void store_c6_residency(struct xe_gt *gt)
> +{
> +	struct xe_device *xe = gt_to_xe(gt);
> +	struct xe_pmu *pmu = &xe->pmu;
> +
> +	store_sample(pmu, gt->info.id, __XE_SAMPLE_C6,
> +		     xe_gt_idle_residency_msec(&gt->gtidle));
> +	pmu->sleep_last[gt->info.id] = ktime_get_raw();
> +}
> +
> +/**
> + * xe_pmu_suspend() - Save residency count before suspend
> + * @gt: GT object
> + */
> +void xe_pmu_suspend(struct xe_gt *gt)
> +{
> +	struct xe_device *xe = gt_to_xe(gt);
> +	struct xe_pmu *pmu = &xe->pmu;
> +
> +	if (!pmu->base.event_init)
> +		return;
> +
> +	raw_spin_lock_irq(&pmu->lock);
> +	store_c6_residency(gt);
> +	raw_spin_unlock_irq(&pmu->lock);
> +}
> +
>  /**
>   * xe_pmu_unregister() - Remove/cleanup PMU registration
>   * @arg: Ptr to pmu
> @@ -533,6 +709,24 @@ void xe_pmu_unregister(void *arg)
>  	free_event_attributes(pmu);
>  }
>  
> +static void init_c6(struct xe_pmu *pmu)
> +{
> +	struct xe_device *xe = container_of(pmu, typeof(*xe), pmu);
> +	struct xe_gt *gt;
> +	unsigned int j;
> +
> +	for_each_gt(gt, xe, j) {
> +		xe_pm_runtime_get(xe);
> +		u64 val = xe_gt_idle_residency_msec(&gt->gtidle);
> +
> +		store_sample(pmu, j, __XE_SAMPLE_C6, val);
> +		store_sample(pmu, j, __XE_SAMPLE_C6_LAST_REPORTED,
> +			     val);
> +		pmu->sleep_last[j] = ktime_get_raw();
> +		xe_pm_runtime_put(xe);
> +	}
> +}
> +
>  /**
>   * xe_pmu_register() - Define basic PMU properties for Xe and add event callbacks.
>   * @pmu: the PMU object
> @@ -569,6 +763,8 @@ void xe_pmu_register(struct xe_pmu *pmu)
>  	if (!pmu->events_attr_group.attrs)
>  		goto err_name;
>  
> +	init_c6(pmu);
> +
>  	pmu->base.attr_groups = kmemdup(attr_groups, sizeof(attr_groups),
>  					GFP_KERNEL);
>  	if (!pmu->base.attr_groups)
> diff --git a/drivers/gpu/drm/xe/xe_pmu.h b/drivers/gpu/drm/xe/xe_pmu.h
> index d3d91d00e50e..263665f814f0 100644
> --- a/drivers/gpu/drm/xe/xe_pmu.h
> +++ b/drivers/gpu/drm/xe/xe_pmu.h
> @@ -15,11 +15,13 @@ int xe_pmu_init(void);
>  void xe_pmu_exit(void);
>  void xe_pmu_register(struct xe_pmu *pmu);
>  void xe_pmu_unregister(void *arg);
> +void xe_pmu_suspend(struct xe_gt *gt);
>  #else
>  static inline int xe_pmu_init(void) { return 0; }
>  static inline void xe_pmu_exit(void) {}
>  static inline void xe_pmu_register(struct xe_pmu *pmu) {}
>  static inline void xe_pmu_unregister(void *arg) {}
> +static inline void xe_pmu_suspend(struct xe_gt *gt) {}
>  #endif
>  
>  #endif
> diff --git a/drivers/gpu/drm/xe/xe_pmu_types.h b/drivers/gpu/drm/xe/xe_pmu_types.h
> index 29a2009f4d5e..b97ba536d3ee 100644
> --- a/drivers/gpu/drm/xe/xe_pmu_types.h
> +++ b/drivers/gpu/drm/xe/xe_pmu_types.h
> @@ -10,6 +10,8 @@
>  #include <linux/spinlock_types.h>
>  
>  enum {
> +	__XE_SAMPLE_C6,
> +	__XE_SAMPLE_C6_LAST_REPORTED,
>  	__XE_NUM_PMU_SAMPLERS
>  };
>  
> @@ -20,10 +22,30 @@ enum {
>   */
>  #define __XE_PMU_GT_SHIFT (60)
>  
> -#define ___XE_PMU_PM(gt, x) \
> +#define ___XE_PMU_EVENT(gt, x) \
>  	(((__u64)(x)) | ((__u64)(gt) << __XE_PMU_GT_SHIFT))
>  
> -#define __XE_PMU_PM(x) ___XE_PMU_PM(0, x)
> +#define __XE_PMU_EVENT(x) ___XE_PMU_EVENT(0, x)
> +
> +#define XE_PMU_C6_RESIDENCY		__XE_PMU_EVENT(0)
> +#define __XE_PMU_C6_RESIDENCY(gt)	___XE_PMU_EVENT(gt, 0)
> +
> +/*
> + * Non-engine events that we need to track enabled-disabled transition and
> + * current state.
> + */
> +enum xe_pmu_tracked_events {
> +	__XE_PMU_C6_RESIDENCY_ENABLED,
> +	__XE_PMU_TRACKED_EVENT_COUNT, /* count marker */
> +};
> +
> +/* Global PMU mask to track enabled events */
> +#define XE_PMU_MASK_BITS \
> +	(XE_PMU_MAX_GT * __XE_PMU_TRACKED_EVENT_COUNT)
> +
> +struct xe_pmu_sample {
> +	u64 cur;
> +};
>  
>  /**
>   * struct xe_pmu - PMU related data per Xe device
> @@ -73,6 +95,33 @@ struct xe_pmu {
>  	 * @pmu_attr: Memory block holding perf attributes.
>  	 */
>  	void *pmu_attr;
> +
> +	/**
> +	 * @enable: Bitmask of specific enabled events.
> +	 *
> +	 * For some events we need to track their state and do some internal
> +	 * house keeping.
> +	 */
> +	u32 enable;
> +
> +	/**
> +	 * @enable_count: Reference counter for enabled events.
> +	 *
> +	 * Array indices are mapped in the same way as bits in the @enable field
> +	 * and they are used to control sampling on/off when multiple clients
> +	 * are using the PMU API.
> +	 */
> +	unsigned int enable_count[XE_PMU_MASK_BITS];
> +	/**
> +	 * @sample: Current and previous (raw) counters for sampling events.
> +	 *
> +	 * These counters are updated from the PMU sampling timer.
> +	 */
> +	struct xe_pmu_sample event_sample[XE_PMU_MAX_GT][__XE_NUM_PMU_SAMPLERS];
> +	/**
> +	 * @sleep_last: Last time GT parked for C6 estimation.
> +	 */
> +	ktime_t sleep_last[XE_PMU_MAX_GT];
>  };
>  
>  #endif
> -- 
> 2.38.1
> 

  reply	other threads:[~2025-01-09 23:24 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-08 17:59 [PATCH v12 0/4] drm/xe/pmu: PMU interface for Xe Vinay Belgaumkar
2025-01-08 17:59 ` [PATCH v12 1/4] drm/xe/pmu: Enable PMU interface Vinay Belgaumkar
2025-01-09 23:22   ` Rodrigo Vivi
2025-01-08 17:59 ` [PATCH v12 2/4] drm/xe: Add locks in gtidle code Vinay Belgaumkar
2025-01-08 17:59 ` [PATCH v12 3/4] drm/xe/pmu: Add GT C6 events Vinay Belgaumkar
2025-01-09 23:24   ` Rodrigo Vivi [this message]
2025-01-14  3:18   ` Lucas De Marchi
2025-01-08 17:59 ` [PATCH v12 4/4] drm/xe/pmu: Add GT frequency events Vinay Belgaumkar
2025-01-08 19:38 ` ✓ CI.Patch_applied: success for drm/xe/pmu: PMU interface for Xe (rev12) Patchwork
2025-01-08 19:38 ` ✗ CI.checkpatch: warning " Patchwork
2025-01-08 19:39 ` ✓ CI.KUnit: success " Patchwork
2025-01-08 20:00 ` ✗ CI.Hooks: failure " Patchwork
2025-01-08 20:01 ` ✓ CI.checksparse: success " Patchwork
2025-01-08 20:32 ` ✓ Xe.CI.BAT: " Patchwork
2025-01-10 22:15 ` ✗ Xe.CI.Full: failure " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Z4BamWHv320vP5FW@intel.com \
    --to=rodrigo.vivi@intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=lucas.demarchi@intel.com \
    --cc=vinay.belgaumkar@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.