summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErnesto Corona <ernesto.corona@intel.com>2021-03-04 03:11:47 +0300
committerJae Hyun Yoo <jae.hyun.yoo@intel.com>2021-07-14 20:07:04 +0300
commite689e7ebfcd29ecc1e46f4954293a7d8e216c926 (patch)
treebba445b97cb170c1e6f597da6234cf0ab543c6c3
parent45c47cd4091a6f2368b19e62e46fc43b6d286f0b (diff)
downloadlinux-e689e7ebfcd29ecc1e46f4954293a7d8e216c926.tar.xz
ASD Prevent TDI remaining bits to be override during JTAG xfer
JTAG xfer length is measured in bits and it is allowed to send non 8-bit aligned xfers. For such xfers we will read the content of the remaining bits in the last byte of tdi buffer and restore those bits along with the xfer readback. Add also linux types to JTAG header to remove external dependencies. Test: SPR ASD Sanity and jtag_test finished successfully. SKX ASD Sanity and jtag_test finished successfully. Signed-off-by: Ernesto Corona <ernesto.corona@intel.com>
-rw-r--r--drivers/jtag/jtag.c18
-rw-r--r--include/uapi/linux/jtag.h3
2 files changed, 20 insertions, 1 deletions
diff --git a/drivers/jtag/jtag.c b/drivers/jtag/jtag.c
index 39a4d88a9c21..d4f0250d56be 100644
--- a/drivers/jtag/jtag.c
+++ b/drivers/jtag/jtag.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/rtnetlink.h>
#include <linux/spinlock.h>
-#include <linux/types.h>
#include <uapi/linux/jtag.h>
struct jtag {
@@ -89,6 +88,10 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
case JTAG_IOCXFER:
+ {
+ u8 ubit_mask = GENMASK(7, 0);
+ u8 remaining_bits = 0x0;
+
if (copy_from_user(&xfer, (const void __user *)arg,
sizeof(struct jtag_xfer)))
return -EFAULT;
@@ -110,6 +113,14 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE);
xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size);
+
+ /* Save unused remaining bits in this transfer */
+ if ((xfer.length % BITS_PER_BYTE)) {
+ ubit_mask = GENMASK((xfer.length % BITS_PER_BYTE) - 1,
+ 0);
+ remaining_bits = xfer_data[data_size - 1] & ~ubit_mask;
+ }
+
if (IS_ERR(xfer_data))
return -EFAULT;
@@ -119,6 +130,10 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return err;
}
+ /* Restore unused remaining bits in this transfer */
+ xfer_data[data_size - 1] = (xfer_data[data_size - 1]
+ & ubit_mask) | remaining_bits;
+
err = copy_to_user(u64_to_user_ptr(xfer.tdio),
(void *)xfer_data, data_size);
kfree(xfer_data);
@@ -129,6 +144,7 @@ static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
sizeof(struct jtag_xfer)))
return -EFAULT;
break;
+ }
case JTAG_GIOCSTATUS:
err = jtag->ops->status_get(jtag, &value);
diff --git a/include/uapi/linux/jtag.h b/include/uapi/linux/jtag.h
index 220ffabe81cd..256ec7231629 100644
--- a/include/uapi/linux/jtag.h
+++ b/include/uapi/linux/jtag.h
@@ -6,6 +6,9 @@
#ifndef __UAPI_LINUX_JTAG_H
#define __UAPI_LINUX_JTAG_H
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
/*
* JTAG_XFER_MODE: JTAG transfer mode. Used to set JTAG controller transfer mode
* This is bitmask for feature param in jtag_mode for ioctl JTAG_SIOCMODE