1/*
2 * Copyright (c) 2014, ETH Zurich. All rights reserved.
3 *
4 * This file is distributed under the terms in the attached LICENSE file.
5 * If you do not find this file, copies can be found by writing to:
6 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
7 */
8/*
9 *
10 *
11 */
12#include <stdio.h>
13#include <string.h>
14
15#include <barrelfish/barrelfish.h>
16
17#include <pci/devids.h>
18
19#include <dma/dma.h>
20#include <dma/dma_device.h>
21#include <dma/dma_service.h>
22#include <dma/dma_manager_client.h>
23#include <dma/ioat/ioat_dma.h>
24#include <dma/dma_bench.h>
25#include "device.h"
26#include "dma_service.h"
27#include "debug.h"
28
29#include <barrelfish/waitset.h>
30#include <pci/pci_types.h>
31
32#define IOAT_BENCHMARK_CORE 20
33
34#define IOAT_IDLE_COUNTER 0xFFF
35
36static struct dma_service_cb dma_svc_cb = {
37    .connect = dma_svc_connect_cb,
38    .addregion = dma_svc_addregion_cb,
39    .removeregion = dma_svc_removeregion_cb,
40    .memcpy = dma_svc_memcpy_cb
41};
42
43#if 0
44#define BUFFER_SIZE (1<<22)
45
46static void impl_test_cb(errval_t err, ioat_dma_req_id_t id, void *arg)
47{
48    debug_printf("impl_test_cb\n");
49    assert(memcmp(arg, arg + BUFFER_SIZE, BUFFER_SIZE) == 0);
50    debug_printf("test ok\n");
51}
52
53static void impl_test(void)
54{
55    errval_t err;
56
57    debug_printf("Doing an implementation test\n");
58
59    struct capref frame;
60    err = frame_alloc(&frame, 2 * BUFFER_SIZE, NULL);
61    assert(err_is_ok(err));
62
63    struct frame_identity id;
64    err = invoke_frame_identify(frame, &id);
65    assert(err_is_ok(err));
66
67    void *buf;
68    err = vspace_map_one_frame(&buf, 1UL << id.bits, frame, NULL, NULL);
69    assert(err_is_ok(err));
70
71    memset(buf, 0, 1UL << id.bits);
72    memset(buf, 0xA5, BUFFER_SIZE);
73
74    struct ioat_dma_req_setup setup = {
75        .type = IOAT_DMA_REQ_TYPE_MEMCPY,
76        .src = id.base,
77        .dst = id.base + BUFFER_SIZE,
78        .bytes = BUFFER_SIZE,
79        .done_cb = impl_test_cb,
80        .arg = buf
81    };
82    int reps = 10;
83    do {
84        debug_printf("!!!!!! NEW ROUND\n");
85        err = ioat_dma_request_memcpy(dma_ctrl.devices, &setup);
86        assert(err_is_ok(err));
87
88        uint32_t i = 10;
89        while(i--) {
90            ioat_dma_device_poll_channels(dma_ctrl.devices);
91        }
92    }while(reps--);
93}
94#endif
95
96int main(int argc,
97         char *argv[])
98{
99    errval_t err;
100
101    debug_printf("I/O AT DMA driver started\n");
102
103    /*
104     * Parsing of cmdline arguments.
105     *
106     * When started by Kaluga, the last element of the cmdline will contain
107     * the basic PCI information of the device.
108     * VENDORID:DEVICEID:BUS:DEV:FUN
109     */
110    uint32_t vendor_id, device_id;
111
112    struct pci_addr addr = {
113        .bus = 0,
114        .device = 0,
115        .function = 0
116    };
117
118    enum device_type devtype = IOAT_DEVICE_INVAL;
119
120    if (argc > 1) {
121        uint32_t parsed = sscanf(argv[argc - 1],
122                "%x:%x:%"SCNx32":%"SCNx32":%"SCNx32, &vendor_id, &device_id,
123                &addr.bus, &addr.device, &addr.function);
124        if (parsed != 5) {
125            DEBUGPRINT("WARNING: cmdline parsing failed. Using PCI Address [0,0,0]");
126        } else {
127            if (vendor_id != 0x8086) {
128                USER_PANIC("unexpected vendor [%x]", vendor_id);
129            }
130            switch ((device_id & 0xFFF0)) {
131                case PCI_DEVICE_IOAT_IVB0:
132                    devtype = IOAT_DEVICE_IVB;
133                    break;
134                case PCI_DEVICE_IOAT_HSW0:
135                    devtype = IOAT_DEVICE_HSW;
136                    break;
137                default:
138                    USER_PANIC("unexpected device [%x]", device_id)
139                    ;
140                    break;
141            }
142
143            DEBUGPRINT("Initializing I/O AT DMA device with PCI address [%u,%u,%u]\n",
144                       addr.bus, addr.device, addr.function);
145        }
146    } else {
147        DEBUGPRINT("WARNING: Initializing I/O AT DMA device with unknown PCI address "
148                   "[0,0,0]\n");
149    }
150
151    err = ioat_device_discovery(addr, devtype, IOAT_DMA_OPERATION);
152    if (err_is_fail(err)) {
153        USER_PANIC_ERR(err, "DMA Device discovery failed");
154    }
155
156#if DMA_BENCH_RUN_BENCHMARK
157    if (disp_get_core_id() < IOAT_BENCHMARK_CORE) {
158        struct ioat_dma_device *dev = ioat_device_get_next();
159        dma_bench_run_default((struct dma_device *)dev);
160    }
161#endif
162
163#if IOAT_DMA_OPERATION == IOAT_DMA_OPERATION_SERVICE
164
165    iref_t svc_iref;
166    char svc_name[30];
167    uint8_t numa_node = (disp_get_core_id() >= 20);
168    snprintf(svc_name, 30, "%s.%u", IOAT_DMA_SERVICE_NAME, numa_node);
169    err = dma_service_init_with_name(svc_name, &dma_svc_cb, NULL, &svc_iref);
170    if (err_is_fail(err)) {
171        USER_PANIC_ERR(err, "Failed to start the DMA service");
172    }
173
174    err = dma_manager_register_driver(0, 1ULL << 40, DMA_DEV_TYPE_IOAT, svc_iref);
175    if (err_is_fail(err)) {
176        USER_PANIC_ERR(err, "Failed to register with the DMA manager\n");
177    }
178
179    DEBUGPRINT("Driver registered with DMA manager. Serving requests now.\n");
180
181#endif
182
183#if IOAT_DMA_OPERATION == IOAT_DMA_OPERATION_LIBRARY
184
185#endif
186
187    uint32_t idle_counter = IOAT_IDLE_COUNTER;
188    while (1) {
189        uint8_t idle = 0x1;
190        err = ioat_device_poll();
191        switch (err_no(err)) {
192            case DMA_ERR_DEVICE_IDLE:
193                break;
194            case SYS_ERR_OK:
195                idle = 0;
196                break;
197            default:
198                debug_printf("I/O AT DMA driver terminated: in poll, %s\n",
199                             err_getstring(err));
200                return err;
201        }
202        err = event_dispatch_non_block(get_default_waitset());
203        switch (err_no(err)) {
204            case SYS_ERR_OK:
205                idle = 0;
206                break;
207            case LIB_ERR_NO_EVENT:
208                break;
209            default:
210                debug_printf("I/O AT DMA driver terminated in dispatch,  %s\n",
211                             err_getstring(err));
212                return err;
213        }
214        if (idle) {
215            idle_counter--;
216            if (idle_counter == 0) {
217                thread_yield();
218                idle_counter = IOAT_IDLE_COUNTER;
219            }
220        } else {
221            idle_counter = IOAT_IDLE_COUNTER;
222        }
223    }
224
225    debug_printf("I/O AT DMA driver terminated");
226
227    return 0;
228}
229
230