i40e_queues.cc 9.42 KB
Newer Older
Antoine Kaufmann's avatar
Antoine Kaufmann committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdlib.h>
#include <string.h>
#include <cassert>
#include <iostream>

#include "i40e_bm.h"

#include "i40e_base_wrapper.h"

using namespace i40e;

extern nicbm::Runner *runner;

queue_base::queue_base(uint32_t &reg_head_, uint32_t &reg_tail_)
15
16
17
    : active_first_pos(0), active_first_idx(0), active_cnt(0),
    base(0), len(0), reg_head(reg_head_), reg_tail(reg_tail_),
    enabled(false), desc_len(0)
Antoine Kaufmann's avatar
Antoine Kaufmann committed
18
{
19
20
21
22
23
24
25
26
27
28
    for (size_t i = 0; i < MAX_ACTIVE_DESCS; i++) {
        desc_ctxs[i] = nullptr;
    }
}

void queue_base::ctxs_init()
{
    for (size_t i = 0; i < MAX_ACTIVE_DESCS; i++) {
        desc_ctxs[i] = &desc_ctx_create();
    }
Antoine Kaufmann's avatar
Antoine Kaufmann committed
29
30
31
32
}

void queue_base::trigger_fetch()
{
33
    if (!enabled)
Antoine Kaufmann's avatar
Antoine Kaufmann committed
34
35
        return;

36
37
38
39
40
41
42
43
    // calculate how many we can fetch
    uint32_t next_idx = (active_first_idx + active_cnt) % len;
    uint32_t desc_avail = (reg_tail - next_idx) % len;
    uint32_t fetch_cnt = desc_avail;
    fetch_cnt = std::min(fetch_cnt, MAX_ACTIVE_DESCS - active_cnt);
    if (max_active_capacity() <= active_cnt)
        fetch_cnt = std::min(fetch_cnt, max_active_capacity() - active_cnt);
    fetch_cnt = std::min(fetch_cnt, max_fetch_capacity());
Antoine Kaufmann's avatar
Antoine Kaufmann committed
44

45
46
    if (next_idx + fetch_cnt > len)
        fetch_cnt = len - next_idx;
Antoine Kaufmann's avatar
Antoine Kaufmann committed
47

48
49
    std::cerr << "fetching: avail=" << desc_avail <<
        " cnt=" << fetch_cnt << " idx=" << next_idx << std::endl;
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
    // abort if nothign to fetch
    if (fetch_cnt == 0)
        return;

    // mark descriptor contexts as fetching
    uint32_t first_pos = (active_first_pos + active_cnt) % MAX_ACTIVE_DESCS;
    for (uint32_t i = 0; i < fetch_cnt; i++) {
        desc_ctx &ctx = *desc_ctxs[(first_pos + i) % MAX_ACTIVE_DESCS];
        assert(ctx.state == desc_ctx::DESC_EMPTY);

        ctx.state = desc_ctx::DESC_FETCHING;
        ctx.index = (next_idx + i) % len;
    }
    active_cnt += fetch_cnt;
Antoine Kaufmann's avatar
Antoine Kaufmann committed
65

66
67
68
69
70
71
    // prepare & issue dma
    dma_fetch *dma = new dma_fetch(*this, desc_len * fetch_cnt);
    dma->write = false;
    dma->dma_addr = base + next_idx * desc_len;
    dma->pos = first_pos;
    std::cerr << "    dma = " << dma << std::endl;
Antoine Kaufmann's avatar
Antoine Kaufmann committed
72
73
74
    runner->issue_dma(*dma);
}

75
void queue_base::trigger_process()
76
{
77
78
    if (!enabled)
        return;
79

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    // first skip over descriptors that are already done processing
    uint32_t i;
    for (i = 0; i < active_cnt; i++)
        if (desc_ctxs[(active_first_pos + i) % MAX_ACTIVE_DESCS]->state
                <= desc_ctx::DESC_PROCESSING)
            break;

    // then run all prepared contexts
    uint32_t j;
    for (j = 0; i + j < active_cnt; j++) {
        desc_ctx &ctx = *desc_ctxs[(active_first_pos + i + j)
            % MAX_ACTIVE_DESCS];
        if (ctx.state != desc_ctx::DESC_PREPARED)
            break;

        ctx.state = desc_ctx::DESC_PROCESSING;
        ctx.process();
    }
}

void queue_base::trigger_writeback()
{
    if (!enabled)
        return;

    // from first pos count number of processed descriptors
    uint32_t avail;
    for (avail = 0; avail < active_cnt; avail++)
        if (desc_ctxs[(active_first_pos + avail) % MAX_ACTIVE_DESCS]->state
                != desc_ctx::DESC_PROCESSED)
            break;

    uint32_t cnt = std::min(avail, max_writeback_capacity());
    if (active_first_pos + cnt > len)
        cnt = len - active_first_pos;

    std::cerr << "writing back: avail=" << avail << " cnt=" << cnt << " idx=" <<
        active_first_idx << std::endl;

    if (cnt == 0)
        return;

    // mark these descriptors as writing back
    for (uint32_t i = 0; i < cnt; i++) {
        desc_ctx &ctx = *desc_ctxs[(active_first_pos + i) % MAX_ACTIVE_DESCS];
        ctx.state = desc_ctx::DESC_WRITING_BACK;
    }

    do_writeback(active_first_idx, active_first_pos, cnt);
129
130
}

131
132
133
void queue_base::reset()
{
    enabled = false;
134
135
136
137
138
139
140
    active_first_pos = 0;
    active_first_idx = 0;
    active_cnt = 0;

    for (size_t i = 0; i < MAX_ACTIVE_DESCS; i++) {
        desc_ctxs[i]->state = desc_ctx::DESC_EMPTY;
    }
141
142
}

Antoine Kaufmann's avatar
Antoine Kaufmann committed
143
144
145
146
147
148
149
150
void queue_base::reg_updated()
{
    if (!enabled)
        return;

    trigger_fetch();
}

151
152
153
154
155
bool queue_base::is_enabled()
{
    return enabled;
}

156
157
158
159
160
161
uint32_t queue_base::max_fetch_capacity()
{
    return UINT32_MAX;
}

uint32_t queue_base::max_active_capacity()
Antoine Kaufmann's avatar
Antoine Kaufmann committed
162
{
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
    return UINT32_MAX;
}

uint32_t queue_base::max_writeback_capacity()
{
    return UINT32_MAX;
}

void queue_base::interrupt()
{
}

void queue_base::do_writeback(uint32_t first_idx, uint32_t first_pos,
        uint32_t cnt)
{
    dma_wb *dma = new dma_wb(*this, desc_len * cnt);
Antoine Kaufmann's avatar
Antoine Kaufmann committed
179
    dma->write = true;
180
181
182
183
184
185
186
187
188
    dma->dma_addr = base + first_idx * desc_len;
    dma->pos = first_pos;

    uint8_t *buf = reinterpret_cast<uint8_t *> (dma->data);
    for (uint32_t i = 0; i < cnt; i++) {
        desc_ctx &ctx = *desc_ctxs[(first_pos + i) % MAX_ACTIVE_DESCS];
        assert(ctx.state == desc_ctx::DESC_WRITING_BACK);
        memcpy(buf + i * desc_len, ctx.desc, desc_len);
    }
Antoine Kaufmann's avatar
Antoine Kaufmann committed
189
190
191
192

    runner->issue_dma(*dma);
}

193
void queue_base::writeback_done(uint32_t first_pos, uint32_t cnt)
194
{
195
196
    if (!enabled)
        return;
197

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    // first mark descriptors as written back
    for (uint32_t i = 0; i < cnt; i++) {
        desc_ctx &ctx = *desc_ctxs[(first_pos + i) % MAX_ACTIVE_DESCS];
        assert(ctx.state == desc_ctx::DESC_WRITING_BACK);
        ctx.state = desc_ctx::DESC_WRITTEN_BACK;
    }

    std::cerr << "written back: afi=" << active_first_idx << " afp=" <<
        active_first_pos << " acnt=" << active_cnt << " pos=" << first_pos <<
        " cnt=" << cnt << std::endl;

    // then start at the beginning and check how many are written back and then
    // free those
    uint32_t bump_cnt = 0;
    for (bump_cnt = 0; bump_cnt < active_cnt; bump_cnt++) {
        desc_ctx &ctx = *desc_ctxs[(active_first_pos + bump_cnt) %
            MAX_ACTIVE_DESCS];
        if (ctx.state != desc_ctx::DESC_WRITTEN_BACK)
            break;

        ctx.state = desc_ctx::DESC_EMPTY;
    }
    std::cerr << "    bump_cnt=" << bump_cnt << std::endl;

    active_first_pos = (active_first_pos + bump_cnt) % MAX_ACTIVE_DESCS;
    active_first_idx = (active_first_idx + bump_cnt) % len;
    active_cnt -= bump_cnt;

    reg_head = active_first_idx;
    interrupt();
}
229

230
231
232
233
234
queue_base::desc_ctx::desc_ctx(queue_base &queue_)
    : queue(queue_), state(DESC_EMPTY), index(0), data(nullptr), data_len(0),
    data_capacity(0)
{
    desc = new uint8_t[queue_.desc_len];
235
236
}

237
queue_base::desc_ctx::~desc_ctx()
238
{
239
240
241
    delete[] ((uint8_t *) desc);
    if (data_capacity > 0)
        delete[] ((uint8_t *) data);
242
243
}

244
void queue_base::desc_ctx::prepare()
245
{
246
    prepared();
247
248
}

249
void queue_base::desc_ctx::prepared()
250
{
251
252
253
    assert(state == DESC_PREPARING);
    state = DESC_PREPARED;
    queue.trigger_process();
254
255
}

256
void queue_base::desc_ctx::processed()
Antoine Kaufmann's avatar
Antoine Kaufmann committed
257
{
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
    assert(state == DESC_PROCESSING);
    state = DESC_PROCESSED;
    queue.trigger_writeback();
}

void queue_base::desc_ctx::data_fetch(uint64_t addr, size_t data_len)
{
    if (data_capacity < data_len) {
        std::cerr << "data_fetch: allocating" << std::endl;
        if (data_capacity != 0)
            delete[] ((uint8_t *) data);

        data = new uint8_t[data_len];
        data_capacity = data_len;
    }

    dma_data_fetch *dma = new dma_data_fetch(*this, data_len, data);
    dma->write = false;
    dma->dma_addr = addr;

    std::cerr << "fetching data idx=" << index << " addr=" << addr << " len=" <<
        data_len << std::endl;
    std::cerr << "dma = " << dma << " data=" << data << std::endl;
    runner->issue_dma(*dma);
282

283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
}

void queue_base::desc_ctx::data_fetched(uint64_t addr, size_t len)
{
    prepared();
}

void queue_base::desc_ctx::data_write(uint64_t addr, size_t data_len,
        const void *buf)
{
    std::cerr << "data_write(addr=" << addr << " datalen=" << data_len <<
        ")" << std::endl;
    dma_data_wb *data_dma = new dma_data_wb(*this, data_len);
    data_dma->write = true;
    data_dma->dma_addr = addr;
    memcpy(data_dma->data, buf, data_len);

    runner->issue_dma(*data_dma);
}

void queue_base::desc_ctx::data_written(uint64_t addr, size_t len)
{
    std::cerr << "data_written(addr=" << addr << " datalen=" << len <<
        ")" << std::endl;
    processed();
Antoine Kaufmann's avatar
Antoine Kaufmann committed
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
}

queue_base::dma_fetch::dma_fetch(queue_base &queue_, size_t len_)
    : queue(queue_)
{
    data = new char[len_];
    len = len_;
}

queue_base::dma_fetch::~dma_fetch()
{
    delete[] ((char *) data);
}

void queue_base::dma_fetch::done()
{
324
325
326
327
328
329
330
331
    uint8_t *buf = reinterpret_cast <uint8_t *> (data);
    for (uint32_t i = 0; i < len / queue.desc_len; i++) {
        desc_ctx &ctx = *queue.desc_ctxs[(pos + i) % queue.MAX_ACTIVE_DESCS];
        memcpy(ctx.desc, buf + queue.desc_len * i, queue.desc_len);

        ctx.state = desc_ctx::DESC_PREPARING;
        ctx.prepare();
    }
Antoine Kaufmann's avatar
Antoine Kaufmann committed
332
333
334
    delete this;
}

335
336
337
queue_base::dma_data_fetch::dma_data_fetch(desc_ctx &ctx_, size_t len_,
        void *buffer)
    : ctx(ctx_)
338
{
339
    data = buffer;
340
341
342
343
344
345
346
347
348
    len = len_;
}

queue_base::dma_data_fetch::~dma_data_fetch()
{
}

void queue_base::dma_data_fetch::done()
{
349
    ctx.data_fetched(dma_addr, len);
350
351
    delete this;
}
Antoine Kaufmann's avatar
Antoine Kaufmann committed
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366

queue_base::dma_wb::dma_wb(queue_base &queue_, size_t len_)
    : queue(queue_)
{
    data = new char[len_];
    len = len_;
}

queue_base::dma_wb::~dma_wb()
{
    delete[] ((char *) data);
}

void queue_base::dma_wb::done()
{
367
    queue.writeback_done(pos, len / queue.desc_len);
Antoine Kaufmann's avatar
Antoine Kaufmann committed
368
369
370
371
    delete this;
}


372
373
queue_base::dma_data_wb::dma_data_wb(desc_ctx &ctx_, size_t len_)
    : ctx(ctx_)
374
375
376
377
378
379
380
381
382
383
384
385
{
    data = new char[len_];
    len = len_;
}

queue_base::dma_data_wb::~dma_data_wb()
{
    delete[] ((char *) data);
}

void queue_base::dma_data_wb::done()
{
386
    ctx.data_written(dma_addr, len);
387
388
    delete this;
}