i40e_queues.cc 12.1 KB
Newer Older
Antoine Kaufmann's avatar
Antoine Kaufmann committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
 * Copyright 2021 Max Planck Institute for Software Systems, and
 * National University of Singapore
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

Antoine Kaufmann's avatar
Antoine Kaufmann committed
25
26
27
28
#include <stdlib.h>
#include <string.h>
#include <cassert>
#include <iostream>
29
#include <algorithm>
Antoine Kaufmann's avatar
Antoine Kaufmann committed
30

Antoine Kaufmann's avatar
Antoine Kaufmann committed
31
32
#include "sims/nic/i40e_bm/i40e_bm.h"
#include "sims/nic/i40e_bm/i40e_base_wrapper.h"
Antoine Kaufmann's avatar
Antoine Kaufmann committed
33
34
35
36
37

using namespace i40e;

extern nicbm::Runner *runner;

38
39
queue_base::queue_base(const std::string &qname_, uint32_t &reg_head_,
        uint32_t &reg_tail_)
Antoine Kaufmann's avatar
Antoine Kaufmann committed
40
41
    : qname(qname_), log(qname_), active_first_pos(0), active_first_idx(0),
    active_cnt(0), base(0), len(0), reg_head(reg_head_), reg_tail(reg_tail_),
42
    enabled(false), desc_len(0)
Antoine Kaufmann's avatar
Antoine Kaufmann committed
43
{
44
45
46
47
48
49
50
51
52
53
    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
54
55
56
57
}

void queue_base::trigger_fetch()
{
58
    if (!enabled)
Antoine Kaufmann's avatar
Antoine Kaufmann committed
59
60
        return;

61
62
63
64
65
66
67
68
    // 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
69

70
71
    if (next_idx + fetch_cnt > len)
        fetch_cnt = len - next_idx;
Antoine Kaufmann's avatar
Antoine Kaufmann committed
72

73
#ifdef DEBUG_QUEUES
74
75
    log << "fetching avail=" << desc_avail << " cnt=" << fetch_cnt << " idx=" <<
        next_idx << logger::endl;
76
#endif
77

78
79
80
81
82
83
84
85
86
87
88
89
90
91
    // 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
92

93
94
95
96
97
    // 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;
98
#ifdef DEBUG_QUEUES
99
    log << "    dma = " << dma << logger::endl;
100
#endif
Antoine Kaufmann's avatar
Antoine Kaufmann committed
101
102
103
    runner->issue_dma(*dma);
}

104
void queue_base::trigger_process()
105
{
106
107
    if (!enabled)
        return;
108

109
110
111
112
    // 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
113
                <= desc_ctx::DESC_PREPARED)
114
115
116
117
118
119
120
121
122
123
124
            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;
125
#ifdef DEBUG_QUEUES
126
        log << "processing desc " << ctx.index << logger::endl;
127
#endif
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
        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());
145
146
    if (active_first_idx + cnt > len)
        cnt = len - active_first_idx;
147

148
#ifdef DEBUG_QUEUES
149
150
    log << "writing back avail=" << avail << " cnt=" << cnt <<
        " idx=" << active_first_idx << logger::endl;
151
#endif
152
153
154
155
156
157
158
159
160
161
162

    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);
163
164
}

165
166
167
168
169
170
171
void queue_base::trigger()
{
  trigger_fetch();
  trigger_process();
  trigger_writeback();
}

172
173
void queue_base::reset()
{
174
#ifdef DEBUG_QUEUES
175
    log << "reset" << logger::endl;
176
177
#endif

178
    enabled = false;
179
180
181
182
183
184
185
    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;
    }
186
187
}

Antoine Kaufmann's avatar
Antoine Kaufmann committed
188
189
void queue_base::reg_updated()
{
190
191
192
193
#ifdef DEBUG_QUEUES
    log << "reg_updated: tail=" << reg_tail << " enabled=" << (int) enabled <<
        logger::endl;
#endif
Antoine Kaufmann's avatar
Antoine Kaufmann committed
194
195
196
    if (!enabled)
        return;

197
    trigger();
Antoine Kaufmann's avatar
Antoine Kaufmann committed
198
199
}

200
201
202
203
204
bool queue_base::is_enabled()
{
    return enabled;
}

205
206
207
208
209
210
uint32_t queue_base::max_fetch_capacity()
{
    return UINT32_MAX;
}

uint32_t queue_base::max_active_capacity()
Antoine Kaufmann's avatar
Antoine Kaufmann committed
211
{
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
    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
228
    dma->write = true;
229
230
231
232
233
234
235
236
237
    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
238
239
240
241

    runner->issue_dma(*dma);
}

242
void queue_base::writeback_done(uint32_t first_pos, uint32_t cnt)
243
{
244
245
    if (!enabled)
        return;
246

247
248
249
250
251
252
253
    // 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;
    }

254
#ifdef DEBUG_QUEUES
255
256
257
    log << "written back afi=" << active_first_idx << " afp=" <<
        active_first_pos << " acnt=" << active_cnt << " pos=" <<
        first_pos << " cnt=" << cnt << logger::endl;
258
#endif
259
260
261
262
263
264
265
266
267
268
269
270

    // 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;
    }
271
#ifdef DEBUG_QUEUES
272
    log << "   bump_cnt=" << bump_cnt << logger::endl;
273
#endif
274
275
276
277
278
279
280
281

    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();
}
282

283
284
285
286
287
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];
288
289
}

290
queue_base::desc_ctx::~desc_ctx()
291
{
292
293
294
    delete[] ((uint8_t *) desc);
    if (data_capacity > 0)
        delete[] ((uint8_t *) data);
295
296
}

297
void queue_base::desc_ctx::prepare()
298
{
299
    prepared();
300
301
}

302
void queue_base::desc_ctx::prepared()
303
{
304
#ifdef DEBUG_QUEUES
305
    queue.log << "prepared desc " << index << logger::endl;
306
#endif
307
308
    assert(state == DESC_PREPARING);
    state = DESC_PREPARED;
309
310
}

311
void queue_base::desc_ctx::processed()
Antoine Kaufmann's avatar
Antoine Kaufmann committed
312
{
313
#ifdef DEBUG_QUEUES
314
    queue.log << "processed desc " << index << logger::endl;
315
#endif
316
317
318
319
    assert(state == DESC_PROCESSING);
    state = DESC_PROCESSED;
}

320
#define MAX_DMA_SIZE ((size_t) 9024)
321

322
323
324
void queue_base::desc_ctx::data_fetch(uint64_t addr, size_t data_len)
{
    if (data_capacity < data_len) {
325
#ifdef DEBUG_QUEUES
326
        queue.log << "data_fetch allocating" << logger::endl;
327
#endif
328
329
330
331
332
333
334
        if (data_capacity != 0)
            delete[] ((uint8_t *) data);

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

335
336
337
338
    dma_data_fetch *dma = new dma_data_fetch(*this, std::min(data_len,
                MAX_DMA_SIZE), data);
    dma->part_offset = 0;
    dma->total_len = data_len;
339
340
341
    dma->write = false;
    dma->dma_addr = addr;

342
#ifdef DEBUG_QUEUES
343
344
345
    queue.log << "fetching data idx=" << index << " addr=" << addr << " len=" <<
        data_len << logger::endl;
    queue.log << "  dma = " << dma << " data=" << data << logger::endl;
346
#endif
347
348
349
350
351
352
353
354
355
356
357
    runner->issue_dma(*dma);
}

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)
{
358
#ifdef DEBUG_QUEUES
359
360
    queue.log << "data_write(addr=" << addr << " datalen=" << data_len << ")" <<
        logger::endl;
361
#endif
362
363
364
365
366
367
368
369
370
371
    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)
{
372
#ifdef DEBUG_QUEUES
373
374
    queue.log << "data_written(addr=" << addr << " datalen=" << len << ")" <<
        logger::endl;
375
#endif
376
    processed();
Antoine Kaufmann's avatar
Antoine Kaufmann committed
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
}

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()
{
393
394
395
396
397
    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);

398
#ifdef DEBUG_QUEUES
399
        queue.log << "preparing desc " << ctx.index << logger::endl;
400
#endif
401
402
403
        ctx.state = desc_ctx::DESC_PREPARING;
        ctx.prepare();
    }
404
    queue.trigger();
Antoine Kaufmann's avatar
Antoine Kaufmann committed
405
406
407
    delete this;
}

408
409
410
queue_base::dma_data_fetch::dma_data_fetch(desc_ctx &ctx_, size_t len_,
        void *buffer)
    : ctx(ctx_)
411
{
412
    data = buffer;
413
414
415
416
417
418
419
420
421
    len = len_;
}

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

void queue_base::dma_data_fetch::done()
{
422
423
424
425
426
427
    part_offset += len;
    dma_addr += len;
    data = (uint8_t *) data + len;

    if (part_offset < total_len) {
#ifdef DEBUG_QUEUES
Antoine Kaufmann's avatar
Antoine Kaufmann committed
428
429
        ctx.queue.log << "  dma_fetch: next part of multi part dma" <<
            logger::endl;
430
431
432
433
434
435
#endif
        len = std::min(total_len - part_offset, MAX_DMA_SIZE);
        runner->issue_dma(*this);
        return;
    }
    ctx.data_fetched(dma_addr - part_offset, total_len);
436
    ctx.queue.trigger();
437
438
    delete this;
}
Antoine Kaufmann's avatar
Antoine Kaufmann committed
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453

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()
{
454
    queue.writeback_done(pos, len / queue.desc_len);
455
    queue.trigger();
Antoine Kaufmann's avatar
Antoine Kaufmann committed
456
457
458
459
    delete this;
}


460
461
queue_base::dma_data_wb::dma_data_wb(desc_ctx &ctx_, size_t len_)
    : ctx(ctx_)
462
463
464
465
466
467
468
469
470
471
472
473
{
    data = new char[len_];
    len = len_;
}

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

void queue_base::dma_data_wb::done()
{
474
    ctx.data_written(dma_addr, len);
475
    ctx.queue.trigger();
476
477
    delete this;
}