From 77d2716cf5579c4ad74df978ad58d983419cc44b Mon Sep 17 00:00:00 2001
From: Jakub Kicinski <jakub.kicinski@netronome.com>
Date: Wed, 31 Aug 2016 12:46:44 +0100
Subject: [PATCH] UPSTREAM: add basic register-field manipulation macros

Common approach to accessing register fields is to define
structures or sets of macros containing mask and shift pair.
Operations on the register are then performed as follows:

 field = (reg >> shift) & mask;

 reg &= ~(mask << shift);
 reg |= (field & mask) << shift;

Defining shift and mask separately is tedious.  Ivo van Doorn
came up with an idea of computing them at compilation time
based on a single shifted mask (later refined by Felix) which
can be used like this:

 #define REG_FIELD 0x000ff000

 field = FIELD_GET(REG_FIELD, reg);

 reg &= ~REG_FIELD;
 reg |= FIELD_PREP(REG_FIELD, field);

FIELD_{GET,PREP} macros take care of finding out what the
appropriate shift is based on compilation time ffs operation.

GENMASK can be used to define registers (which is usually
less error-prone and easier to match with datasheets).

This approach is the most convenient I've seen so to limit code
multiplication let's move the macros to a global header file.
Attempts to use static inlines instead of macros failed due
to false positive triggering of BUILD_BUG_ON()s, especially with
GCC < 6.0.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Dinan Gunawardena <dinan.gunawardena@netronome.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
(cherry picked from commit 3e9b3112ec74f192eaab976c3889e34255cae940)
---
 include/linux/bitfield.h | 93 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/bug.h      |  3 ++
 2 files changed, 96 insertions(+)
 create mode 100644 include/linux/bitfield.h

diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
new file mode 100644
index 000000000000..f6505d83069d
--- /dev/null
+++ b/include/linux/bitfield.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LINUX_BITFIELD_H
+#define _LINUX_BITFIELD_H
+
+#include <linux/bug.h>
+
+/*
+ * Bitfield access macros
+ *
+ * FIELD_{GET,PREP} macros take as first parameter shifted mask
+ * from which they extract the base mask and shift amount.
+ * Mask must be a compilation time constant.
+ *
+ * Example:
+ *
+ *  #define REG_FIELD_A  GENMASK(6, 0)
+ *  #define REG_FIELD_B  BIT(7)
+ *  #define REG_FIELD_C  GENMASK(15, 8)
+ *  #define REG_FIELD_D  GENMASK(31, 16)
+ *
+ * Get:
+ *  a = FIELD_GET(REG_FIELD_A, reg);
+ *  b = FIELD_GET(REG_FIELD_B, reg);
+ *
+ * Set:
+ *  reg = FIELD_PREP(REG_FIELD_A, 1) |
+ *	  FIELD_PREP(REG_FIELD_B, 0) |
+ *	  FIELD_PREP(REG_FIELD_C, c) |
+ *	  FIELD_PREP(REG_FIELD_D, 0x40);
+ *
+ * Modify:
+ *  reg &= ~REG_FIELD_C;
+ *  reg |= FIELD_PREP(REG_FIELD_C, c);
+ */
+
+#define __bf_shf(x) (__builtin_ffsll(x) - 1)
+
+#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx)			\
+	({								\
+		BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask),		\
+				 _pfx "mask is not constant");		\
+		BUILD_BUG_ON_MSG(!(_mask), _pfx "mask is zero");	\
+		BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ?		\
+				 ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \
+				 _pfx "value too large for the field"); \
+		BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ull,		\
+				 _pfx "type of reg too small for mask"); \
+		__BUILD_BUG_ON_NOT_POWER_OF_2((_mask) +			\
+					      (1ULL << __bf_shf(_mask))); \
+	})
+
+/**
+ * FIELD_PREP() - prepare a bitfield element
+ * @_mask: shifted mask defining the field's length and position
+ * @_val:  value to put in the field
+ *
+ * FIELD_PREP() masks and shifts up the value.  The result should
+ * be combined with other fields of the bitfield using logical OR.
+ */
+#define FIELD_PREP(_mask, _val)						\
+	({								\
+		__BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: ");	\
+		((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask);	\
+	})
+
+/**
+ * FIELD_GET() - extract a bitfield element
+ * @_mask: shifted mask defining the field's length and position
+ * @_reg:  32bit value of entire bitfield
+ *
+ * FIELD_GET() extracts the field specified by @_mask from the
+ * bitfield passed in as @_reg by masking and shifting it down.
+ */
+#define FIELD_GET(_mask, _reg)						\
+	({								\
+		__BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: ");	\
+		(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask));	\
+	})
+
+#endif
diff --git a/include/linux/bug.h b/include/linux/bug.h
index 7f4818673c41..edd3d8d3cd90 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -13,6 +13,7 @@ enum bug_trap_type {
 struct pt_regs;
 
 #ifdef __CHECKER__
+#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) (0)
 #define BUILD_BUG_ON_NOT_POWER_OF_2(n) (0)
 #define BUILD_BUG_ON_ZERO(e) (0)
 #define BUILD_BUG_ON_NULL(e) ((void*)0)
@@ -23,6 +24,8 @@ struct pt_regs;
 #else /* __CHECKER__ */
 
 /* Force a compilation error if a constant expression is not a power of 2 */
+#define __BUILD_BUG_ON_NOT_POWER_OF_2(n)	\
+	BUILD_BUG_ON(((n) & ((n) - 1)) != 0)
 #define BUILD_BUG_ON_NOT_POWER_OF_2(n)			\
 	BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
 

From 3841d053b087e87d8d3d77738452c3b14d724049 Mon Sep 17 00:00:00 2001
From: Jakub Kicinski <jakub.kicinski@netronome.com>
Date: Thu, 9 Feb 2017 09:17:27 -0800
Subject: [PATCH] UPSTREAM: bitfield.h: add FIELD_FIT() helper

Add a helper for checking at runtime that a value will fit inside
a specified field/mask.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 1697599ee301a52cded6499a09bd609f7f63fd06)
---
 include/linux/bitfield.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index f6505d83069d..8b9d6fff002d 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -62,6 +62,19 @@
 					      (1ULL << __bf_shf(_mask))); \
 	})
 
+/**
+ * FIELD_FIT() - check if value fits in the field
+ * @_mask: shifted mask defining the field's length and position
+ * @_val:  value to test against the field
+ *
+ * Return: true if @_val can fit inside @_mask, false if @_val is too big.
+ */
+#define FIELD_FIT(_mask, _val)						\
+	({								\
+		__BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_FIT: ");	\
+		!((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \
+	})
+
 /**
  * FIELD_PREP() - prepare a bitfield element
  * @_mask: shifted mask defining the field's length and position

From b0dcc7c8cc60ef7877baf3639a46344d8b184fc7 Mon Sep 17 00:00:00 2001
From: Laurent Defert <laurent.defert@smartjog.com>
Date: Wed, 11 Oct 2017 08:46:52 +0200
Subject: [PATCH] FROMLIST: compat_ioctl: add compat handler for
 FE_SET_PROPERTY and FE_GET_PROPERTY

https://patchwork.linuxtv.org/patch/8209/
---
 fs/compat_ioctl.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 138 insertions(+)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index a52ca5cba015..438ce0c6851e 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -223,6 +223,140 @@ static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd,
 	return err;
 }
 
+struct compat_dtv_property {
+	__u32 cmd;
+	__u32 reserved[3];
+	union {
+		__u32 data;
+		struct {
+			__u8 data[32];
+			__u32 len;
+			__u32 reserved1[3];
+			compat_uptr_t reserved2;
+		} buffer;
+	} u;
+	int result;
+};
+
+struct compat_dtv_properties {
+	__u32 num;
+	compat_uptr_t props;
+};
+
+#define FE_SET_PROPERTY32    _IOW('o', 82, struct compat_dtv_properties)
+#define FE_GET_PROPERTY32    _IOR('o', 83, struct compat_dtv_properties)
+
+static int do_fe_set_property(unsigned int fd, unsigned int cmd,
+		struct compat_dtv_properties __user *dtv32)
+{
+	struct dtv_properties __user *dtv;
+	struct dtv_property __user *properties;
+	struct compat_dtv_property __user *properties32;
+	compat_uptr_t data;
+
+	int err;
+	int i;
+	__u32 num;
+
+	err = get_user(num, &dtv32->num);
+	err |= get_user(data, &dtv32->props);
+
+	if(err)
+		return -EFAULT;
+
+	dtv = compat_alloc_user_space(sizeof(struct dtv_properties) +
+			sizeof(struct dtv_property) * num);
+	properties = (struct dtv_property*)((char*)dtv +
+			sizeof(struct dtv_properties));
+
+	err = put_user(properties, &dtv->props);
+	err |= put_user(num, &dtv->num);
+
+	properties32 = compat_ptr(data);
+
+	if(err)
+		return -EFAULT;
+
+	for(i = 0; i < num; i++) {
+		compat_uptr_t reserved2;
+
+		err |= copy_in_user(&properties[i], &properties32[i],
+				(8 * sizeof(__u32)) + (32 * sizeof(__u8)));
+		err |= get_user(reserved2, &properties32[i].u.buffer.reserved2);
+		err |= put_user(compat_ptr(reserved2),
+				&properties[i].u.buffer.reserved2);
+	}
+
+	if(err)
+		return -EFAULT;
+
+	err = sys_ioctl(fd, FE_SET_PROPERTY, (unsigned long) dtv);
+
+	for(i = 0; i < num; i++) {
+		if(copy_in_user(&properties32[i].result, &properties[i].result,
+					sizeof(int)))
+			return -EFAULT;
+	}
+
+	return err;
+}
+
+static int do_fe_get_property(unsigned int fd, unsigned int cmd,
+		struct compat_dtv_properties __user *dtv32)
+{
+	struct dtv_properties __user *dtv;
+	struct dtv_property __user *properties;
+	struct compat_dtv_property __user *properties32;
+	compat_uptr_t data;
+
+	int err;
+	int i;
+	__u32 num;
+
+	err = get_user(num, &dtv32->num);
+	err |= get_user(data, &dtv32->props);
+
+	if(err)
+		return -EFAULT;
+
+	dtv = compat_alloc_user_space(sizeof(struct dtv_properties) +
+			sizeof(struct dtv_property) * num);
+	properties = (struct dtv_property*)((char*)dtv +
+			sizeof(struct dtv_properties));
+
+	err = put_user(properties, &dtv->props);
+	err |= put_user(num, &dtv->num);
+
+	properties32 = compat_ptr(data);
+
+	if(err)
+		return -EFAULT;
+
+	for(i = 0; i < num; i++) {
+		compat_uptr_t reserved2;
+
+		err |= copy_in_user(&properties[i], &properties32[i],
+				(8 * sizeof(__u32)) + (32 * sizeof(__u8)));
+		err |= get_user(reserved2, &properties32[i].u.buffer.reserved2);
+		err |= put_user(compat_ptr(reserved2),
+				&properties[i].u.buffer.reserved2);
+	}
+
+	if(err)
+		return -EFAULT;
+
+	err = sys_ioctl(fd, FE_GET_PROPERTY, (unsigned long) dtv);
+
+	for(i = 0; i < num; i++) {
+
+		if(copy_in_user(&properties32[i], &properties[i],
+					sizeof(properties32[i])))
+			return -EFAULT;
+	}
+
+	return err;
+}
+
 #ifdef CONFIG_BLOCK
 typedef struct sg_io_hdr32 {
 	compat_int_t interface_id;	/* [i] 'S' for SCSI generic (required) */
@@ -1483,6 +1617,10 @@ static long do_ioctl_trans(int fd, unsigned int cmd,
 		return do_video_stillpicture(fd, cmd, argp);
 	case VIDEO_SET_SPU_PALETTE:
 		return do_video_set_spu_palette(fd, cmd, argp);
+	case FE_SET_PROPERTY32:
+		return do_fe_set_property(fd, cmd, argp);
+	case FE_GET_PROPERTY32:
+		return do_fe_get_property(fd, cmd, argp);
 	}
 
 	/*
