-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
…s_m() Jacob Keller came with data in #2 that proves that defining pack_fields_m() and unpack_fields_m() as macros directly callable by consumer drivers is not a great idea. We can hide those macros inside the lib/packing.c translation module, and just provide pack_fields_8(), pack_fields_16(), unpack_fields_8() and unpack_fields_16() as entry points into the library. We can even go one step further and expose just pack_fields() and unpack_fields(), and use the new C11 _Generic() selection feature, which can call one function or the other, depending on the type of the "fields" array - a caveman form of polymorphism. It is evaluated at compile time which function will actually be called. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,68 +65,32 @@ struct packed_field { | |
|
||
#include <generated/packing-checks.h> | ||
|
||
void pack_fields(void *pbuf, size_t pbuflen, const void *ustruct, | ||
const struct packed_field *fields, size_t num_fields, | ||
u8 quirks); | ||
|
||
void unpack_fields(const void *pbuf, size_t pbuflen, void *ustruct, | ||
const struct packed_field *fields, size_t num_fields, | ||
void pack_fields_8(void *pbuf, size_t pbuflen, const void *ustruct, | ||
const struct packed_field_8 *fields, size_t num_fields, | ||
u8 quirks); | ||
|
||
#define pack_fields_m(pbuf, pbuflen, ustruct, fields, quirks) \ | ||
({ \ | ||
size_t num_fields = ARRAY_SIZE(fields); \ | ||
\ | ||
for (size_t i = 0; i < num_fields; i++) { \ | ||
typeof ((fields)[0]) *field = &(fields)[i]; \ | ||
u64 uval; \ | ||
\ | ||
switch (field->size) { \ | ||
case 1: \ | ||
uval = *((u8 *)((u8 *)ustruct + field->offset)); \ | ||
break; \ | ||
case 2: \ | ||
uval = *((u16 *)((u8 *)ustruct + field->offset)); \ | ||
break; \ | ||
case 4: \ | ||
uval = *((u32 *)((u8 *)ustruct + field->offset)); \ | ||
break; \ | ||
default: \ | ||
uval = *((u64 *)((u8 *)ustruct + field->offset)); \ | ||
break; \ | ||
} \ | ||
\ | ||
__pack(pbuf, uval, field->startbit, field->endbit, \ | ||
pbuflen, quirks); \ | ||
} \ | ||
}) | ||
|
||
#define unpack_fields_m(pbuf, pbuflen, ustruct, fields, quirks) \ | ||
({ \ | ||
size_t num_fields = ARRAY_SIZE(fields); \ | ||
\ | ||
for (size_t i = 0; i < num_fields; i++) { \ | ||
typeof ((fields)[0]) *field = &fields[i]; \ | ||
u64 uval; \ | ||
\ | ||
__unpack(pbuf, &uval, field->startbit, field->endbit, \ | ||
pbuflen, quirks); \ | ||
\ | ||
switch (field->size) { \ | ||
case 1: \ | ||
*((u8 *)((u8 *)ustruct + field->offset)) = uval; \ | ||
break; \ | ||
case 2: \ | ||
*((u16 *)((u8 *)ustruct + field->offset)) = uval; \ | ||
break; \ | ||
case 4: \ | ||
*((u32 *)((u8 *)ustruct + field->offset)) = uval; \ | ||
break; \ | ||
default: \ | ||
*((u64 *)((u8 *)ustruct + field->offset)) = uval; \ | ||
break; \ | ||
} \ | ||
} \ | ||
}) | ||
void pack_fields_16(void *pbuf, size_t pbuflen, const void *ustruct, | ||
const struct packed_field_16 *fields, size_t num_fields, | ||
u8 quirks); | ||
|
||
void unpack_fields_8(const void *pbuf, size_t pbuflen, void *ustruct, | ||
const struct packed_field_8 *fields, size_t num_fields, | ||
u8 quirks); | ||
|
||
void unpack_fields_16(const void *pbuf, size_t pbuflen, void *ustruct, | ||
const struct packed_field_16 *fields, size_t num_fields, | ||
u8 quirks); | ||
|
||
#define pack_fields(pbuf, pbuflen, ustruct, fields, quirks) \ | ||
_Generic((fields), \ | ||
const struct packed_field_8 *: pack_fields_8, \ | ||
default: pack_fields_16 \ | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
vladimiroltean
Author
Owner
|
||
)(pbuf, pbuflen, ustruct, fields, ARRAY_SIZE(fields), quirks) | ||
|
||
#define unpack_fields(pbuf, pbuflen, ustruct, fields, quirks) \ | ||
_Generic((fields), \ | ||
const struct packed_field_8 *: unpack_fields_8, \ | ||
default: unpack_fields_16 \ | ||
)(pbuf, pbuflen, ustruct, fields, ARRAY_SIZE(fields), quirks) | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,32 @@ | |
#include <linux/types.h> | ||
#include <linux/bitrev.h> | ||
|
||
#define pack_fields_m(pbuf, pbuflen, ustruct, fields, num_fields, quirks) \ | ||
({ \ | ||
for (size_t i = 0; i < (num_fields); i++) { \ | ||
typeof ((fields)[0]) *field = &(fields)[i]; \ | ||
u64 uval; \ | ||
\ | ||
uval = ustruct_field_to_u64(ustruct, field->offset, field->size); \ | ||
This comment has been minimized.
Sorry, something went wrong.
jacob-keller
|
||
\ | ||
__pack(pbuf, uval, field->startbit, field->endbit, \ | ||
pbuflen, quirks); \ | ||
} \ | ||
}) | ||
|
||
#define unpack_fields_m(pbuf, pbuflen, ustruct, fields, num_fields, quirks) \ | ||
({ \ | ||
for (size_t i = 0; i < (num_fields); i++) { \ | ||
typeof ((fields)[0]) *field = &fields[i]; \ | ||
u64 uval; \ | ||
\ | ||
__unpack(pbuf, &uval, field->startbit, field->endbit, \ | ||
pbuflen, quirks); \ | ||
\ | ||
u64_to_ustruct_field(ustruct, field->offset, field->size, uval); \ | ||
} \ | ||
}) | ||
|
||
/** | ||
* calculate_box_addr - Determine physical location of byte in buffer | ||
* @box: Index of byte within buffer seen as a logical big-endian big number | ||
|
@@ -130,7 +156,6 @@ void __pack(void *pbuf, u64 uval, size_t startbit, size_t endbit, | |
((u8 *)pbuf)[box_addr] |= pval; | ||
} | ||
} | ||
EXPORT_SYMBOL(__pack); | ||
|
||
/** | ||
* pack - Pack u64 number into bitfield of buffer. | ||
|
@@ -243,7 +268,6 @@ void __unpack(const void *pbuf, u64 *uval, size_t startbit, size_t endbit, | |
*uval |= pval; | ||
} | ||
} | ||
EXPORT_SYMBOL(__unpack); | ||
|
||
/** | ||
* unpack - Unpack u64 number from packed buffer. | ||
|
@@ -287,72 +311,70 @@ int unpack(const void *pbuf, u64 *uval, size_t startbit, size_t endbit, | |
} | ||
EXPORT_SYMBOL(unpack); | ||
|
||
static u64 ustruct_field_to_u64(const void *ustruct, const struct packed_field *field) | ||
static u64 ustruct_field_to_u64(const void *ustruct, size_t field_offset, | ||
size_t field_size) | ||
{ | ||
switch (field->size) { | ||
switch (field_size) { | ||
case 1: | ||
return *((u8 *)(ustruct + field->offset)); | ||
return *((u8 *)(ustruct + field_offset)); | ||
case 2: | ||
return *((u16 *)(ustruct + field->offset)); | ||
return *((u16 *)(ustruct + field_offset)); | ||
case 4: | ||
return *((u32 *)(ustruct + field->offset)); | ||
return *((u32 *)(ustruct + field_offset)); | ||
default: | ||
return *((u64 *)(ustruct + field->offset)); | ||
return *((u64 *)(ustruct + field_offset)); | ||
} | ||
} | ||
|
||
static void u64_to_ustruct_field(void *ustruct, const struct packed_field *field, | ||
u64 uval) | ||
static void u64_to_ustruct_field(void *ustruct, size_t field_offset, | ||
size_t field_size, u64 uval) | ||
{ | ||
switch (field->size) { | ||
switch (field_size) { | ||
case 1: | ||
*((u8 *)(ustruct + field->offset)) = uval; | ||
*((u8 *)(ustruct + field_offset)) = uval; | ||
break; | ||
case 2: | ||
*((u16 *)(ustruct + field->offset)) = uval; | ||
*((u16 *)(ustruct + field_offset)) = uval; | ||
break; | ||
case 4: | ||
*((u32 *)(ustruct + field->offset)) = uval; | ||
*((u32 *)(ustruct + field_offset)) = uval; | ||
break; | ||
default: | ||
*((u64 *)(ustruct + field->offset)) = uval; | ||
*((u64 *)(ustruct + field_offset)) = uval; | ||
break; | ||
} | ||
} | ||
|
||
void pack_fields(void *pbuf, size_t pbuflen, const void *ustruct, | ||
const struct packed_field *fields, size_t num_fields, u8 quirks) | ||
void pack_fields_8(void *pbuf, size_t pbuflen, const void *ustruct, | ||
const struct packed_field_8 *fields, size_t num_fields, | ||
u8 quirks) | ||
{ | ||
size_t i; | ||
|
||
for (i = 0; i < num_fields; i++) { | ||
const struct packed_field *field = &fields[i]; | ||
u64 uval; | ||
|
||
uval = ustruct_field_to_u64(ustruct, field); | ||
|
||
__pack(pbuf, uval, field->startbit, field->endbit, pbuflen, | ||
quirks); | ||
} | ||
pack_fields_m(pbuf, pbuflen, ustruct, fields, num_fields, quirks); | ||
} | ||
EXPORT_SYMBOL(pack_fields); | ||
EXPORT_SYMBOL(pack_fields_8); | ||
|
||
void unpack_fields(const void *pbuf, size_t pbuflen, void *ustruct, | ||
const struct packed_field *fields, size_t num_fields, | ||
u8 quirks) | ||
void pack_fields_16(void *pbuf, size_t pbuflen, const void *ustruct, | ||
const struct packed_field_16 *fields, size_t num_fields, | ||
u8 quirks) | ||
{ | ||
size_t i; | ||
|
||
for (i = 0; i < num_fields; i++) { | ||
const struct packed_field *field = &fields[i]; | ||
u64 uval; | ||
pack_fields_m(pbuf, pbuflen, ustruct, fields, num_fields, quirks); | ||
} | ||
EXPORT_SYMBOL(pack_fields_16); | ||
|
||
__unpack(pbuf, &uval, field->startbit, field->endbit, pbuflen, | ||
quirks); | ||
void unpack_fields_8(const void *pbuf, size_t pbuflen, void *ustruct, | ||
const struct packed_field_8 *fields, size_t num_fields, | ||
u8 quirks) | ||
{ | ||
unpack_fields_m(pbuf, pbuflen, ustruct, fields, num_fields, quirks); | ||
} | ||
EXPORT_SYMBOL(unpack_fields_8); | ||
|
||
u64_to_ustruct_field(ustruct, field, uval); | ||
} | ||
void unpack_fields_16(const void *pbuf, size_t pbuflen, void *ustruct, | ||
const struct packed_field_16 *fields, size_t num_fields, | ||
u8 quirks) | ||
{ | ||
unpack_fields_m(pbuf, pbuflen, ustruct, fields, num_fields, quirks); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
vladimiroltean
Author
Owner
|
||
} | ||
This comment has been minimized.
Sorry, something went wrong.
jacob-keller
|
||
EXPORT_SYMBOL(unpack_fields); | ||
EXPORT_SYMBOL(unpack_fields_16); | ||
|
||
MODULE_DESCRIPTION("Generic bitfield packing and unpacking"); |
1 comment
on commit c77f375
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to load this on my live migration branch and test it out to confirm that everything works ok for ice.
This only supports _8 and _16 right now? And we drop size_t altogether?
Does _Generic support producing an error if we don't specify the right type? I think it would be more readable to specify the types fully and leave out a default.