diff options
Diffstat (limited to 'drivers/platform/x86/intel/pmt/class.c')
| -rw-r--r-- | drivers/platform/x86/intel/pmt/class.c | 31 | 
1 files changed, 30 insertions, 1 deletions
diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c index 53d7fd2943b4..46598dcb634a 100644 --- a/drivers/platform/x86/intel/pmt/class.c +++ b/drivers/platform/x86/intel/pmt/class.c @@ -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,7 +79,11 @@ intel_pmt_read(struct file *filp, struct kobject *kobj,  	if (count > entry->size - off)  		count = entry->size - off; -	memcpy_fromio(buf, entry->base + off, count); +	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;  }  | 
