Commit a74e0c4c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dp-4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull device properties framework update from Rafael Wysocki:
 "Modify the device properties framework to remove union aliasing from
  it (Andy Shevchenko)"

* tag 'dp-4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  device property: Get rid of union aliasing
parents f4fe74cc 63dcc709
...@@ -56,6 +56,72 @@ pset_prop_get(const struct property_set *pset, const char *name) ...@@ -56,6 +56,72 @@ pset_prop_get(const struct property_set *pset, const char *name)
return NULL; return NULL;
} }
static const void *property_get_pointer(const struct property_entry *prop)
{
switch (prop->type) {
case DEV_PROP_U8:
if (prop->is_array)
return prop->pointer.u8_data;
return &prop->value.u8_data;
case DEV_PROP_U16:
if (prop->is_array)
return prop->pointer.u16_data;
return &prop->value.u16_data;
case DEV_PROP_U32:
if (prop->is_array)
return prop->pointer.u32_data;
return &prop->value.u32_data;
case DEV_PROP_U64:
if (prop->is_array)
return prop->pointer.u64_data;
return &prop->value.u64_data;
case DEV_PROP_STRING:
if (prop->is_array)
return prop->pointer.str;
return &prop->value.str;
default:
return NULL;
}
}
static void property_set_pointer(struct property_entry *prop, const void *pointer)
{
switch (prop->type) {
case DEV_PROP_U8:
if (prop->is_array)
prop->pointer.u8_data = pointer;
else
prop->value.u8_data = *((u8 *)pointer);
break;
case DEV_PROP_U16:
if (prop->is_array)
prop->pointer.u16_data = pointer;
else
prop->value.u16_data = *((u16 *)pointer);
break;
case DEV_PROP_U32:
if (prop->is_array)
prop->pointer.u32_data = pointer;
else
prop->value.u32_data = *((u32 *)pointer);
break;
case DEV_PROP_U64:
if (prop->is_array)
prop->pointer.u64_data = pointer;
else
prop->value.u64_data = *((u64 *)pointer);
break;
case DEV_PROP_STRING:
if (prop->is_array)
prop->pointer.str = pointer;
else
prop->value.str = pointer;
break;
default:
break;
}
}
static const void *pset_prop_find(const struct property_set *pset, static const void *pset_prop_find(const struct property_set *pset,
const char *propname, size_t length) const char *propname, size_t length)
{ {
...@@ -65,10 +131,7 @@ static const void *pset_prop_find(const struct property_set *pset, ...@@ -65,10 +131,7 @@ static const void *pset_prop_find(const struct property_set *pset,
prop = pset_prop_get(pset, propname); prop = pset_prop_get(pset, propname);
if (!prop) if (!prop)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (prop->is_array) pointer = property_get_pointer(prop);
pointer = prop->pointer.raw_data;
else
pointer = &prop->value.raw_data;
if (!pointer) if (!pointer)
return ERR_PTR(-ENODATA); return ERR_PTR(-ENODATA);
if (length > prop->length) if (length > prop->length)
...@@ -698,16 +761,17 @@ EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); ...@@ -698,16 +761,17 @@ EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
static void property_entry_free_data(const struct property_entry *p) static void property_entry_free_data(const struct property_entry *p)
{ {
const void *pointer = property_get_pointer(p);
size_t i, nval; size_t i, nval;
if (p->is_array) { if (p->is_array) {
if (p->is_string && p->pointer.str) { if (p->type == DEV_PROP_STRING && p->pointer.str) {
nval = p->length / sizeof(const char *); nval = p->length / sizeof(const char *);
for (i = 0; i < nval; i++) for (i = 0; i < nval; i++)
kfree(p->pointer.str[i]); kfree(p->pointer.str[i]);
} }
kfree(p->pointer.raw_data); kfree(pointer);
} else if (p->is_string) { } else if (p->type == DEV_PROP_STRING) {
kfree(p->value.str); kfree(p->value.str);
} }
kfree(p->name); kfree(p->name);
...@@ -716,7 +780,7 @@ static void property_entry_free_data(const struct property_entry *p) ...@@ -716,7 +780,7 @@ static void property_entry_free_data(const struct property_entry *p)
static int property_copy_string_array(struct property_entry *dst, static int property_copy_string_array(struct property_entry *dst,
const struct property_entry *src) const struct property_entry *src)
{ {
char **d; const char **d;
size_t nval = src->length / sizeof(*d); size_t nval = src->length / sizeof(*d);
int i; int i;
...@@ -734,40 +798,44 @@ static int property_copy_string_array(struct property_entry *dst, ...@@ -734,40 +798,44 @@ static int property_copy_string_array(struct property_entry *dst,
} }
} }
dst->pointer.raw_data = d; dst->pointer.str = d;
return 0; return 0;
} }
static int property_entry_copy_data(struct property_entry *dst, static int property_entry_copy_data(struct property_entry *dst,
const struct property_entry *src) const struct property_entry *src)
{ {
const void *pointer = property_get_pointer(src);
const void *new;
int error; int error;
if (src->is_array) { if (src->is_array) {
if (!src->length) if (!src->length)
return -ENODATA; return -ENODATA;
if (src->is_string) { if (src->type == DEV_PROP_STRING) {
error = property_copy_string_array(dst, src); error = property_copy_string_array(dst, src);
if (error) if (error)
return error; return error;
new = dst->pointer.str;
} else { } else {
dst->pointer.raw_data = kmemdup(src->pointer.raw_data, new = kmemdup(pointer, src->length, GFP_KERNEL);
src->length, GFP_KERNEL); if (!new)
if (!dst->pointer.raw_data)
return -ENOMEM; return -ENOMEM;
} }
} else if (src->is_string) { } else if (src->type == DEV_PROP_STRING) {
dst->value.str = kstrdup(src->value.str, GFP_KERNEL); new = kstrdup(src->value.str, GFP_KERNEL);
if (!dst->value.str && src->value.str) if (!new && src->value.str)
return -ENOMEM; return -ENOMEM;
} else { } else {
dst->value.raw_data = src->value.raw_data; new = pointer;
} }
dst->length = src->length; dst->length = src->length;
dst->is_array = src->is_array; dst->is_array = src->is_array;
dst->is_string = src->is_string; dst->type = src->type;
property_set_pointer(dst, new);
dst->name = kstrdup(src->name, GFP_KERNEL); dst->name = kstrdup(src->name, GFP_KERNEL);
if (!dst->name) if (!dst->name)
......
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>. * along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Note, all properties are considered as u8 arrays.
* To get a value of any of them the caller must use device_property_read_u8_array().
*/ */
#define pr_fmt(fmt) "apple-properties: " fmt #define pr_fmt(fmt) "apple-properties: " fmt
...@@ -96,12 +99,13 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, ...@@ -96,12 +99,13 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
entry[i].name = key; entry[i].name = key;
entry[i].length = val_len - sizeof(val_len); entry[i].length = val_len - sizeof(val_len);
entry[i].is_array = !!entry[i].length; entry[i].is_array = !!entry[i].length;
entry[i].pointer.raw_data = ptr + key_len + sizeof(val_len); entry[i].type = DEV_PROP_U8;
entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len);
if (dump_properties) { if (dump_properties) {
dev_info(dev, "property: %s\n", entry[i].name); dev_info(dev, "property: %s\n", entry[i].name);
print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET, print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
16, 1, entry[i].pointer.raw_data, 16, 1, entry[i].pointer.u8_data,
entry[i].length, true); entry[i].length, true);
} }
......
...@@ -178,7 +178,7 @@ static inline int fwnode_property_read_u64(const struct fwnode_handle *fwnode, ...@@ -178,7 +178,7 @@ static inline int fwnode_property_read_u64(const struct fwnode_handle *fwnode,
* @name: Name of the property. * @name: Name of the property.
* @length: Length of data making up the value. * @length: Length of data making up the value.
* @is_array: True when the property is an array. * @is_array: True when the property is an array.
* @is_string: True when property is a string. * @type: Type of the data in unions.
* @pointer: Pointer to the property (an array of items of the given type). * @pointer: Pointer to the property (an array of items of the given type).
* @value: Value of the property (when it is a single item of the given type). * @value: Value of the property (when it is a single item of the given type).
*/ */
...@@ -186,10 +186,9 @@ struct property_entry { ...@@ -186,10 +186,9 @@ struct property_entry {
const char *name; const char *name;
size_t length; size_t length;
bool is_array; bool is_array;
bool is_string; enum dev_prop_type type;
union { union {
union { union {
const void *raw_data;
const u8 *u8_data; const u8 *u8_data;
const u16 *u16_data; const u16 *u16_data;
const u32 *u32_data; const u32 *u32_data;
...@@ -197,7 +196,6 @@ struct property_entry { ...@@ -197,7 +196,6 @@ struct property_entry {
const char * const *str; const char * const *str;
} pointer; } pointer;
union { union {
unsigned long long raw_data;
u8 u8_data; u8 u8_data;
u16 u16_data; u16 u16_data;
u32 u32_data; u32 u32_data;
...@@ -213,55 +211,55 @@ struct property_entry { ...@@ -213,55 +211,55 @@ struct property_entry {
* and structs. * and structs.
*/ */
#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_) \ #define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _Type_, _val_) \
(struct property_entry) { \ (struct property_entry) { \
.name = _name_, \ .name = _name_, \
.length = ARRAY_SIZE(_val_) * sizeof(_type_), \ .length = ARRAY_SIZE(_val_) * sizeof(_type_), \
.is_array = true, \ .is_array = true, \
.is_string = false, \ .type = DEV_PROP_##_Type_, \
{ .pointer = { ._type_##_data = _val_ } }, \ { .pointer = { ._type_##_data = _val_ } }, \
} }
#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \ #define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, _val_) PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, U8, _val_)
#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \ #define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, _val_) PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, U16, _val_)
#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \ #define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, _val_) PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, U32, _val_)
#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \ #define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, _val_) PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, U64, _val_)
#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \ #define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \
(struct property_entry) { \ (struct property_entry) { \
.name = _name_, \ .name = _name_, \
.length = ARRAY_SIZE(_val_) * sizeof(const char *), \ .length = ARRAY_SIZE(_val_) * sizeof(const char *), \
.is_array = true, \ .is_array = true, \
.is_string = true, \ .type = DEV_PROP_STRING, \
{ .pointer = { .str = _val_ } }, \ { .pointer = { .str = _val_ } }, \
} }
#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_) \ #define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_) \
(struct property_entry) { \ (struct property_entry) { \
.name = _name_, \ .name = _name_, \
.length = sizeof(_type_), \ .length = sizeof(_type_), \
.is_string = false, \ .type = DEV_PROP_##_Type_, \
{ .value = { ._type_##_data = _val_ } }, \ { .value = { ._type_##_data = _val_ } }, \
} }
#define PROPERTY_ENTRY_U8(_name_, _val_) \ #define PROPERTY_ENTRY_U8(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u8, _val_) PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_)
#define PROPERTY_ENTRY_U16(_name_, _val_) \ #define PROPERTY_ENTRY_U16(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u16, _val_) PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_)
#define PROPERTY_ENTRY_U32(_name_, _val_) \ #define PROPERTY_ENTRY_U32(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u32, _val_) PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_)
#define PROPERTY_ENTRY_U64(_name_, _val_) \ #define PROPERTY_ENTRY_U64(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u64, _val_) PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_)
#define PROPERTY_ENTRY_STRING(_name_, _val_) \ #define PROPERTY_ENTRY_STRING(_name_, _val_) \
(struct property_entry) { \ (struct property_entry) { \
.name = _name_, \ .name = _name_, \
.length = sizeof(_val_), \ .length = sizeof(_val_), \
.is_string = true, \ .type = DEV_PROP_STRING, \
{ .value = { .str = _val_ } }, \ { .value = { .str = _val_ } }, \
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment