1709Swollman================================================ 217210SpstGeneric bitfield packing and unpacking functions 3709Swollman================================================ 437Srgrimes 537SrgrimesProblem statement 637Srgrimes----------------- 737Srgrimes 837SrgrimesWhen working with hardware, one has to choose between several approaches of 937Srgrimesinterfacing with it. 108460SjkhOne can memory-map a pointer to a carefully crafted struct over the hardware 118460Sjkhdevice's memory region, and access its fields as struct members (potentially 128460Sjkhdeclared as bitfields). But writing code this way would make it less portable, 138460Sjkhdue to potential endianness mismatches between the CPU and the hardware device. 1437SrgrimesAdditionally, one has to pay close attention when translating register 1537Srgrimesdefinitions from the hardware documentation into bit field indices for the 1637Srgrimesstructs. Also, some hardware (typically networking equipment) tends to group 1737Srgrimesits register fields in ways that violate any reasonable word boundaries 1837Srgrimes(sometimes even 64 bit ones). This creates the inconvenience of having to 1937Srgrimesdefine "high" and "low" portions of register fields within the struct. 2037SrgrimesA more robust alternative to struct field definitions would be to extract the 2137Srgrimesrequired fields by shifting the appropriate number of bits. But this would 2237Srgrimesstill not protect from endianness mismatches, except if all memory accesses 2337Srgrimeswere performed byte-by-byte. Also the code can easily get cluttered, and the 2437Srgrimeshigh-level idea might get lost among the many bit shifts required. 2515568SasamiMany drivers take the bit-shifting approach and then attempt to reduce the 2615568Sasamiclutter with tailored macros, but more often than not these macros take 2715568Sasamishortcuts that still prevent the code from being truly portable. 2815568Sasami 2915568SasamiThe solution 3015568Sasami------------ 313843Sdg 323843SdgThis API deals with 2 basic operations: 332164Sdg 3437Srgrimes - Packing a CPU-usable number into a memory buffer (with hardware 3537Srgrimes constraints/quirks) 3637Srgrimes - Unpacking a memory buffer (which has hardware constraints/quirks) 3737Srgrimes into a CPU-usable number. 3837Srgrimes 3937SrgrimesThe API offers an abstraction over said hardware constraints and quirks, 4037Srgrimesover CPU endianness and therefore between possible mismatches between 4137Srgrimesthe two. 4237Srgrimes 4337SrgrimesThe basic unit of these API functions is the u64. From the CPU's 4437Srgrimesperspective, bit 63 always means bit offset 7 of byte 7, albeit only 4537Srgrimeslogically. The question is: where do we lay this bit out in memory? 4637Srgrimes 4737SrgrimesThe following examples cover the memory layout of a packed u64 field. 4837SrgrimesThe byte offsets in the packed buffer are always implicitly 0, 1, ... 7. 4937SrgrimesWhat the examples show is where the logical bytes and bits sit. 5037Srgrimes 5137Srgrimes1. Normally (no quirks), we would do it like this: 5237Srgrimes 5337Srgrimes:: 5437Srgrimes 5537Srgrimes 63 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 5637Srgrimes 7 6 5 4 5737Srgrimes 31 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 5837Srgrimes 3 2 1 0 5937Srgrimes 6037SrgrimesThat is, the MSByte (7) of the CPU-usable u64 sits at memory offset 0, and the 6137SrgrimesLSByte (0) of the u64 sits at memory offset 7. 6237SrgrimesThis corresponds to what most folks would regard to as "big endian", where 6337Srgrimesbit i corresponds to the number 2^i. This is also referred to in the code 6437Srgrimescomments as "logical" notation. 652164Sdg 662164Sdg 6737Srgrimes2. If QUIRK_MSB_ON_THE_RIGHT is set, we do it like this: 6837Srgrimes 6937Srgrimes:: 7037Srgrimes 713036Sdg 56 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 723036Sdg 7 6 5 4 733036Sdg 24 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 748530Sdg 3 2 1 0 758530Sdg 768530SdgThat is, QUIRK_MSB_ON_THE_RIGHT does not affect byte positioning, but 778530Sdginverts bit offsets inside a byte. 781692Sphk 7937Srgrimes 808530Sdg3. If QUIRK_LITTLE_ENDIAN is set, we do it like this: 8137Srgrimes 828530Sdg:: 838530Sdg 848530Sdg 39 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 858530Sdg 4 5 6 7 8637Srgrimes 7 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 874091Sache 0 1 2 3 88872Sache 897219SjkhTherefore, QUIRK_LITTLE_ENDIAN means that inside the memory region, every 907219Sjkhbyte from each 4-byte word is placed at its mirrored position compared to 917219Sjkhthe boundary of that word. 927219Sjkh 937219Sjkh4. If QUIRK_MSB_ON_THE_RIGHT and QUIRK_LITTLE_ENDIAN are both set, we do it 941675Sache like this: 957219Sjkh 967293Sjkh:: 971675Sache 981675Sache 32 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 9914596Snate 4 5 6 7 10014624Snate 0 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 10114624Snate 0 1 2 3 10214596Snate 10314596Snate 1047487Srgrimes5. If just QUIRK_LSW32_IS_FIRST is set, we do it like this: 1057460Sjkh 1067750Srgrimes:: 1077460Sjkh 1087460Sjkh 31 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 1098540Srgrimes 3 2 1 0 1107487Srgrimes 63 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 1117487Srgrimes 7 6 5 4 1127487Srgrimes 1137487SrgrimesIn this case the 8 byte memory region is interpreted as follows: first 1147487Srgrimes4 bytes correspond to the least significant 4-byte word, next 4 bytes to 1157487Srgrimesthe more significant 4-byte word. 1167487Srgrimes 1177761Sache 1187487Srgrimes6. If QUIRK_LSW32_IS_FIRST and QUIRK_MSB_ON_THE_RIGHT are set, we do it like 11915684Sjkh this: 1207487Srgrimes 12116588Sjoerg:: 12216588Sjoerg 12316588Sjoerg 24 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 12416588Sjoerg 3 2 1 0 12516588Sjoerg 56 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 12616588Sjoerg 7 6 5 4 12716588Sjoerg 12816588Sjoerg 12916588Sjoerg7. If QUIRK_LSW32_IS_FIRST and QUIRK_LITTLE_ENDIAN are set, it looks like 1307487Srgrimes this: 1317487Srgrimes 1327487Srgrimes:: 1337487Srgrimes 1347487Srgrimes 7 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 1357487Srgrimes 0 1 2 3 1367487Srgrimes 39 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 13716588Sjoerg 4 5 6 7 13816588Sjoerg 13916588Sjoerg 14016588Sjoerg8. If QUIRK_LSW32_IS_FIRST, QUIRK_LITTLE_ENDIAN and QUIRK_MSB_ON_THE_RIGHT 14116588Sjoerg are set, it looks like this: 14216588Sjoerg 14316588Sjoerg:: 14416588Sjoerg 1459305Sbde 0 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 1469305Sbde 0 1 2 3 1479305Sbde 32 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 1489305Sbde 4 5 6 7 1499305Sbde 1507487Srgrimes 1517487SrgrimesWe always think of our offsets as if there were no quirk, and we translate 1527487Srgrimesthem afterwards, before accessing the memory region. 1537487Srgrimes 1547487SrgrimesIntended use 1557487Srgrimes------------ 1567487Srgrimes 1577487SrgrimesDrivers that opt to use this API first need to identify which of the above 3 1587487Srgrimesquirk combinations (for a total of 8) match what the hardware documentation 1597487Srgrimesdescribes. Then they should wrap the packing() function, creating a new 1607487Srgrimesxxx_packing() that calls it using the proper QUIRK_* one-hot bits set. 1617487Srgrimes 1627487SrgrimesThe packing() function returns an int-encoded error code, which protects the 1637487Srgrimesprogrammer against incorrect API use. The errors are not expected to occur 1647487Srgrimesduring runtime, therefore it is reasonable for xxx_packing() to return void 1657487Srgrimesand simply swallow those errors. Optionally it can dump stack or print the 1667487Srgrimeserror description. 1677487Srgrimes