← Documents Documentation/core-api/packing.rst GitHub 원문 ↗

Linux 6.18.37 · Core API

Generic bitfield packing and unpacking functions

CPU와 hardware의 endian 및 register layout 차이를 추상화하는 bitfield packing API, 세 quirk의 여덟 조합과 fields 기반 bulk 변환을 설명합니다.

Source pathDocumentation/core-api/packing.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

packing.rst:1-345

Packing API는 CPU가 이해하는 `u64` bit numbering을 byte 단위 memory access로 변환해 CPU와 hardware endianness mismatch를 피합니다. 세 quirk는 byte 내부 bit 반전, 4-byte word 내부 byte mirror, least-significant 32-bit word 우선 배치를 각각 표현합니다.

Offset은 quirk가 없는 logical numbering으로 정의하고 실제 memory access 직전에 변환합니다. Buffer 길이가 4의 배수가 아니면 most-significant group을 실제 octet 수만큼 논리적으로 줄여 bitfield discontinuity를 방지합니다.

Deprecated `packing()`보다 const-correct `pack()`과 `unpack()`을 사용해야 합니다. Field가 많다면 compile-time type dispatch와 `BUILD_BUG_ON` 검사를 제공하고 code footprint도 줄이는 `pack_fields()`와 `unpack_fields()`가 적합합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 ================================================
2 Generic bitfield packing and unpacking functions
3 ================================================
4
5 Problem statement
6 -----------------
7
8 When working with hardware, one has to choose between several approaches of
9 interfacing with it.
10 One can memory-map a pointer to a carefully crafted struct over the hardware
11 device's memory region, and access its fields as struct members (potentially
12 declared as bitfields). But writing code this way would make it less portable,
13 due to potential endianness mismatches between the CPU and the hardware device.
14 Additionally, one has to pay close attention when translating register
15 definitions from the hardware documentation into bit field indices for the
16 structs. Also, some hardware (typically networking equipment) tends to group
17 its register fields in ways that violate any reasonable word boundaries
18 (sometimes even 64 bit ones). This creates the inconvenience of having to
19 define "high" and "low" portions of register fields within the struct.
20 A more robust alternative to struct field definitions would be to extract the
21 required fields by shifting the appropriate number of bits. But this would
22 still not protect from endianness mismatches, except if all memory accesses
23 were performed byte-by-byte. Also the code can easily get cluttered, and the
24 high-level idea might get lost among the many bit shifts required.
25 Many drivers take the bit-shifting approach and then attempt to reduce the
26 clutter with tailored macros, but more often than not these macros take
27 shortcuts that still prevent the code from being truly portable.
28
29 The solution
30 ------------
31
32 This API deals with 2 basic operations:
33
34 - Packing a CPU-usable number into a memory buffer (with hardware
35 constraints/quirks)
36 - Unpacking a memory buffer (which has hardware constraints/quirks)
37 into a CPU-usable number.
38
39 The API offers an abstraction over said hardware constraints and quirks,
40 over CPU endianness and therefore between possible mismatches between
41 the two.
42
43 The basic unit of these API functions is the u64. From the CPU's
44 perspective, bit 63 always means bit offset 7 of byte 7, albeit only
45 logically. The question is: where do we lay this bit out in memory?
46
47 The following examples cover the memory layout of a packed u64 field.
48 The byte offsets in the packed buffer are always implicitly 0, 1, ... 7.
49 What the examples show is where the logical bytes and bits sit.
50
51 1. Normally (no quirks), we would do it like this:
52
53 ::
54
55 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
56 7 6 5 4
57 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
58 3 2 1 0
59
60 That is, the MSByte (7) of the CPU-usable u64 sits at memory offset 0, and the
61 LSByte (0) of the u64 sits at memory offset 7.
62 This corresponds to what most folks would regard to as "big endian", where
63 bit i corresponds to the number 2^i. This is also referred to in the code
64 comments as "logical" notation.
65
66
67 2. If QUIRK_MSB_ON_THE_RIGHT is set, we do it like this:
68
69 ::
70
71 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
72 7 6 5 4
73 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
74 3 2 1 0
75
76 That is, QUIRK_MSB_ON_THE_RIGHT does not affect byte positioning, but
77 inverts bit offsets inside a byte.
78
79
80 3. If QUIRK_LITTLE_ENDIAN is set, we do it like this:
81
82 ::
83
84 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
85 4 5 6 7
86 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
87 0 1 2 3
88
89 Therefore, QUIRK_LITTLE_ENDIAN means that inside the memory region, every
90 byte from each 4-byte word is placed at its mirrored position compared to
91 the boundary of that word.
92
93 4. If QUIRK_MSB_ON_THE_RIGHT and QUIRK_LITTLE_ENDIAN are both set, we do it
94 like this:
95
96 ::
97
98 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
99 4 5 6 7
100 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
101 0 1 2 3
102
103
104 5. If just QUIRK_LSW32_IS_FIRST is set, we do it like this:
105
106 ::
107
108 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
109 3 2 1 0
110 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
111 7 6 5 4
112
113 In this case the 8 byte memory region is interpreted as follows: first
114 4 bytes correspond to the least significant 4-byte word, next 4 bytes to
115 the more significant 4-byte word.
116
117
118 6. If QUIRK_LSW32_IS_FIRST and QUIRK_MSB_ON_THE_RIGHT are set, we do it like
119 this:
120
121 ::
122
123 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
124 3 2 1 0
125 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
126 7 6 5 4
127
128
129 7. If QUIRK_LSW32_IS_FIRST and QUIRK_LITTLE_ENDIAN are set, it looks like
130 this:
131
132 ::
133
134 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
135 0 1 2 3
136 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
137 4 5 6 7
138
139
140 8. If QUIRK_LSW32_IS_FIRST, QUIRK_LITTLE_ENDIAN and QUIRK_MSB_ON_THE_RIGHT
141 are set, it looks like this:
142
143 ::
144
145 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
146 0 1 2 3
147 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
148 4 5 6 7
149
150
151 We always think of our offsets as if there were no quirk, and we translate
152 them afterwards, before accessing the memory region.
153
154 Note on buffer lengths not multiple of 4
155 ----------------------------------------
156
157 To deal with memory layout quirks where groups of 4 bytes are laid out "little
158 endian" relative to each other, but "big endian" within the group itself, the
159 concept of groups of 4 bytes is intrinsic to the packing API (not to be
160 confused with the memory access, which is performed byte by byte, though).
161
162 With buffer lengths not multiple of 4, this means one group will be incomplete.
163 Depending on the quirks, this may lead to discontinuities in the bit fields
164 accessible through the buffer. The packing API assumes discontinuities were not
165 the intention of the memory layout, so it avoids them by effectively logically
166 shortening the most significant group of 4 octets to the number of octets
167 actually available.
168
169 Example with a 31 byte sized buffer given below. Physical buffer offsets are
170 implicit, and increase from left to right within a group, and from top to
171 bottom within a column.
172
173 No quirks:
174
175 ::
176
177 31 29 28 | Group 7 (most significant)
178 27 26 25 24 | Group 6
179 23 22 21 20 | Group 5
180 19 18 17 16 | Group 4
181 15 14 13 12 | Group 3
182 11 10 9 8 | Group 2
183 7 6 5 4 | Group 1
184 3 2 1 0 | Group 0 (least significant)
185
186 QUIRK_LSW32_IS_FIRST:
187
188 ::
189
190 3 2 1 0 | Group 0 (least significant)
191 7 6 5 4 | Group 1
192 11 10 9 8 | Group 2
193 15 14 13 12 | Group 3
194 19 18 17 16 | Group 4
195 23 22 21 20 | Group 5
196 27 26 25 24 | Group 6
197 30 29 28 | Group 7 (most significant)
198
199 QUIRK_LITTLE_ENDIAN:
200
201 ::
202
203 30 28 29 | Group 7 (most significant)
204 24 25 26 27 | Group 6
205 20 21 22 23 | Group 5
206 16 17 18 19 | Group 4
207 12 13 14 15 | Group 3
208 8 9 10 11 | Group 2
209 4 5 6 7 | Group 1
210 0 1 2 3 | Group 0 (least significant)
211
212 QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST:
213
214 ::
215
216 0 1 2 3 | Group 0 (least significant)
217 4 5 6 7 | Group 1
218 8 9 10 11 | Group 2
219 12 13 14 15 | Group 3
220 16 17 18 19 | Group 4
221 20 21 22 23 | Group 5
222 24 25 26 27 | Group 6
223 28 29 30 | Group 7 (most significant)
224
225 Intended use
226 ------------
227
228 Drivers that opt to use this API first need to identify which of the above 3
229 quirk combinations (for a total of 8) match what the hardware documentation
230 describes.
231
232 There are 3 supported usage patterns, detailed below.
233
234 packing()
235 ^^^^^^^^^
236
237 This API function is deprecated.
238
239 The packing() function returns an int-encoded error code, which protects the
240 programmer against incorrect API use. The errors are not expected to occur
241 during runtime, therefore it is reasonable to wrap packing() into a custom
242 function which returns void and swallows those errors. Optionally it can
243 dump stack or print the error description.
244
245 .. code-block:: c
246
247 void my_packing(void *buf, u64 *val, int startbit, int endbit,
248 size_t len, enum packing_op op)
249 {
250 int err;
251
252 /* Adjust quirks accordingly */
253 err = packing(buf, val, startbit, endbit, len, op, QUIRK_LSW32_IS_FIRST);
254 if (likely(!err))
255 return;
256
257 if (err == -EINVAL) {
258 pr_err("Start bit (%d) expected to be larger than end (%d)\n",
259 startbit, endbit);
260 } else if (err == -ERANGE) {
261 if ((startbit - endbit + 1) > 64)
262 pr_err("Field %d-%d too large for 64 bits!\n",
263 startbit, endbit);
264 else
265 pr_err("Cannot store %llx inside bits %d-%d (would truncate)\n",
266 *val, startbit, endbit);
267 }
268 dump_stack();
269 }
270
271 pack() and unpack()
272 ^^^^^^^^^^^^^^^^^^^
273
274 These are const-correct variants of packing(), and eliminate the last "enum
275 packing_op op" argument.
276
277 Calling pack(...) is equivalent, and preferred, to calling packing(..., PACK).
278
279 Calling unpack(...) is equivalent, and preferred, to calling packing(..., UNPACK).
280
281 pack_fields() and unpack_fields()
282 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
283
284 The library exposes optimized functions for the scenario where there are many
285 fields represented in a buffer, and it encourages consumer drivers to avoid
286 repetitive calls to pack() and unpack() for each field, but instead use
287 pack_fields() and unpack_fields(), which reduces the code footprint.
288
289 These APIs use field definitions in arrays of ``struct packed_field_u8`` or
290 ``struct packed_field_u16``, allowing consumer drivers to minimize the size
291 of these arrays according to their custom requirements.
292
293 The pack_fields() and unpack_fields() API functions are actually macros which
294 automatically select the appropriate function at compile time, based on the
295 type of the fields array passed in.
296
297 An additional benefit over pack() and unpack() is that sanity checks on the
298 field definitions are handled at compile time with ``BUILD_BUG_ON`` rather
299 than only when the offending code is executed. These functions return void and
300 wrapping them to handle unexpected errors is not necessary.
301
302 It is recommended, but not required, that you wrap your packed buffer into a
303 structured type with a fixed size. This generally makes it easier for the
304 compiler to enforce that the correct size buffer is used.
305
306 Here is an example of how to use the fields APIs:
307
308 .. code-block:: c
309
310 /* Ordering inside the unpacked structure is flexible and can be different
311 * from the packed buffer. Here, it is optimized to reduce padding.
312 */
313 struct data {
314 u64 field3;
315 u32 field4;
316 u16 field1;
317 u8 field2;
318 };
319
320 #define SIZE 13
321
322 typedef struct __packed { u8 buf[SIZE]; } packed_buf_t;
323
324 static const struct packed_field_u8 fields[] = {
325 PACKED_FIELD(100, 90, struct data, field1),
326 PACKED_FIELD(90, 87, struct data, field2),
327 PACKED_FIELD(86, 30, struct data, field3),
328 PACKED_FIELD(29, 0, struct data, field4),
329 };
330
331 void unpack_your_data(const packed_buf_t *buf, struct data *unpacked)
332 {
333 BUILD_BUG_ON(sizeof(*buf) != SIZE;
334
335 unpack_fields(buf, sizeof(*buf), unpacked, fields,
336 QUIRK_LITTLE_ENDIAN);
337 }
338
339 void pack_your_data(const struct data *unpacked, packed_buf_t *buf)
340 {
341 BUILD_BUG_ON(sizeof(*buf) != SIZE;
342
343 pack_fields(buf, sizeof(*buf), unpacked, fields,
344 QUIRK_LITTLE_ENDIAN);
345 }
346

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

Hardware bitfield 표현의 문제

1-28

Generic bitfield packing and unpacking functions

문제 정의 (Problem statement)

Hardware와 작업할 때는 여러 interface 방식 중 하나를 선택해야 합니다. 정교하게 만든 struct pointer를 hardware device의 memory region에 map하고, bitfield로 선언할 수도 있는 member를 통해 field에 접근할 수 있습니다. 하지만 CPU와 hardware device의 endianness가 다를 수 있어 portability가 떨어집니다.

Hardware 문서의 register definition을 struct bitfield index로 옮길 때도 세심한 주의가 필요합니다. 특히 networking 장비 같은 hardware는 합리적인 word boundary, 때로는 64-bit boundary까지 위반하는 방식으로 register field를 묶습니다. 그러면 struct 안에서 register field의 high와 low 부분을 따로 정의해야 하는 불편이 생깁니다.

Struct field 대신 필요한 bit 수만큼 shift하여 field를 추출하는 방식이 더 견고할 수 있습니다. 그러나 모든 memory access를 byte 단위로 수행하지 않는 한 endianness mismatch를 막지는 못합니다. 많은 bit shift 때문에 code가 복잡해지고 high-level 의도가 묻히기도 쉽습니다.

많은 driver가 bit-shift 방식을 사용한 뒤 custom macro로 복잡함을 줄이려 하지만, 이 macro도 대개 shortcut을 택해 code가 완전히 portable해지는 것을 막습니다.

Packing API가 제공하는 추상화

29-50

해결책 (The solution)

이 API는 두 가지 기본 operation을 다룹니다.

  • CPU가 사용할 수 있는 숫자를 hardware constraint와 quirk를 적용하여 memory buffer에 packing합니다.
  • Hardware constraint와 quirk가 적용된 memory buffer를 CPU가 사용할 수 있는 숫자로 unpacking합니다.

API는 hardware constraint와 quirk, CPU endianness, 그리고 둘 사이에서 생길 수 있는 mismatch를 추상화합니다.

이 API function의 기본 단위는 `u64`입니다. CPU 관점에서 bit 63은 논리적으로 항상 byte 7의 bit offset 7을 뜻합니다. 핵심 질문은 이 bit를 memory의 어느 위치에 놓는가입니다.

다음 예제는 packed `u64` field의 memory layout을 설명합니다. Packed buffer의 byte offset은 항상 암묵적으로 0, 1부터 7까지이며, 그림은 logical byte와 bit가 놓이는 위치를 보여 줍니다.

Quirk가 없는 기본 layout

51-66

1. Quirk가 없을 때의 일반적인 layout입니다.

기본 big-endian logical layout
physical offset01234567
logical byte76543210
bit orderMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSB

Packed buffer의 physical byte offset별 logical byte와 byte 내부 bit 진행 방향입니다.

CPU가 사용하는 `u64`의 MSByte인 7은 memory offset 0에 있고 LSByte인 0은 memory offset 7에 있습니다. 이는 bit `i`가 숫자 `2^i`에 대응하는 일반적인 big-endian 형태이며 code comment에서는 logical notation이라고도 부릅니다.

QUIRK_MSB_ON_THE_RIGHT layout

67-79

2. `QUIRK_MSB_ON_THE_RIGHT`를 설정한 layout입니다.

MSB-on-the-right layout
physical offset01234567
logical byte76543210
bit orderLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSB

Packed buffer의 physical byte offset별 logical byte와 byte 내부 bit 진행 방향입니다.

`QUIRK_MSB_ON_THE_RIGHT`는 byte 위치에는 영향을 주지 않고 byte 내부의 bit offset을 반전합니다.

QUIRK_LITTLE_ENDIAN layout

80-92

3. `QUIRK_LITTLE_ENDIAN`을 설정한 layout입니다.

4-byte word 내부 byte mirror layout
physical offset01234567
logical byte45670123
bit orderMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSB

Packed buffer의 physical byte offset별 logical byte와 byte 내부 bit 진행 방향입니다.

`QUIRK_LITTLE_ENDIAN`은 memory region의 각 4-byte word 안에서 모든 byte를 word boundary에 대해 mirror된 위치에 배치합니다.

MSB-right와 little-endian 조합

93-103

4. `QUIRK_MSB_ON_THE_RIGHT`와 `QUIRK_LITTLE_ENDIAN`을 모두 설정한 layout입니다.

Byte mirror와 bit reversal 조합
physical offset01234567
logical byte45670123
bit orderLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSB

Packed buffer의 physical byte offset별 logical byte와 byte 내부 bit 진행 방향입니다.

QUIRK_LSW32_IS_FIRST layout

104-117

5. `QUIRK_LSW32_IS_FIRST`만 설정한 layout입니다.

Least-significant 32-bit word 우선 layout
physical offset01234567
logical byte32107654
bit orderMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSB

Packed buffer의 physical byte offset별 logical byte와 byte 내부 bit 진행 방향입니다.

8-byte memory region의 첫 4 byte는 least-significant 4-byte word에 대응하고 다음 4 byte는 more-significant 4-byte word에 대응합니다.

LSW-first와 MSB-right 조합

118-128

6. `QUIRK_LSW32_IS_FIRST`와 `QUIRK_MSB_ON_THE_RIGHT`를 설정한 layout입니다.

LSW-first와 bit reversal 조합
physical offset01234567
logical byte32107654
bit orderLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSB

Packed buffer의 physical byte offset별 logical byte와 byte 내부 bit 진행 방향입니다.

LSW-first와 little-endian 조합

129-139

7. `QUIRK_LSW32_IS_FIRST`와 `QUIRK_LITTLE_ENDIAN`을 설정한 layout입니다.

LSW-first와 byte mirror 조합
physical offset01234567
logical byte01234567
bit orderMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSBMSB→LSB

Packed buffer의 physical byte offset별 logical byte와 byte 내부 bit 진행 방향입니다.

세 quirk를 모두 적용한 layout

140-153

8. `QUIRK_LSW32_IS_FIRST`, `QUIRK_LITTLE_ENDIAN`, `QUIRK_MSB_ON_THE_RIGHT`를 모두 설정한 layout입니다.

LSW-first, byte mirror, bit reversal 조합
physical offset01234567
logical byte01234567
bit orderLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSBLSB→MSB

Packed buffer의 physical byte offset별 logical byte와 byte 내부 bit 진행 방향입니다.

Offset은 항상 quirk가 없는 것처럼 생각하고, memory region에 접근하기 직전에 quirk에 맞춰 변환합니다.

4의 배수가 아닌 buffer 길이

154-224

4의 배수가 아닌 buffer 길이에 관한 참고 사항

4-byte group끼리는 little-endian으로, group 내부는 big-endian으로 배치되는 memory layout quirk를 처리하기 위해 4-byte group 개념은 packing API에 내재합니다. 실제 memory access는 byte 단위라는 점과 혼동하면 안 됩니다.

Buffer 길이가 4의 배수가 아니면 한 group이 불완전합니다. Quirk 조합에 따라 buffer를 통해 접근할 수 있는 bitfield가 불연속적일 수 있습니다. Packing API는 이런 불연속이 의도된 layout이 아니라고 보고, most-significant 4-octet group을 실제 사용 가능한 octet 수만큼 논리적으로 줄여 불연속을 피합니다.

다음은 31-byte buffer 예제입니다. Physical buffer offset은 암묵적으로 group 안에서 왼쪽에서 오른쪽으로, column 안에서 위에서 아래로 증가합니다.

Quirk가 없는 경우입니다.

31-byte 기본 layout
groupslot 0slot 1slot 2slot 3
Group 7 (most significant)-312928
Group 627262524
Group 523222120
Group 419181716
Group 315141312
Group 2111098
Group 17654
Group 0 (least significant)3210

31-byte buffer에서 physical offset이 왼쪽에서 오른쪽, 위에서 아래로 증가할 때 각 group에 놓이는 logical octet입니다.

`QUIRK_LSW32_IS_FIRST`를 적용한 경우입니다.

31-byte LSW-first layout
groupslot 0slot 1slot 2slot 3
Group 0 (least significant)3210
Group 17654
Group 2111098
Group 315141312
Group 419181716
Group 523222120
Group 627262524
Group 7 (most significant)302928-

31-byte buffer에서 physical offset이 왼쪽에서 오른쪽, 위에서 아래로 증가할 때 각 group에 놓이는 logical octet입니다.

`QUIRK_LITTLE_ENDIAN`을 적용한 경우입니다.

31-byte little-endian group layout
groupslot 0slot 1slot 2slot 3
Group 7 (most significant)-302829
Group 624252627
Group 520212223
Group 416171819
Group 312131415
Group 2891011
Group 14567
Group 0 (least significant)0123

31-byte buffer에서 physical offset이 왼쪽에서 오른쪽, 위에서 아래로 증가할 때 각 group에 놓이는 logical octet입니다.

`QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST`를 적용한 경우입니다.

31-byte little-endian과 LSW-first 조합
groupslot 0slot 1slot 2slot 3
Group 0 (least significant)0123
Group 14567
Group 2891011
Group 312131415
Group 416171819
Group 520212223
Group 624252627
Group 7 (most significant)282930-

31-byte buffer에서 physical offset이 왼쪽에서 오른쪽, 위에서 아래로 증가할 때 각 group에 놓이는 logical octet입니다.

Deprecated packing() 사용 pattern

225-270

의도된 사용법 (Intended use)

이 API를 선택한 driver는 먼저 hardware 문서의 layout과 일치하는 세 quirk 조합, 총 여덟 경우 중 하나를 식별해야 합니다. 지원하는 사용 pattern은 세 가지이며 아래에서 설명합니다.

packing()

이 API function은 deprecated 상태입니다.

`packing()`은 잘못된 API 사용으로부터 programmer를 보호하는 int encoded error code를 반환합니다. Runtime에는 error가 발생하지 않을 것으로 기대하므로 `packing()`을 custom void function으로 감싸 error를 무시할 수 있습니다. 선택적으로 stack을 dump하거나 error 설명을 출력할 수 있습니다.

void my_packing(void *buf, u64 *val, int startbit, int endbit,
                size_t len, enum packing_op op)
{
        int err;

        /* Adjust quirks accordingly */
        err = packing(buf, val, startbit, endbit, len, op, QUIRK_LSW32_IS_FIRST);
        if (likely(!err))
                return;

        if (err == -EINVAL) {
                pr_err("Start bit (%d) expected to be larger than end (%d)\n",
                       startbit, endbit);
        } else if (err == -ERANGE) {
                if ((startbit - endbit + 1) > 64)
                        pr_err("Field %d-%d too large for 64 bits!\n",
                               startbit, endbit);
                else
                        pr_err("Cannot store %llx inside bits %d-%d (would truncate)\n",
                               *val, startbit, endbit);
        }
        dump_stack();
}

Const-correct pack()과 unpack()

271-280

pack() and unpack()

이들은 `packing()`의 const-correct variant이며 마지막 `enum packing_op op` argument를 제거합니다.

`pack(...)` 호출은 `packing(..., PACK)`과 같고 더 권장됩니다. `unpack(...)` 호출은 `packing(..., UNPACK)`과 같고 더 권장됩니다.

pack_fields()와 unpack_fields()

281-345

pack_fields() and unpack_fields()

Library는 buffer에 많은 field가 있는 상황을 위한 optimized function을 제공합니다. Consumer driver가 field마다 `pack()`과 `unpack()`을 반복 호출하지 말고 code footprint를 줄이는 `pack_fields()`와 `unpack_fields()`를 사용하도록 권장합니다.

이 API는 `struct packed_field_u8` 또는 `struct packed_field_u16` array의 field definition을 사용하므로 consumer driver는 요구 사항에 맞춰 array 크기를 최소화할 수 있습니다.

`pack_fields()`와 `unpack_fields()`는 실제로 macro이며 전달된 fields array의 type을 기준으로 compile time에 적절한 function을 자동 선택합니다.

`pack()`과 `unpack()`보다 나은 또 다른 점은 field definition sanity check가 문제가 되는 code를 실행할 때가 아니라 compile time에 `BUILD_BUG_ON`으로 처리된다는 것입니다. 이 function은 void를 반환하므로 예상치 못한 error를 처리하기 위해 감쌀 필요가 없습니다.

필수는 아니지만 packed buffer를 고정 크기의 structured type으로 감싸는 것이 권장됩니다. 그러면 compiler가 올바른 크기의 buffer 사용을 강제하기 쉽습니다.

다음은 fields API 사용 예제입니다.

/* Ordering inside the unpacked structure is flexible and can be different
 * from the packed buffer. Here, it is optimized to reduce padding.
 */
struct data {
     u64 field3;
     u32 field4;
     u16 field1;
     u8 field2;
};

#define SIZE 13

typedef struct __packed { u8 buf[SIZE]; } packed_buf_t;

static const struct packed_field_u8 fields[] = {
        PACKED_FIELD(100, 90, struct data, field1),
        PACKED_FIELD(90, 87, struct data, field2),
        PACKED_FIELD(86, 30, struct data, field3),
        PACKED_FIELD(29, 0, struct data, field4),
};

void unpack_your_data(const packed_buf_t *buf, struct data *unpacked)
{
        BUILD_BUG_ON(sizeof(*buf) != SIZE;

        unpack_fields(buf, sizeof(*buf), unpacked, fields,
                      QUIRK_LITTLE_ENDIAN);
}

void pack_your_data(const struct data *unpacked, packed_buf_t *buf)
{
        BUILD_BUG_ON(sizeof(*buf) != SIZE;

        pack_fields(buf, sizeof(*buf), unpacked, fields,
                    QUIRK_LITTLE_ENDIAN);
}

Unpacked `struct data`의 member 순서는 packed buffer와 달라도 되며 예제는 padding을 줄이도록 정렬합니다. `packed_buf_t`는 13-byte fixed-size buffer이고 `PACKED_FIELD` array는 logical bit range와 destination member를 연결합니다.

`unpack_your_data()`와 `pack_your_data()`는 `BUILD_BUG_ON`으로 buffer size를 확인하고 `QUIRK_LITTLE_ENDIAN`을 적용해 모든 field를 한 번에 변환합니다.