11ec779b9SMauro Carvalho Chehab================================================ 21ec779b9SMauro Carvalho ChehabGeneric bitfield packing and unpacking functions 31ec779b9SMauro Carvalho Chehab================================================ 41ec779b9SMauro Carvalho Chehab 51ec779b9SMauro Carvalho ChehabProblem statement 61ec779b9SMauro Carvalho Chehab----------------- 71ec779b9SMauro Carvalho Chehab 81ec779b9SMauro Carvalho ChehabWhen working with hardware, one has to choose between several approaches of 91ec779b9SMauro Carvalho Chehabinterfacing with it. 101ec779b9SMauro Carvalho ChehabOne can memory-map a pointer to a carefully crafted struct over the hardware 111ec779b9SMauro Carvalho Chehabdevice's memory region, and access its fields as struct members (potentially 121ec779b9SMauro Carvalho Chehabdeclared as bitfields). But writing code this way would make it less portable, 131ec779b9SMauro Carvalho Chehabdue to potential endianness mismatches between the CPU and the hardware device. 141ec779b9SMauro Carvalho ChehabAdditionally, one has to pay close attention when translating register 151ec779b9SMauro Carvalho Chehabdefinitions from the hardware documentation into bit field indices for the 161ec779b9SMauro Carvalho Chehabstructs. Also, some hardware (typically networking equipment) tends to group 171ec779b9SMauro Carvalho Chehabits register fields in ways that violate any reasonable word boundaries 181ec779b9SMauro Carvalho Chehab(sometimes even 64 bit ones). This creates the inconvenience of having to 191ec779b9SMauro Carvalho Chehabdefine "high" and "low" portions of register fields within the struct. 201ec779b9SMauro Carvalho ChehabA more robust alternative to struct field definitions would be to extract the 211ec779b9SMauro Carvalho Chehabrequired fields by shifting the appropriate number of bits. But this would 221ec779b9SMauro Carvalho Chehabstill not protect from endianness mismatches, except if all memory accesses 231ec779b9SMauro Carvalho Chehabwere performed byte-by-byte. Also the code can easily get cluttered, and the 241ec779b9SMauro Carvalho Chehabhigh-level idea might get lost among the many bit shifts required. 251ec779b9SMauro Carvalho ChehabMany drivers take the bit-shifting approach and then attempt to reduce the 261ec779b9SMauro Carvalho Chehabclutter with tailored macros, but more often than not these macros take 271ec779b9SMauro Carvalho Chehabshortcuts that still prevent the code from being truly portable. 281ec779b9SMauro Carvalho Chehab 291ec779b9SMauro Carvalho ChehabThe solution 301ec779b9SMauro Carvalho Chehab------------ 311ec779b9SMauro Carvalho Chehab 321ec779b9SMauro Carvalho ChehabThis API deals with 2 basic operations: 331ec779b9SMauro Carvalho Chehab 341ec779b9SMauro Carvalho Chehab - Packing a CPU-usable number into a memory buffer (with hardware 351ec779b9SMauro Carvalho Chehab constraints/quirks) 361ec779b9SMauro Carvalho Chehab - Unpacking a memory buffer (which has hardware constraints/quirks) 371ec779b9SMauro Carvalho Chehab into a CPU-usable number. 381ec779b9SMauro Carvalho Chehab 391ec779b9SMauro Carvalho ChehabThe API offers an abstraction over said hardware constraints and quirks, 401ec779b9SMauro Carvalho Chehabover CPU endianness and therefore between possible mismatches between 411ec779b9SMauro Carvalho Chehabthe two. 421ec779b9SMauro Carvalho Chehab 431ec779b9SMauro Carvalho ChehabThe basic unit of these API functions is the u64. From the CPU's 441ec779b9SMauro Carvalho Chehabperspective, bit 63 always means bit offset 7 of byte 7, albeit only 451ec779b9SMauro Carvalho Chehablogically. The question is: where do we lay this bit out in memory? 461ec779b9SMauro Carvalho Chehab 471ec779b9SMauro Carvalho ChehabThe following examples cover the memory layout of a packed u64 field. 481ec779b9SMauro Carvalho ChehabThe byte offsets in the packed buffer are always implicitly 0, 1, ... 7. 491ec779b9SMauro Carvalho ChehabWhat the examples show is where the logical bytes and bits sit. 501ec779b9SMauro Carvalho Chehab 511ec779b9SMauro Carvalho Chehab1. Normally (no quirks), we would do it like this: 521ec779b9SMauro Carvalho Chehab 531ec779b9SMauro Carvalho Chehab:: 541ec779b9SMauro Carvalho Chehab 551ec779b9SMauro Carvalho Chehab 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 561ec779b9SMauro Carvalho Chehab 7 6 5 4 571ec779b9SMauro Carvalho Chehab 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 581ec779b9SMauro Carvalho Chehab 3 2 1 0 591ec779b9SMauro Carvalho Chehab 601ec779b9SMauro Carvalho ChehabThat is, the MSByte (7) of the CPU-usable u64 sits at memory offset 0, and the 611ec779b9SMauro Carvalho ChehabLSByte (0) of the u64 sits at memory offset 7. 621ec779b9SMauro Carvalho ChehabThis corresponds to what most folks would regard to as "big endian", where 631ec779b9SMauro Carvalho Chehabbit i corresponds to the number 2^i. This is also referred to in the code 641ec779b9SMauro Carvalho Chehabcomments as "logical" notation. 651ec779b9SMauro Carvalho Chehab 661ec779b9SMauro Carvalho Chehab 671ec779b9SMauro Carvalho Chehab2. If QUIRK_MSB_ON_THE_RIGHT is set, we do it like this: 681ec779b9SMauro Carvalho Chehab 691ec779b9SMauro Carvalho Chehab:: 701ec779b9SMauro Carvalho Chehab 711ec779b9SMauro Carvalho Chehab 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 721ec779b9SMauro Carvalho Chehab 7 6 5 4 731ec779b9SMauro Carvalho Chehab 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 741ec779b9SMauro Carvalho Chehab 3 2 1 0 751ec779b9SMauro Carvalho Chehab 761ec779b9SMauro Carvalho ChehabThat is, QUIRK_MSB_ON_THE_RIGHT does not affect byte positioning, but 771ec779b9SMauro Carvalho Chehabinverts bit offsets inside a byte. 781ec779b9SMauro Carvalho Chehab 791ec779b9SMauro Carvalho Chehab 801ec779b9SMauro Carvalho Chehab3. If QUIRK_LITTLE_ENDIAN is set, we do it like this: 811ec779b9SMauro Carvalho Chehab 821ec779b9SMauro Carvalho Chehab:: 831ec779b9SMauro Carvalho Chehab 841ec779b9SMauro Carvalho Chehab 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 851ec779b9SMauro Carvalho Chehab 4 5 6 7 861ec779b9SMauro Carvalho Chehab 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 871ec779b9SMauro Carvalho Chehab 0 1 2 3 881ec779b9SMauro Carvalho Chehab 891ec779b9SMauro Carvalho ChehabTherefore, QUIRK_LITTLE_ENDIAN means that inside the memory region, every 901ec779b9SMauro Carvalho Chehabbyte from each 4-byte word is placed at its mirrored position compared to 911ec779b9SMauro Carvalho Chehabthe boundary of that word. 921ec779b9SMauro Carvalho Chehab 931ec779b9SMauro Carvalho Chehab4. If QUIRK_MSB_ON_THE_RIGHT and QUIRK_LITTLE_ENDIAN are both set, we do it 941ec779b9SMauro Carvalho Chehab like this: 951ec779b9SMauro Carvalho Chehab 961ec779b9SMauro Carvalho Chehab:: 971ec779b9SMauro Carvalho Chehab 981ec779b9SMauro Carvalho Chehab 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 991ec779b9SMauro Carvalho Chehab 4 5 6 7 1001ec779b9SMauro Carvalho Chehab 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 1011ec779b9SMauro Carvalho Chehab 0 1 2 3 1021ec779b9SMauro Carvalho Chehab 1031ec779b9SMauro Carvalho Chehab 1041ec779b9SMauro Carvalho Chehab5. If just QUIRK_LSW32_IS_FIRST is set, we do it like this: 1051ec779b9SMauro Carvalho Chehab 1061ec779b9SMauro Carvalho Chehab:: 1071ec779b9SMauro Carvalho Chehab 1081ec779b9SMauro Carvalho Chehab 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 1091ec779b9SMauro Carvalho Chehab 3 2 1 0 1101ec779b9SMauro Carvalho Chehab 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 1111ec779b9SMauro Carvalho Chehab 7 6 5 4 1121ec779b9SMauro Carvalho Chehab 1131ec779b9SMauro Carvalho ChehabIn this case the 8 byte memory region is interpreted as follows: first 1141ec779b9SMauro Carvalho Chehab4 bytes correspond to the least significant 4-byte word, next 4 bytes to 1151ec779b9SMauro Carvalho Chehabthe more significant 4-byte word. 1161ec779b9SMauro Carvalho Chehab 1171ec779b9SMauro Carvalho Chehab 1181ec779b9SMauro Carvalho Chehab6. If QUIRK_LSW32_IS_FIRST and QUIRK_MSB_ON_THE_RIGHT are set, we do it like 1191ec779b9SMauro Carvalho Chehab this: 1201ec779b9SMauro Carvalho Chehab 1211ec779b9SMauro Carvalho Chehab:: 1221ec779b9SMauro Carvalho Chehab 1231ec779b9SMauro Carvalho Chehab 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 1241ec779b9SMauro Carvalho Chehab 3 2 1 0 1251ec779b9SMauro Carvalho Chehab 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 1261ec779b9SMauro Carvalho Chehab 7 6 5 4 1271ec779b9SMauro Carvalho Chehab 1281ec779b9SMauro Carvalho Chehab 1291ec779b9SMauro Carvalho Chehab7. If QUIRK_LSW32_IS_FIRST and QUIRK_LITTLE_ENDIAN are set, it looks like 1301ec779b9SMauro Carvalho Chehab this: 1311ec779b9SMauro Carvalho Chehab 1321ec779b9SMauro Carvalho Chehab:: 1331ec779b9SMauro Carvalho Chehab 1341ec779b9SMauro Carvalho Chehab 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 1351ec779b9SMauro Carvalho Chehab 0 1 2 3 1361ec779b9SMauro Carvalho Chehab 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 1371ec779b9SMauro Carvalho Chehab 4 5 6 7 1381ec779b9SMauro Carvalho Chehab 1391ec779b9SMauro Carvalho Chehab 1401ec779b9SMauro Carvalho Chehab8. If QUIRK_LSW32_IS_FIRST, QUIRK_LITTLE_ENDIAN and QUIRK_MSB_ON_THE_RIGHT 1411ec779b9SMauro Carvalho Chehab are set, it looks like this: 1421ec779b9SMauro Carvalho Chehab 1431ec779b9SMauro Carvalho Chehab:: 1441ec779b9SMauro Carvalho Chehab 1451ec779b9SMauro Carvalho Chehab 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 1461ec779b9SMauro Carvalho Chehab 0 1 2 3 1471ec779b9SMauro Carvalho Chehab 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 1481ec779b9SMauro Carvalho Chehab 4 5 6 7 1491ec779b9SMauro Carvalho Chehab 1501ec779b9SMauro Carvalho Chehab 1511ec779b9SMauro Carvalho ChehabWe always think of our offsets as if there were no quirk, and we translate 1521ec779b9SMauro Carvalho Chehabthem afterwards, before accessing the memory region. 1531ec779b9SMauro Carvalho Chehab 1541ec779b9SMauro Carvalho ChehabIntended use 1551ec779b9SMauro Carvalho Chehab------------ 1561ec779b9SMauro Carvalho Chehab 1571ec779b9SMauro Carvalho ChehabDrivers that opt to use this API first need to identify which of the above 3 1581ec779b9SMauro Carvalho Chehabquirk combinations (for a total of 8) match what the hardware documentation 1591ec779b9SMauro Carvalho Chehabdescribes. Then they should wrap the packing() function, creating a new 1601ec779b9SMauro Carvalho Chehabxxx_packing() that calls it using the proper QUIRK_* one-hot bits set. 1611ec779b9SMauro Carvalho Chehab 1621ec779b9SMauro Carvalho ChehabThe packing() function returns an int-encoded error code, which protects the 1631ec779b9SMauro Carvalho Chehabprogrammer against incorrect API use. The errors are not expected to occur 164*1f26c8b7SRandy Dunlapduring runtime, therefore it is reasonable for xxx_packing() to return void 1651ec779b9SMauro Carvalho Chehaband simply swallow those errors. Optionally it can dump stack or print the 1661ec779b9SMauro Carvalho Chehaberror description. 167