← Documents Documentation/arch/sparc/oradax/oracle-dax.rst GitHub 원문 ↗

Linux 6.18.37 · Architecture

Oracle Data Analytics Accelerator (DAX)

SPARC M7/M8의 DAX coprocessor를 Linux user space와 kernel에서 사용하는 driver API, memory 제약, CCB 제출·완료 처리, Scan command 예제를 설명합니다.

Source pathDocumentation/arch/sparc/oradax/oracle-dax.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

요약과 해설

oracle-dax.rst:1-445

DAX는 SPARC M7/M8에서 CPU cache와 physical memory에 직접 접근해 data-stream 연산을 수행하는 coprocessor입니다. user application은 `write()`/`pwrite()`로 CCB를 제출하고 read-only로 mmap한 128-byte Completion Area를 monitored load와 `mwait`으로 polling합니다. 완료 interrupt 없이 user level에서 즉시 실행을 재개하도록 설계된 것이 핵심입니다.

DAX에는 I/O TLB나 scatter/gather가 없으므로 모든 buffer가 물리적으로 연속되어야 하며 operation은 virtual page boundary를 넘지 못합니다. user driver는 address type을 virtual로 제한해 process 소유 memory만 접근하게 하고, kernel은 Completion Area를 직접 할당해 `sun4v_ccb_submit()` hypercall을 호출합니다.

예제는 1-bit input vector에서 0을 찾는 Scan CCB를 구성해 반전 bitmap을 만들고, 제출 실패 status 조회, ASI `0x84` monitored load, `%asr28` `mwait`, `CCB_DEQUEUE` resource 회수까지 전체 수명주기를 보여 줍니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 =======================================
2 Oracle Data Analytics Accelerator (DAX)
3 =======================================
4
5 DAX is a coprocessor which resides on the SPARC M7 (DAX1) and M8
6 (DAX2) processor chips, and has direct access to the CPU's L3 caches
7 as well as physical memory. It can perform several operations on data
8 streams with various input and output formats. A driver provides a
9 transport mechanism and has limited knowledge of the various opcodes
10 and data formats. A user space library provides high level services
11 and translates these into low level commands which are then passed
12 into the driver and subsequently the Hypervisor and the coprocessor.
13 The library is the recommended way for applications to use the
14 coprocessor, and the driver interface is not intended for general use.
15 This document describes the general flow of the driver, its
16 structures, and its programmatic interface. It also provides example
17 code sufficient to write user or kernel applications that use DAX
18 functionality.
19
20 The user library is open source and available at:
21
22 https://oss.oracle.com/git/gitweb.cgi?p=libdax.git
23
24 The Hypervisor interface to the coprocessor is described in detail in
25 the accompanying document, dax-hv-api.txt, which is a plain text
26 excerpt of the (Oracle internal) "UltraSPARC Virtual Machine
27 Specification" version 3.0.20+15, dated 2017-09-25.
28
29
30 High Level Overview
31 ===================
32
33 A coprocessor request is described by a Command Control Block
34 (CCB). The CCB contains an opcode and various parameters. The opcode
35 specifies what operation is to be done, and the parameters specify
36 options, flags, sizes, and addresses. The CCB (or an array of CCBs)
37 is passed to the Hypervisor, which handles queueing and scheduling of
38 requests to the available coprocessor execution units. A status code
39 returned indicates if the request was submitted successfully or if
40 there was an error. One of the addresses given in each CCB is a
41 pointer to a "completion area", which is a 128 byte memory block that
42 is written by the coprocessor to provide execution status. No
43 interrupt is generated upon completion; the completion area must be
44 polled by software to find out when a transaction has finished, but
45 the M7 and later processors provide a mechanism to pause the virtual
46 processor until the completion status has been updated by the
47 coprocessor. This is done using the monitored load and mwait
48 instructions, which are described in more detail later. The DAX
49 coprocessor was designed so that after a request is submitted, the
50 kernel is no longer involved in the processing of it. The polling is
51 done at the user level, which results in almost zero latency between
52 completion of a request and resumption of execution of the requesting
53 thread.
54
55
56 Addressing Memory
57 =================
58
59 The kernel does not have access to physical memory in the Sun4v
60 architecture, as there is an additional level of memory virtualization
61 present. This intermediate level is called "real" memory, and the
62 kernel treats this as if it were physical. The Hypervisor handles the
63 translations between real memory and physical so that each logical
64 domain (LDOM) can have a partition of physical memory that is isolated
65 from that of other LDOMs. When the kernel sets up a virtual mapping,
66 it specifies a virtual address and the real address to which it should
67 be mapped.
68
69 The DAX coprocessor can only operate on physical memory, so before a
70 request can be fed to the coprocessor, all the addresses in a CCB must
71 be converted into physical addresses. The kernel cannot do this since
72 it has no visibility into physical addresses. So a CCB may contain
73 either the virtual or real addresses of the buffers or a combination
74 of them. An "address type" field is available for each address that
75 may be given in the CCB. In all cases, the Hypervisor will translate
76 all the addresses to physical before dispatching to hardware. Address
77 translations are performed using the context of the process initiating
78 the request.
79
80
81 The Driver API
82 ==============
83
84 An application makes requests to the driver via the write() system
85 call, and gets results (if any) via read(). The completion areas are
86 made accessible via mmap(), and are read-only for the application.
87
88 The request may either be an immediate command or an array of CCBs to
89 be submitted to the hardware.
90
91 Each open instance of the device is exclusive to the thread that
92 opened it, and must be used by that thread for all subsequent
93 operations. The driver open function creates a new context for the
94 thread and initializes it for use. This context contains pointers and
95 values used internally by the driver to keep track of submitted
96 requests. The completion area buffer is also allocated, and this is
97 large enough to contain the completion areas for many concurrent
98 requests. When the device is closed, any outstanding transactions are
99 flushed and the context is cleaned up.
100
101 On a DAX1 system (M7), the device will be called "oradax1", while on a
102 DAX2 system (M8) it will be "oradax2". If an application requires one
103 or the other, it should simply attempt to open the appropriate
104 device. Only one of the devices will exist on any given system, so the
105 name can be used to determine what the platform supports.
106
107 The immediate commands are CCB_DEQUEUE, CCB_KILL, and CCB_INFO. For
108 all of these, success is indicated by a return value from write()
109 equal to the number of bytes given in the call. Otherwise -1 is
110 returned and errno is set.
111
112 CCB_DEQUEUE
113 -----------
114
115 Tells the driver to clean up resources associated with past
116 requests. Since no interrupt is generated upon the completion of a
117 request, the driver must be told when it may reclaim resources. No
118 further status information is returned, so the user should not
119 subsequently call read().
120
121 CCB_KILL
122 --------
123
124 Kills a CCB during execution. The CCB is guaranteed to not continue
125 executing once this call returns successfully. On success, read() must
126 be called to retrieve the result of the action.
127
128 CCB_INFO
129 --------
130
131 Retrieves information about a currently executing CCB. Note that some
132 Hypervisors might return 'notfound' when the CCB is in 'inprogress'
133 state. To ensure a CCB in the 'notfound' state will never be executed,
134 CCB_KILL must be invoked on that CCB. Upon success, read() must be
135 called to retrieve the details of the action.
136
137 Submission of an array of CCBs for execution
138 ---------------------------------------------
139
140 A write() whose length is a multiple of the CCB size is treated as a
141 submit operation. The file offset is treated as the index of the
142 completion area to use, and may be set via lseek() or using the
143 pwrite() system call. If -1 is returned then errno is set to indicate
144 the error. Otherwise, the return value is the length of the array that
145 was actually accepted by the coprocessor. If the accepted length is
146 equal to the requested length, then the submission was completely
147 successful and there is no further status needed; hence, the user
148 should not subsequently call read(). Partial acceptance of the CCB
149 array is indicated by a return value less than the requested length,
150 and read() must be called to retrieve further status information. The
151 status will reflect the error caused by the first CCB that was not
152 accepted, and status_data will provide additional data in some cases.
153
154 MMAP
155 ----
156
157 The mmap() function provides access to the completion area allocated
158 in the driver. Note that the completion area is not writeable by the
159 user process, and the mmap call must not specify PROT_WRITE.
160
161
162 Completion of a Request
163 =======================
164
165 The first byte in each completion area is the command status which is
166 updated by the coprocessor hardware. Software may take advantage of
167 new M7/M8 processor capabilities to efficiently poll this status byte.
168 First, a "monitored load" is achieved via a Load from Alternate Space
169 (ldxa, lduba, etc.) with ASI 0x84 (ASI_MONITOR_PRIMARY). Second, a
170 "monitored wait" is achieved via the mwait instruction (a write to
171 %asr28). This instruction is like pause in that it suspends execution
172 of the virtual processor for the given number of nanoseconds, but in
173 addition will terminate early when one of several events occur. If the
174 block of data containing the monitored location is modified, then the
175 mwait terminates. This causes software to resume execution immediately
176 (without a context switch or kernel to user transition) after a
177 transaction completes. Thus the latency between transaction completion
178 and resumption of execution may be just a few nanoseconds.
179
180
181 Application Life Cycle of a DAX Submission
182 ==========================================
183
184 - open dax device
185 - call mmap() to get the completion area address
186 - allocate a CCB and fill in the opcode, flags, parameters, addresses, etc.
187 - submit CCB via write() or pwrite()
188 - go into a loop executing monitored load + monitored wait and
189 terminate when the command status indicates the request is complete
190 (CCB_KILL or CCB_INFO may be used any time as necessary)
191 - perform a CCB_DEQUEUE
192 - call munmap() for completion area
193 - close the dax device
194
195
196 Memory Constraints
197 ==================
198
199 The DAX hardware operates only on physical addresses. Therefore, it is
200 not aware of virtual memory mappings and the discontiguities that may
201 exist in the physical memory that a virtual buffer maps to. There is
202 no I/O TLB or any scatter/gather mechanism. All buffers, whether input
203 or output, must reside in a physically contiguous region of memory.
204
205 The Hypervisor translates all addresses within a CCB to physical
206 before handing off the CCB to DAX. The Hypervisor determines the
207 virtual page size for each virtual address given, and uses this to
208 program a size limit for each address. This prevents the coprocessor
209 from reading or writing beyond the bound of the virtual page, even
210 though it is accessing physical memory directly. A simpler way of
211 saying this is that a DAX operation will never "cross" a virtual page
212 boundary. If an 8k virtual page is used, then the data is strictly
213 limited to 8k. If a user's buffer is larger than 8k, then a larger
214 page size must be used, or the transaction size will be truncated to
215 8k.
216
217 Huge pages. A user may allocate huge pages using standard interfaces.
218 Memory buffers residing on huge pages may be used to achieve much
219 larger DAX transaction sizes, but the rules must still be followed,
220 and no transaction will cross a page boundary, even a huge page. A
221 major caveat is that Linux on Sparc presents 8Mb as one of the huge
222 page sizes. Sparc does not actually provide a 8Mb hardware page size,
223 and this size is synthesized by pasting together two 4Mb pages. The
224 reasons for this are historical, and it creates an issue because only
225 half of this 8Mb page can actually be used for any given buffer in a
226 DAX request, and it must be either the first half or the second half;
227 it cannot be a 4Mb chunk in the middle, since that crosses a
228 (hardware) page boundary. Note that this entire issue may be hidden by
229 higher level libraries.
230
231
232 CCB Structure
233 -------------
234 A CCB is an array of 8 64-bit words. Several of these words provide
235 command opcodes, parameters, flags, etc., and the rest are addresses
236 for the completion area, output buffer, and various inputs::
237
238 struct ccb {
239 u64 control;
240 u64 completion;
241 u64 input0;
242 u64 access;
243 u64 input1;
244 u64 op_data;
245 u64 output;
246 u64 table;
247 };
248
249 See libdax/common/sys/dax1/dax1_ccb.h for a detailed description of
250 each of these fields, and see dax-hv-api.txt for a complete description
251 of the Hypervisor API available to the guest OS (ie, Linux kernel).
252
253 The first word (control) is examined by the driver for the following:
254 - CCB version, which must be consistent with hardware version
255 - Opcode, which must be one of the documented allowable commands
256 - Address types, which must be set to "virtual" for all the addresses
257 given by the user, thereby ensuring that the application can
258 only access memory that it owns
259
260
261 Example Code
262 ============
263
264 The DAX is accessible to both user and kernel code. The kernel code
265 can make hypercalls directly while the user code must use wrappers
266 provided by the driver. The setup of the CCB is nearly identical for
267 both; the only difference is in preparation of the completion area. An
268 example of user code is given now, with kernel code afterwards.
269
270 In order to program using the driver API, the file
271 arch/sparc/include/uapi/asm/oradax.h must be included.
272
273 First, the proper device must be opened. For M7 it will be
274 /dev/oradax1 and for M8 it will be /dev/oradax2. The simplest
275 procedure is to attempt to open both, as only one will succeed::
276
277 fd = open("/dev/oradax1", O_RDWR);
278 if (fd < 0)
279 fd = open("/dev/oradax2", O_RDWR);
280 if (fd < 0)
281 /* No DAX found */
282
283 Next, the completion area must be mapped::
284
285 completion_area = mmap(NULL, DAX_MMAP_LEN, PROT_READ, MAP_SHARED, fd, 0);
286
287 All input and output buffers must be fully contained in one hardware
288 page, since as explained above, the DAX is strictly constrained by
289 virtual page boundaries. In addition, the output buffer must be
290 64-byte aligned and its size must be a multiple of 64 bytes because
291 the coprocessor writes in units of cache lines.
292
293 This example demonstrates the DAX Scan command, which takes as input a
294 vector and a match value, and produces a bitmap as the output. For
295 each input element that matches the value, the corresponding bit is
296 set in the output.
297
298 In this example, the input vector consists of a series of single bits,
299 and the match value is 0. So each 0 bit in the input will produce a 1
300 in the output, and vice versa, which produces an output bitmap which
301 is the input bitmap inverted.
302
303 For details of all the parameters and bits used in this CCB, please
304 refer to section 36.2.1.3 of the DAX Hypervisor API document, which
305 describes the Scan command in detail::
306
307 ccb->control = /* Table 36.1, CCB Header Format */
308 (2L << 48) /* command = Scan Value */
309 | (3L << 40) /* output address type = primary virtual */
310 | (3L << 34) /* primary input address type = primary virtual */
311 /* Section 36.2.1, Query CCB Command Formats */
312 | (1 << 28) /* 36.2.1.1.1 primary input format = fixed width bit packed */
313 | (0 << 23) /* 36.2.1.1.2 primary input element size = 0 (1 bit) */
314 | (8 << 10) /* 36.2.1.1.6 output format = bit vector */
315 | (0 << 5) /* 36.2.1.3 First scan criteria size = 0 (1 byte) */
316 | (31 << 0); /* 36.2.1.3 Disable second scan criteria */
317
318 ccb->completion = 0; /* Completion area address, to be filled in by driver */
319
320 ccb->input0 = (unsigned long) input; /* primary input address */
321
322 ccb->access = /* Section 36.2.1.2, Data Access Control */
323 (2 << 24) /* Primary input length format = bits */
324 | (nbits - 1); /* number of bits in primary input stream, minus 1 */
325
326 ccb->input1 = 0; /* secondary input address, unused */
327
328 ccb->op_data = 0; /* scan criteria (value to be matched) */
329
330 ccb->output = (unsigned long) output; /* output address */
331
332 ccb->table = 0; /* table address, unused */
333
334 The CCB submission is a write() or pwrite() system call to the
335 driver. If the call fails, then a read() must be used to retrieve the
336 status::
337
338 if (pwrite(fd, ccb, 64, 0) != 64) {
339 struct ccb_exec_result status;
340 read(fd, &status, sizeof(status));
341 /* bail out */
342 }
343
344 After a successful submission of the CCB, the completion area may be
345 polled to determine when the DAX is finished. Detailed information on
346 the contents of the completion area can be found in section 36.2.2 of
347 the DAX HV API document::
348
349 while (1) {
350 /* Monitored Load */
351 __asm__ __volatile__("lduba [%1] 0x84, %0\n"
352 : "=r" (status)
353 : "r" (completion_area));
354
355 if (status) /* 0 indicates command in progress */
356 break;
357
358 /* MWAIT */
359 __asm__ __volatile__("wr %%g0, 1000, %%asr28\n" ::); /* 1000 ns */
360 }
361
362 A completion area status of 1 indicates successful completion of the
363 CCB and validity of the output bitmap, which may be used immediately.
364 All other non-zero values indicate error conditions which are
365 described in section 36.2.2::
366
367 if (completion_area[0] != 1) { /* section 36.2.2, 1 = command ran and succeeded */
368 /* completion_area[0] contains the completion status */
369 /* completion_area[1] contains an error code, see 36.2.2 */
370 }
371
372 After the completion area has been processed, the driver must be
373 notified that it can release any resources associated with the
374 request. This is done via the dequeue operation::
375
376 struct dax_command cmd;
377 cmd.command = CCB_DEQUEUE;
378 if (write(fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
379 /* bail out */
380 }
381
382 Finally, normal program cleanup should be done, i.e., unmapping
383 completion area, closing the dax device, freeing memory etc.
384
385 Kernel example
386 --------------
387
388 The only difference in using the DAX in kernel code is the treatment
389 of the completion area. Unlike user applications which mmap the
390 completion area allocated by the driver, kernel code must allocate its
391 own memory to use for the completion area, and this address and its
392 type must be given in the CCB::
393
394 ccb->control |= /* Table 36.1, CCB Header Format */
395 (3L << 32); /* completion area address type = primary virtual */
396
397 ccb->completion = (unsigned long) completion_area; /* Completion area address */
398
399 The dax submit hypercall is made directly. The flags used in the
400 ccb_submit call are documented in the DAX HV API in section 36.3.1/
401
402 ::
403
404 #include <asm/hypervisor.h>
405
406 hv_rv = sun4v_ccb_submit((unsigned long)ccb, 64,
407 HV_CCB_QUERY_CMD |
408 HV_CCB_ARG0_PRIVILEGED | HV_CCB_ARG0_TYPE_PRIMARY |
409 HV_CCB_VA_PRIVILEGED,
410 0, &bytes_accepted, &status_data);
411
412 if (hv_rv != HV_EOK) {
413 /* hv_rv is an error code, status_data contains */
414 /* potential additional status, see 36.3.1.1 */
415 }
416
417 After the submission, the completion area polling code is identical to
418 that in user land::
419
420 while (1) {
421 /* Monitored Load */
422 __asm__ __volatile__("lduba [%1] 0x84, %0\n"
423 : "=r" (status)
424 : "r" (completion_area));
425
426 if (status) /* 0 indicates command in progress */
427 break;
428
429 /* MWAIT */
430 __asm__ __volatile__("wr %%g0, 1000, %%asr28\n" ::); /* 1000 ns */
431 }
432
433 if (completion_area[0] != 1) { /* section 36.2.2, 1 = command ran and succeeded */
434 /* completion_area[0] contains the completion status */
435 /* completion_area[1] contains an error code, see 36.2.2 */
436 }
437
438 The output bitmap is ready for consumption immediately after the
439 completion status indicates success.
440
441 Excer[t from UltraSPARC Virtual Machine Specification
442 =====================================================
443
444 .. include:: dax-hv-api.txt
445 :literal:
446

3. 한국어 전문 번역

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

Oracle Data Analytics Accelerator

1-27

DAX는 SPARC M7의 DAX1과 M8의 DAX2 processor chip에 탑재되는 coprocessor로, CPU L3 cache와 physical memory에 직접 접근합니다. 여러 input/output format의 data stream에 다양한 연산을 수행할 수 있습니다.

driver는 transport mechanism을 제공하지만 opcode와 data format에 대해서는 제한적으로만 이해합니다. user-space library가 high-level service를 low-level command로 변환해 driver, Hypervisor, coprocessor 순으로 전달합니다. application에는 이 library 사용이 권장되며 driver interface는 일반 용도로 설계되지 않았습니다.

이 문서는 driver의 전체 처리 흐름, 자료 구조, programmatic interface를 설명하고 DAX 기능을 사용하는 user application과 kernel application을 작성할 수 있을 정도의 예제 코드를 제공합니다.

open source user library는 `https://oss.oracle.com/git/gitweb.cgi?p=libdax.git`에서 구할 수 있습니다. coprocessor의 Hypervisor interface는 함께 제공되는 `dax-hv-api.txt`에 자세히 설명되어 있으며, 이 파일은 2017-09-25자 Oracle 내부 문서 UltraSPARC Virtual Machine Specification version `3.0.20+15`의 plain-text 발췌본입니다.

CCB 제출과 비동기 완료 흐름

28-54

coprocessor request는 Command Control Block(CCB)으로 표현합니다. CCB의 opcode는 수행할 연산을 지정하고 parameter는 option, flag, size, address를 지정합니다. 단일 CCB 또는 CCB array를 Hypervisor에 넘기면 Hypervisor가 사용 가능한 coprocessor execution unit을 대상으로 queueing과 scheduling을 처리합니다. 반환 status code는 제출 성공 여부나 오류를 나타냅니다.

각 CCB의 address 중 하나는 128-byte memory block인 Completion Area를 가리킵니다. coprocessor가 이 영역에 execution status를 기록합니다. 완료 interrupt는 발생하지 않으므로 software가 transaction 종료 여부를 확인하도록 Completion Area를 polling해야 합니다.

M7 이후 processor는 monitored load와 `mwait` instruction으로 coprocessor가 completion status를 갱신할 때까지 virtual processor를 멈출 수 있습니다. request를 제출한 뒤 kernel은 처리에 더 관여하지 않고 user level에서 polling하므로 완료 시점부터 요청 thread가 실행을 재개할 때까지의 latency를 거의 0에 가깝게 줄일 수 있습니다.

Sun4v의 virtual·real·physical address

55-78

Sun4v architecture에는 memory virtualization level이 하나 더 있으므로 kernel은 physical memory에 직접 접근할 수 없습니다. 이 중간 계층을 real memory라 하며 kernel은 이를 physical memory처럼 취급합니다. Hypervisor는 real-to-physical translation을 맡아 각 logical domain(LDOM)의 physical memory partition을 다른 LDOM과 격리합니다. kernel이 virtual mapping을 설정할 때는 virtual address와 그 대상 real address를 지정합니다.

DAX coprocessor는 physical memory에서만 동작하므로 hardware에 request를 보내기 전에 CCB의 모든 address를 physical address로 변환해야 합니다. kernel은 physical address를 볼 수 없어 이 변환을 직접 수행할 수 없습니다.

따라서 CCB에는 buffer의 virtual address, real address 또는 두 종류의 조합이 들어갈 수 있으며 각 address에는 address type field가 있습니다. Hypervisor는 어떤 경우든 hardware dispatch 전에 모든 address를 physical address로 변환하고, request를 시작한 process의 context를 address translation에 사용합니다.

driver open context와 device 선택

79-110

application은 `write()` system call로 driver에 request를 보내고 결과가 있으면 `read()`로 받습니다. Completion Area는 `mmap()`으로 노출되며 application에서는 read-only입니다. request는 immediate command이거나 hardware에 제출할 CCB array일 수 있습니다.

device를 연 각 instance는 그 device를 연 thread에 독점적으로 귀속되며 이후 모든 operation도 같은 thread가 수행해야 합니다. driver open function은 thread용 context를 만들고 초기화합니다. 이 context에는 제출된 request를 추적하는 driver 내부 pointer와 value가 들어갑니다.

driver는 여러 concurrent request의 Completion Area를 담을 만큼 큰 completion-area buffer도 할당합니다. device를 닫으면 outstanding transaction을 flush하고 context를 정리합니다.

DAX1(M7) system의 device 이름은 `oradax1`, DAX2(M8) system은 `oradax2`입니다. 특정 version이 필요하면 해당 device를 열어 보면 됩니다. 한 system에는 둘 중 하나만 존재하므로 이름으로 platform 지원 수준을 판별할 수 있습니다.

immediate command는 `CCB_DEQUEUE`, `CCB_KILL`, `CCB_INFO`입니다. 모두 성공하면 `write()`가 전달한 byte 수와 같은 값을 반환하며, 실패하면 `-1`을 반환하고 `errno`를 설정합니다.

CCB_DEQUEUE·CCB_KILL·CCB_INFO

111-135
command동작성공 후 read()
`CCB_DEQUEUE`지난 request와 연결된 resource를 정리할 수 있다고 driver에 알립니다.추가 status가 없으므로 호출하지 않습니다.
`CCB_KILL`실행 중인 CCB를 중단하며 성공 반환 뒤에는 더 실행되지 않음을 보장합니다.action 결과를 가져오기 위해 호출해야 합니다.
`CCB_INFO`현재 실행 중인 CCB 정보를 조회합니다.action 세부 정보를 가져오기 위해 호출해야 합니다.

완료 interrupt가 없으므로 driver는 resource를 회수해도 되는 시점을 스스로 알 수 없습니다. application은 완료 처리를 마친 뒤 `CCB_DEQUEUE`를 명시적으로 수행해야 합니다.

일부 Hypervisor는 CCB가 `inprogress`인데도 `CCB_INFO`에 `notfound`를 반환할 수 있습니다. `notfound` 상태의 CCB가 이후 절대 실행되지 않도록 보장하려면 그 CCB에 `CCB_KILL`을 호출해야 합니다.

CCB array 제출과 mmap

136-159

길이가 CCB size의 배수인 `write()`는 submit operation으로 취급됩니다. file offset은 사용할 Completion Area index이며 `lseek()` 또는 `pwrite()`로 지정할 수 있습니다.

반환의미와 후속 처리
`-1``errno`가 오류를 나타냅니다.
요청 길이와 같은 값coprocessor가 array 전체를 받아 제출이 완전히 성공했습니다. 이후 `read()`를 호출하지 않습니다.
0 이상이지만 요청 길이보다 작은 값CCB array가 일부만 수락되었습니다. `read()`로 첫 미수락 CCB의 오류 status와 경우에 따라 `status_data`를 가져옵니다.

`mmap()`은 driver가 할당한 Completion Area에 대한 접근을 제공합니다. user process는 이 영역에 쓸 수 없으므로 mmap call에 `PROT_WRITE`를 지정하면 안 됩니다.

monitored load와 mwait로 완료 감지

160-178

각 Completion Area의 첫 byte는 coprocessor hardware가 갱신하는 command status입니다. software는 M7/M8 processor 기능으로 이 byte를 효율적으로 polling할 수 있습니다.

monitored load는 ASI `0x84`인 `ASI_MONITOR_PRIMARY`를 사용한 Load from Alternate Space(`ldxa`, `lduba` 등)로 수행합니다. monitored wait는 `%asr28`에 쓰는 `mwait` instruction으로 수행합니다.

`mwait`는 지정한 nanosecond 동안 virtual processor 실행을 멈춘다는 점에서 pause와 비슷하지만 여러 event 중 하나가 발생하면 일찍 끝납니다. 감시 위치를 포함하는 data block이 수정되면 즉시 종료되므로 transaction 완료 뒤 context switch나 kernel-to-user transition 없이 software가 실행을 재개합니다. 이 때문에 완료부터 재개까지의 latency가 불과 몇 nanosecond일 수 있습니다.

DAX 제출의 application 수명주기

179-193
  • DAX device를 엽니다.
  • `mmap()`을 호출해 Completion Area address를 얻습니다.
  • CCB를 할당하고 opcode, flag, parameter, address 등을 채웁니다.
  • `write()` 또는 `pwrite()`로 CCB를 제출합니다.
  • monitored load와 monitored wait를 반복하고 command status가 완료를 나타내면 끝냅니다. 필요하면 언제든 `CCB_KILL` 또는 `CCB_INFO`를 사용할 수 있습니다.
  • `CCB_DEQUEUE`를 수행합니다.
  • Completion Area에 `munmap()`을 호출합니다.
  • DAX device를 닫습니다.

물리 연속성과 page boundary 제약

194-229

DAX hardware는 physical address만 사용하므로 virtual memory mapping이나 virtual buffer가 매핑되는 physical memory의 불연속을 알지 못합니다. I/O TLB도 scatter/gather mechanism도 없습니다. input과 output을 포함한 모든 buffer는 physically contiguous memory region 안에 있어야 합니다.

Hypervisor는 CCB의 모든 address를 physical address로 바꾼 뒤 DAX에 넘깁니다. 각 virtual address의 virtual page size를 확인해 address별 size limit을 programming하므로 coprocessor가 physical memory에 직접 접근하더라도 virtual page 경계 밖을 읽거나 쓰지 못합니다.

즉 DAX operation은 virtual page boundary를 절대 넘지 않습니다. 8 KiB virtual page를 쓰면 data는 8 KiB로 엄격히 제한됩니다. user buffer가 더 크다면 더 큰 page size를 쓰지 않는 한 transaction size가 8 KiB로 잘립니다.

표준 interface로 huge page를 할당하면 훨씬 큰 DAX transaction을 수행할 수 있지만 huge page에서도 page boundary를 넘을 수 없다는 규칙은 그대로입니다.

Linux/SPARC가 제공하는 8 MiB huge page는 실제 8 MiB hardware page가 아니라 4 MiB page 두 개를 이어 붙여 합성한 것입니다. DAX request의 한 buffer는 앞쪽 또는 뒤쪽 4 MiB 절반만 쓸 수 있으며 hardware page boundary를 가로지르는 가운데 4 MiB 구간은 쓸 수 없습니다. high-level library가 이 제약을 감출 수도 있습니다.

CCB 구조와 driver 검증

230-258

CCB는 64-bit word 8개로 이루어진 array입니다. 일부 word에는 command opcode, parameter, flag 등이 들어가고 나머지는 Completion Area, output buffer, 여러 input의 address입니다.

struct ccb {
    u64   control;
    u64   completion;
    u64   input0;
    u64   access;
    u64   input1;
    u64   op_data;
    u64   output;
    u64   table;
};

각 field의 상세 설명은 `libdax/common/sys/dax1/dax1_ccb.h`를 참조하고, guest OS인 Linux kernel에 제공되는 전체 Hypervisor API는 `dax-hv-api.txt`를 참조합니다.

driver는 첫 word인 `control`에서 다음 항목을 검사합니다.

  • CCB version은 hardware version과 일치해야 합니다.
  • Opcode는 문서에 허용된 command 중 하나여야 합니다.
  • user가 제공한 모든 address의 address type은 `virtual`이어야 합니다. 이 검증으로 application은 자신이 소유한 memory만 접근할 수 있습니다.

user code의 device·Completion Area 준비

259-291

DAX는 user code와 kernel code 모두에서 접근할 수 있습니다. kernel code는 hypercall을 직접 실행하지만 user code는 driver wrapper를 사용해야 합니다. CCB 설정은 거의 같고 Completion Area 준비 방식만 다릅니다. 먼저 user code 예제를 설명한 뒤 kernel code 예제를 설명합니다.

driver API로 programming하려면 `arch/sparc/include/uapi/asm/oradax.h`를 include해야 합니다. M7은 `/dev/oradax1`, M8은 `/dev/oradax2`를 사용하며 한 device만 열리므로 둘을 차례로 시도하는 방법이 가장 단순합니다.

fd = open("/dev/oradax1", O_RDWR);
if (fd < 0)
        fd = open("/dev/oradax2", O_RDWR);
if (fd < 0)
       /* No DAX found */

다음으로 Completion Area를 read-only mapping합니다.

completion_area = mmap(NULL, DAX_MMAP_LEN, PROT_READ, MAP_SHARED, fd, 0);

모든 input/output buffer는 하나의 hardware page 안에 완전히 들어가야 합니다. DAX가 virtual page boundary에 엄격히 제한되기 때문입니다. 또한 coprocessor는 cache-line 단위로 쓰므로 output buffer는 64-byte aligned여야 하고 size도 64 byte의 배수여야 합니다.

Scan command 예제의 의미

292-305

이 예제는 input vector와 match value를 받아 output bitmap을 만드는 DAX Scan command를 보여 줍니다. match value와 일치하는 각 input element에 대응하는 output bit를 설정합니다.

input vector는 1-bit element의 연속이고 match value는 0입니다. 따라서 input의 각 0 bit는 output의 1이 되고 input의 1은 output의 0이 되어 결과 bitmap은 input bitmap을 뒤집은 값입니다.

이 CCB에서 사용하는 모든 parameter와 bit의 세부 의미는 DAX Hypervisor API 문서 section `36.2.1.3`의 Scan command 설명을 참조합니다.

Scan CCB 구성 코드

306-333

`control`은 Scan Value command, primary virtual input/output address type, fixed-width bit-packed input, 1-bit element, bit-vector output, 첫 scan criterion과 비활성화된 둘째 criterion을 지정합니다. `access`는 primary input 길이를 bit 단위로 `nbits - 1`에 기록합니다.

driver가 Completion Area address를 채우므로 `completion`은 0으로 두고, secondary input과 table은 사용하지 않습니다. `op_data`의 scan criterion은 match value 0입니다.

Scan CCB control bit 구성
shiftvaluefield 의미
48`2L`command = Scan Value
40`3L`output address type = primary virtual
34`3L`primary input address type = primary virtual
28`1`primary input format = fixed-width bit packed
23`0`primary input element size = 1 bit
10`8`output format = bit vector
5`0`first scan criterion size = 1 byte
0`31`second scan criterion disabled
access wordshift 24에 length format 2(bits)를 놓고 하위 field에 nbits - 1을 기록합니다.

원문 307-316줄의 shift expression을 field별로 구조화했습니다. 아래 표와 원문 C code는 같은 값을 나타냅니다.

ccb->control =       /* Table 36.1, CCB Header Format */
          (2L << 48)     /* command = Scan Value */
        | (3L << 40)     /* output address type = primary virtual */
        | (3L << 34)     /* primary input address type = primary virtual */
                     /* Section 36.2.1, Query CCB Command Formats */
        | (1 << 28)     /* 36.2.1.1.1 primary input format = fixed width bit packed */
        | (0 << 23)     /* 36.2.1.1.2 primary input element size = 0 (1 bit) */
        | (8 << 10)     /* 36.2.1.1.6 output format = bit vector */
        | (0 <<  5)        /* 36.2.1.3 First scan criteria size = 0 (1 byte) */
        | (31 << 0);        /* 36.2.1.3 Disable second scan criteria */

ccb->completion = 0;    /* Completion area address, to be filled in by driver */

ccb->input0 = (unsigned long) input; /* primary input address */

ccb->access =       /* Section 36.2.1.2, Data Access Control */
          (2 << 24)    /* Primary input length format = bits */
        | (nbits - 1); /* number of bits in primary input stream, minus 1 */

ccb->input1 = 0;       /* secondary input address, unused */

ccb->op_data = 0;      /* scan criteria (value to be matched) */

ccb->output = (unsigned long) output;        /* output address */

ccb->table = 0;               /* table address, unused */

CCB 제출과 Completion Area polling

334-360

CCB는 `write()` 또는 `pwrite()` system call로 driver에 제출합니다. call이 실패하면 `read()`로 status를 가져옵니다.

if (pwrite(fd, ccb, 64, 0) != 64) {
        struct ccb_exec_result status;
        read(fd, &status, sizeof(status));
        /* bail out */
}

CCB 제출이 성공하면 Completion Area를 polling해 DAX 종료를 확인합니다. Completion Area 내용의 상세 형식은 DAX Hypervisor API section `36.2.2`에 있습니다. loop는 ASI `0x84`의 `lduba` monitored load로 status를 읽고, 0이면 `%asr28`에 1000을 쓰는 `mwait`으로 최대 1000 ns 기다린 뒤 다시 확인합니다.

while (1) {
        /* Monitored Load */
        __asm__ __volatile__("lduba [%1] 0x84, %0\n"
                             : "=r" (status)
                             : "r"  (completion_area));

        if (status)             /* 0 indicates command in progress */
                break;

        /* MWAIT */
        __asm__ __volatile__("wr %%g0, 1000, %%asr28\n" ::);    /* 1000 ns */
}

완료 status 확인과 dequeue

361-383

Completion Area status 1은 CCB가 성공적으로 완료되어 output bitmap이 valid함을 뜻하며 즉시 사용할 수 있습니다. 그 밖의 non-zero value는 DAX Hypervisor API section `36.2.2`에 정의된 error condition입니다.

if (completion_area[0] != 1) {        /* section 36.2.2, 1 = command ran and succeeded */
        /* completion_area[0] contains the completion status */
        /* completion_area[1] contains an error code, see 36.2.2 */
}

Completion Area 처리를 마치면 request에 연결된 resource를 해제해도 된다고 driver에 알려야 합니다. `CCB_DEQUEUE` command를 `write()`로 보내고, 그 뒤 Completion Area unmapping, DAX device close, memory free 같은 일반적인 program cleanup을 수행합니다.

struct dax_command cmd;
cmd.command = CCB_DEQUEUE;
if (write(fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
        /* bail out */
}

kernel Completion Area와 직접 hypercall

384-415

kernel code에서 DAX를 사용할 때 user application과 다른 점은 Completion Area 처리뿐입니다. user application은 driver가 할당한 영역을 mmap하지만 kernel code는 Completion Area용 memory를 직접 할당하고 그 address와 type을 CCB에 기록해야 합니다.

ccb->control |=      /* Table 36.1, CCB Header Format */
        (3L << 32);     /* completion area address type = primary virtual */

ccb->completion = (unsigned long) completion_area;   /* Completion area address */

kernel은 DAX submit hypercall을 직접 실행합니다. `sun4v_ccb_submit()`의 flag는 DAX Hypervisor API section `36.3.1`에 정의되어 있습니다. 예제는 query command, privileged argument, primary address type, privileged virtual address를 지정하고 `bytes_accepted`와 `status_data`를 받습니다.

#include <asm/hypervisor.h>

      hv_rv = sun4v_ccb_submit((unsigned long)ccb, 64,
                               HV_CCB_QUERY_CMD |
                               HV_CCB_ARG0_PRIVILEGED | HV_CCB_ARG0_TYPE_PRIMARY |
                               HV_CCB_VA_PRIVILEGED,
                               0, &bytes_accepted, &status_data);

      if (hv_rv != HV_EOK) {
              /* hv_rv is an error code, status_data contains */
              /* potential additional status, see 36.3.1.1 */
      }

`hv_rv`가 `HV_EOK`가 아니면 Hypervisor error code이며 `status_data`에 section `36.3.1.1`이 설명하는 추가 status가 들어 있을 수 있습니다.

kernel의 동일한 polling 절차

416-439

제출 뒤 Completion Area polling code는 user land와 같습니다. monitored load로 status를 읽고 진행 중을 뜻하는 0이면 `mwait`으로 기다립니다. non-zero status가 1이 아니면 Completion Area의 status와 error code를 조사합니다.

while (1) {
        /* Monitored Load */
        __asm__ __volatile__("lduba [%1] 0x84, %0\n"
                             : "=r" (status)
                             : "r"  (completion_area));

        if (status)             /* 0 indicates command in progress */
                break;

        /* MWAIT */
        __asm__ __volatile__("wr %%g0, 1000, %%asr28\n" ::);    /* 1000 ns */
}

if (completion_area[0] != 1) {        /* section 36.2.2, 1 = command ran and succeeded */
        /* completion_area[0] contains the completion status */
        /* completion_area[1] contains an error code, see 36.2.2 */
}

completion status가 성공을 나타내는 즉시 output bitmap을 사용할 수 있습니다.

UltraSPARC VM 사양 발췌 포함

440-445

마지막 절은 companion file인 `dax-hv-api.txt`를 literal include하여 UltraSPARC Virtual Machine Specification의 DAX Hypervisor API 발췌문을 이어 붙입니다. 원문의 heading에는 `Excer[t`라는 오자가 있습니다.

.. include:: dax-hv-api.txt
   :literal: