1================================================ 2Generic bitfield packing and unpacking functions 3================================================ 4 5Problem statement 6----------------- 7 8When working with hardware, one has to choose between several approaches of 9interfacing with it. 10One can memory-map a pointer to a carefully crafted struct over the hardware 11device's memory region, and access its fields as struct members (potentially 12declared as bitfields). But writing code this way would make it less portable, 13due to potential endianness mismatches between the CPU and the hardware device. 14Additionally, one has to pay close attention when translating register 15definitions from the hardware documentation into bit field indices for the 16structs. Also, some hardware (typically networking equipment) tends to group 17its register fields in ways that violate any reasonable word boundaries 18(sometimes even 64 bit ones). This creates the inconvenience of having to 19define "high" and "low" portions of register fields within the struct. 20A more robust alternative to struct field definitions would be to extract the 21required fields by shifting the appropriate number of bits. But this would 22still not protect from endianness mismatches, except if all memory accesses 23were performed byte-by-byte. Also the code can easily get cluttered, and the 24high-level idea might get lost among the many bit shifts required. 25Many drivers take the bit-shifting approach and then attempt to reduce the 26clutter with tailored macros, but more often than not these macros take 27shortcuts that still prevent the code from being truly portable. 28 29The solution 30------------ 31 32This API deals with 2 basic operations: 33 - Packing a CPU-usable number into a memory buffer (with hardware 34 constraints/quirks) 35 - Unpacking a memory buffer (which has hardware constraints/quirks) 36 into a CPU-usable number. 37 38The API offers an abstraction over said hardware constraints and quirks, 39over CPU endianness and therefore between possible mismatches between 40the two. 41 42The basic unit of these API functions is the u64. From the CPU's 43perspective, bit 63 always means bit offset 7 of byte 7, albeit only 44logically. The question is: where do we lay this bit out in memory? 45 46The following examples cover the memory layout of a packed u64 field. 47The byte offsets in the packed buffer are always implicitly 0, 1, ... 7. 48What the examples show is where the logical bytes and bits sit. 49 501. Normally (no quirks), we would do it like this: 51 5263 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 537 6 5 4 5431 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 553 2 1 0 56 57That is, the MSByte (7) of the CPU-usable u64 sits at memory offset 0, and the 58LSByte (0) of the u64 sits at memory offset 7. 59This corresponds to what most folks would regard to as "big endian", where 60bit i corresponds to the number 2^i. This is also referred to in the code 61comments as "logical" notation. 62 63 642. If QUIRK_MSB_ON_THE_RIGHT is set, we do it like this: 65 6656 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39 677 6 5 4 6824 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 693 2 1 0 70 71That is, QUIRK_MSB_ON_THE_RIGHT does not affect byte positioning, but 72inverts bit offsets inside a byte. 73 74 753. If QUIRK_LITTLE_ENDIAN is set, we do it like this: 76 7739 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56 784 5 6 7 797 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24 800 1 2 3 81 82Therefore, QUIRK_LITTLE_ENDIAN means that inside the memory region, every 83byte from each 4-byte word is placed at its mirrored position compared to 84the boundary of that word. 85 864. If QUIRK_MSB_ON_THE_RIGHT and QUIRK_LITTLE_ENDIAN are both set, we do it 87 like this: 88 8932 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 904 5 6 7 910 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 920 1 2 3 93 94 955. If just QUIRK_LSW32_IS_FIRST is set, we do it like this: 96 9731 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 983 2 1 0 9963 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 1007 6 5 4 101 102In this case the 8 byte memory region is interpreted as follows: first 1034 bytes correspond to the least significant 4-byte word, next 4 bytes to 104the more significant 4-byte word. 105 106 1076. If QUIRK_LSW32_IS_FIRST and QUIRK_MSB_ON_THE_RIGHT are set, we do it like 108 this: 109 11024 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 1113 2 1 0 11256 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39 1137 6 5 4 114 115 1167. If QUIRK_LSW32_IS_FIRST and QUIRK_LITTLE_ENDIAN are set, it looks like 117 this: 118 1197 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24 1200 1 2 3 12139 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56 1224 5 6 7 123 124 1258. If QUIRK_LSW32_IS_FIRST, QUIRK_LITTLE_ENDIAN and QUIRK_MSB_ON_THE_RIGHT 126 are set, it looks like this: 127 1280 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1290 1 2 3 13032 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 1314 5 6 7 132 133 134We always think of our offsets as if there were no quirk, and we translate 135them afterwards, before accessing the memory region. 136 137Intended use 138------------ 139 140Drivers that opt to use this API first need to identify which of the above 3 141quirk combinations (for a total of 8) match what the hardware documentation 142describes. Then they should wrap the packing() function, creating a new 143xxx_packing() that calls it using the proper QUIRK_* one-hot bits set. 144 145The packing() function returns an int-encoded error code, which protects the 146programmer against incorrect API use. The errors are not expected to occur 147durring runtime, therefore it is reasonable for xxx_packing() to return void 148and simply swallow those errors. Optionally it can dump stack or print the 149error description. 150