summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErnesto Corona <ernesto.corona@intel.com>2021-03-04 03:11:47 +0300
committerCorona, Ernesto <ernesto.corona@intel.com>2021-03-10 01:20:41 +0300
commit0f09c51c79e5c94308c7ab784ca3b8c81c8ab388 (patch)
treed9ebe690015b7dc92c340bba6e4ba1e1c9ec958d
parent817457c56a3ba0b3630e27ca1ba6cd8b8e5d1c0d (diff)
downloadlinux-0f09c51c79e5c94308c7ab784ca3b8c81c8ab388.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. Change-Id: I6d53349a724c66d08b6cbbaeac166c4857835b55 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