Commit bcdfa1f7 authored by David E. Box's avatar David E. Box Committed by Hans de Goede
Browse files

platform/x86/intel/pmt: Sapphire Rapids PMT errata fix



On Sapphire Rapids, due to a hardware issue affecting the PUNIT telemetry
region, reads that are not done in QWORD quantities and alignment may
return incorrect data. Use a custom 64-bit copy for this region.

Signed-off-by: default avatarDavid E. Box <david.e.box@linux.intel.com>
Link: https://lore.kernel.org/r/20221105034228.1376677-1-david.e.box@linux.intel.com


Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent 1598bfa8
Loading
Loading
Loading
Loading
+30 −1
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
 */

#include <linux/kernel.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/pci.h>
@@ -19,6 +20,7 @@
#define PMT_XA_START		0
#define PMT_XA_MAX		INT_MAX
#define PMT_XA_LIMIT		XA_LIMIT(PMT_XA_START, PMT_XA_MAX)
#define GUID_SPR_PUNIT		0x9956f43f

bool intel_pmt_is_early_client_hw(struct device *dev)
{
@@ -33,6 +35,29 @@ bool intel_pmt_is_early_client_hw(struct device *dev)
}
EXPORT_SYMBOL_GPL(intel_pmt_is_early_client_hw);

static inline int
pmt_memcpy64_fromio(void *to, const u64 __iomem *from, size_t count)
{
	int i, remain;
	u64 *buf = to;

	if (!IS_ALIGNED((unsigned long)from, 8))
		return -EFAULT;

	for (i = 0; i < count/8; i++)
		buf[i] = readq(&from[i]);

	/* Copy any remaining bytes */
	remain = count % 8;
	if (remain) {
		u64 tmp = readq(&from[i]);

		memcpy(&buf[i], &tmp, remain);
	}

	return count;
}

/*
 * sysfs
 */
@@ -54,6 +79,10 @@ intel_pmt_read(struct file *filp, struct kobject *kobj,
	if (count > entry->size - off)
		count = entry->size - off;

	if (entry->guid == GUID_SPR_PUNIT)
		/* PUNIT on SPR only supports aligned 64-bit read */
		count = pmt_memcpy64_fromio(buf, entry->base + off, count);
	else
		memcpy_fromio(buf, entry->base + off, count);

	return count;