i40e_adminq.cc 15.3 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.
 */

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#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_admin_tx::queue_admin_tx(i40e_bm &dev_, uint64_t &reg_base_,
        uint32_t &reg_len_, uint32_t &reg_head_, uint32_t &reg_tail_)
40
    : queue_base("atx", reg_head_, reg_tail_), dev(dev_), reg_base(reg_base_),
41
42
43
    reg_len(reg_len_)
{
    desc_len = 32;
44
    ctxs_init();
45
46
}

47
48
49
50
51
52
53
54
55
56
57
queue_base::desc_ctx &queue_admin_tx::desc_ctx_create()
{
    return *new admin_desc_ctx(*this, dev);
}

void queue_admin_tx::reg_updated()
{
    base = reg_base;
    len = (reg_len & I40E_GL_ATQLEN_ATQLEN_MASK) >> I40E_GL_ATQLEN_ATQLEN_SHIFT;

    if (!enabled  && (reg_len & I40E_GL_ATQLEN_ATQENABLE_MASK)) {
58
#ifdef DEBUG_ADMINQ
59
60
        log << " enable base=" << base << " len=" << len <<
            logger::endl;
61
#endif
62
63
        enabled = true;
    } else if (enabled && !(reg_len & I40E_GL_ATQLEN_ATQENABLE_MASK)) {
64
#ifdef DEBUG_ADMINQ
65
        log << " disable" << logger::endl;
66
#endif
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
        enabled = false;
    }

    queue_base::reg_updated();
}

queue_admin_tx::admin_desc_ctx::admin_desc_ctx(queue_admin_tx &queue_,
        i40e_bm &dev_)
    : i40e::queue_base::desc_ctx(queue_), aq(queue_), dev(dev_)
{
    d = reinterpret_cast <struct i40e_aq_desc *> (desc);
}

void queue_admin_tx::admin_desc_ctx::data_written(uint64_t addr, size_t len)
{
    processed();
}

void queue_admin_tx::admin_desc_ctx::desc_compl_prepare(uint16_t retval,
86
87
88
89
90
91
92
        uint16_t extra_flags)
{
    d->flags &= ~0x1ff;
    d->flags |= I40E_AQ_FLAG_DD | I40E_AQ_FLAG_CMP | extra_flags;
    if (retval)
        d->flags |= I40E_AQ_FLAG_ERR;
    d->retval = retval;
Antoine Kaufmann's avatar
Antoine Kaufmann committed
93
94

#ifdef DEBUG_ADMINQ
95
96
    queue.log << " desc_compl_prepare index=" << index << " retval=" <<
        retval << logger::endl;
Antoine Kaufmann's avatar
Antoine Kaufmann committed
97
#endif
98
99
}

100
101
void queue_admin_tx::admin_desc_ctx::desc_complete(uint16_t retval,
        uint16_t extra_flags)
102
{
103
104
    desc_compl_prepare(retval, extra_flags);
    processed();
105
106
}

107
108
void queue_admin_tx::admin_desc_ctx::desc_complete_indir(uint16_t retval,
        const void *data, size_t len, uint16_t extra_flags, bool ignore_datalen)
109
{
110
    if (!ignore_datalen && len > d->datalen) {
111
112
        queue.log << "queue_admin_tx::desc_complete_indir: data too long ("
            << len << ") got buffer for (" << d->datalen << ")" << logger::endl;
113
114
115
116
        abort();
    }
    d->datalen = len;

117
    desc_compl_prepare(retval, extra_flags);
118
119
120

    uint64_t addr = d->params.external.addr_low |
        (((uint64_t) d->params.external.addr_high) << 32);
121
    data_write(addr, len, data);
122
123
}

124
void queue_admin_tx::admin_desc_ctx::prepare()
125
{
126
127
128
    if ((d->flags & I40E_AQ_FLAG_RD)) {
        uint64_t addr = d->params.external.addr_low |
            (((uint64_t) d->params.external.addr_high) << 32);
129
#ifdef DEBUG_ADMINQ
130
131
        queue.log << " desc with buffer opc=" << d->opcode << " addr=" <<
            addr << logger::endl;
132
#endif
133
134
135
136
137
        data_fetch(addr, d->datalen);
    } else {
        prepared();
    }
}
138

139
140
void queue_admin_tx::admin_desc_ctx::process()
{
141
#ifdef DEBUG_ADMINQ
142
    queue.log << " descriptor " << index << " fetched" << logger::endl;
143
#endif
144
145

    if (d->opcode == i40e_aqc_opc_get_version) {
146
#ifdef DEBUG_ADMINQ
147
        queue.log << "  get version" << logger::endl;
148
#endif
149
150
151
152
153
154
155
156
157
        struct i40e_aqc_get_version *gv =
            reinterpret_cast<struct i40e_aqc_get_version *>(d->params.raw);
        gv->rom_ver = 0;
        gv->fw_build = 0;
        gv->fw_major = 0;
        gv->fw_minor = 0;
        gv->api_major = I40E_FW_API_VERSION_MAJOR;
        gv->api_minor = I40E_FW_API_VERSION_MINOR_X710;

158
        desc_complete(0);
159
    } else if (d->opcode == i40e_aqc_opc_request_resource) {
160
#ifdef DEBUG_ADMINQ
161
        queue.log << "  request resource" << logger::endl;
162
#endif
163
164
165
166
        struct i40e_aqc_request_resource *rr =
            reinterpret_cast<struct i40e_aqc_request_resource *>(
                    d->params.raw);
        rr->timeout = 180000;
167
#ifdef DEBUG_ADMINQ
168
169
        queue.log << "    res_id=" << rr->resource_id << logger::endl;
        queue.log << "    res_nu=" << rr->resource_number << logger::endl;
170
#endif
171
        desc_complete(0);
172
    } else if (d->opcode == i40e_aqc_opc_release_resource) {
173
#ifdef DEBUG_ADMINQ
174
        queue.log << "  release resource" << logger::endl;
175
176
#endif
#ifdef DEBUG_ADMINQ
177
178
179
        struct i40e_aqc_request_resource *rr =
            reinterpret_cast<struct i40e_aqc_request_resource *>(
                    d->params.raw);
180
181
        queue.log << "    res_id=" << rr->resource_id << logger::endl;
        queue.log << "    res_nu=" << rr->resource_number << logger::endl;
182
#endif
183
        desc_complete(0);
184
    } else if (d->opcode == i40e_aqc_opc_clear_pxe_mode)  {
185
#ifdef DEBUG_ADMINQ
186
        queue.log << "  clear PXE mode" << logger::endl;
187
#endif
188
        dev.regs.gllan_rctl_0 &= ~I40E_GLLAN_RCTL_0_PXE_MODE_MASK;
189
        desc_complete(0);
190
191
192
    } else if (d->opcode == i40e_aqc_opc_list_func_capabilities ||
            d->opcode == i40e_aqc_opc_list_dev_capabilities)
    {
193
#ifdef DEBUG_ADMINQ
194
        queue.log << "  get dev/fun caps" << logger::endl;
195
#endif
196
197
198
199
200
201
202
203
204
        struct i40e_aqc_list_capabilites *lc =
            reinterpret_cast<struct i40e_aqc_list_capabilites *>(
                    d->params.raw);

        struct i40e_aqc_list_capabilities_element_resp caps[] = {
            { I40E_AQ_CAP_ID_RSS, 1, 0, 512, 6, 0, {} },
            { I40E_AQ_CAP_ID_RXQ, 1, 0, dev.NUM_QUEUES, 0, 0, {} },
            { I40E_AQ_CAP_ID_TXQ, 1, 0, dev.NUM_QUEUES, 0, 0, {} },
            { I40E_AQ_CAP_ID_MSIX, 1, 0, dev.NUM_PFINTS, 0, 0, {} },
205
206
            { I40E_AQ_CAP_ID_VSI, 1, 0, dev.NUM_VSIS, 0, 0, {} },
            { I40E_AQ_CAP_ID_DCB, 1, 0, 1, 1, 1, {} },
207
208
209
210
        };
        size_t num_caps = sizeof(caps) / sizeof(caps[0]);

        if (sizeof(caps) <= d->datalen) {
211
#ifdef DEBUG_ADMINQ
212
            queue.log << "    data fits" << logger::endl;
213
#endif
214
215
            // data fits within the buffer
            lc->count = num_caps;
216
            desc_complete_indir(0, caps, sizeof(caps));
217
        } else {
218
#ifdef DEBUG_ADMINQ
219
            queue.log << "    data doesn't fit" << logger::endl;
220
#endif
221
222
            // data does not fit
            d->datalen = sizeof(caps);
223
            desc_complete(I40E_AQ_RC_ENOMEM);
224
225
        }
    } else if (d->opcode == i40e_aqc_opc_lldp_stop) {
226
#ifdef DEBUG_ADMINQ
227
        queue.log << "  lldp stop" << logger::endl;
228
#endif
229
        desc_complete(0);
230
    } else if (d->opcode == i40e_aqc_opc_mac_address_read) {
231
#ifdef DEBUG_ADMINQ
232
        queue.log << "  read mac" << logger::endl;
233
#endif
234
235
236
237
238
239
        struct i40e_aqc_mac_address_read *ar =
            reinterpret_cast<struct i40e_aqc_mac_address_read *>(
                    d->params.raw);

        struct i40e_aqc_mac_address_read_data ard;
        uint64_t mac = runner->get_mac_addr();
240
#ifdef DEBUG_ADMINQ
241
        queue.log << "    mac = " << mac << logger::endl;
242
#endif
243
244
245
246
        memcpy(ard.pf_lan_mac, &mac, 6);
        memcpy(ard.port_mac, &mac, 6);

        ar->command_flags = I40E_AQC_LAN_ADDR_VALID | I40E_AQC_PORT_ADDR_VALID;
247
        desc_complete_indir(0, &ard, sizeof(ard));
248
    } else if (d->opcode == i40e_aqc_opc_get_phy_abilities) {
249
#ifdef DEBUG_ADMINQ
250
        queue.log << "  get phy abilities" << logger::endl;
251
#endif
252
253
254
255
256
257
258
259
260
261
262
263
        struct i40e_aq_get_phy_abilities_resp par;
        memset(&par, 0, sizeof(par));

        par.phy_type = (1ULL << I40E_PHY_TYPE_40GBASE_CR4_CU);
        par.link_speed = I40E_LINK_SPEED_40GB;
        par.abilities = I40E_AQ_PHY_LINK_ENABLED |
            I40E_AQ_PHY_AN_ENABLED;
        par.eee_capability = 0;

        d->params.external.param0 = 0;
        d->params.external.param1 = 0;

264
        desc_complete_indir(0, &par, sizeof(par), 0, true);
265
    } else if (d->opcode == i40e_aqc_opc_get_link_status) {
266
#ifdef DEBUG_ADMINQ
267
        queue.log << "  link status" << logger::endl;
268
#endif
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
        struct i40e_aqc_get_link_status *gls =
            reinterpret_cast<struct i40e_aqc_get_link_status *>(
                    d->params.raw);

        gls->command_flags &= I40E_AQ_LSE_IS_ENABLED; // should actually return
                                                      // status of link status
                                                      // notification
        gls->phy_type = I40E_PHY_TYPE_40GBASE_CR4_CU;
        gls->link_speed = I40E_LINK_SPEED_40GB;
        gls->link_info = I40E_AQ_LINK_UP_FUNCTION | I40E_AQ_LINK_UP_PORT |
            I40E_AQ_MEDIA_AVAILABLE | I40E_AQ_SIGNAL_DETECT;
        gls->an_info = I40E_AQ_AN_COMPLETED | I40E_AQ_LP_AN_ABILITY; // might need qualified module
        gls->ext_info = 0;
        gls->loopback = I40E_AQ_LINK_POWER_CLASS_4 << I40E_AQ_PWR_CLASS_SHIFT_LB;
        gls->max_frame_size = dev.MAX_MTU;
        gls->config = I40E_AQ_CONFIG_CRC_ENA;

286
        desc_complete(0);
287
    } else if (d->opcode == i40e_aqc_opc_get_switch_config) {
288
#ifdef DEBUG_ADMINQ
289
        queue.log << "  get switch config" << logger::endl;
290
#endif
291
292
293
        struct i40e_aqc_switch_seid *sw = reinterpret_cast<
            struct i40e_aqc_switch_seid *>(d->params.raw);
        struct i40e_aqc_get_switch_config_header_resp hr;
294
        /* Not sure why dpdk doesn't like this?
295
        struct i40e_aqc_switch_config_element_resp els[] = {
296
297
            // EMC
            { I40E_AQ_SW_ELEM_TYPE_EMP, I40E_AQ_SW_ELEM_REV_1, 1, 513, 0, {},
298
                I40E_AQ_CONN_TYPE_REGULAR, 0, 0},
299
300
            // MAC
            { I40E_AQ_SW_ELEM_TYPE_MAC, I40E_AQ_SW_ELEM_REV_1, 2, 0, 0, {},
301
302
                I40E_AQ_CONN_TYPE_REGULAR, 0, 0},
            // PF
303
304
305
306
307
308
309
310
311
312
313
314
            { I40E_AQ_SW_ELEM_TYPE_PF, I40E_AQ_SW_ELEM_REV_1, 16, 512, 0, {},
                I40E_AQ_CONN_TYPE_REGULAR, 0, 0},
            // VSI PF
            { I40E_AQ_SW_ELEM_TYPE_VSI, I40E_AQ_SW_ELEM_REV_1, 512, 2, 16, {},
                I40E_AQ_CONN_TYPE_REGULAR, 0, 0},
            // VSI PF
            { I40E_AQ_SW_ELEM_TYPE_VSI, I40E_AQ_SW_ELEM_REV_1, 513, 2, 1, {},
                I40E_AQ_CONN_TYPE_REGULAR, 0, 0},
        };*/
        struct i40e_aqc_switch_config_element_resp els[] = {
            // VSI PF
            { I40E_AQ_SW_ELEM_TYPE_VSI, I40E_AQ_SW_ELEM_REV_1, 512, 2, 16, {},
315
316
317
                I40E_AQ_CONN_TYPE_REGULAR, 0, 0},
        };

318

319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
        // find start idx
        size_t cnt = sizeof(els) / sizeof(els[0]);
        size_t first = 0;
        for (first = 0; first < cnt && els[first].seid < sw->seid; first++);

        // figure out how many fit in the buffer
        size_t max = (d->datalen - sizeof(hr)) / sizeof(els[0]);
        size_t report = cnt - first;
        if (report > max) {
            report = max;
            sw->seid = els[first + report].seid;
        } else {
            sw->seid = 0;
        }

        // prepare header
        memset(&hr, 0, sizeof(hr));
        hr.num_reported = report;
        hr.num_total = cnt;
338
#ifdef DEBUG_ADMINQ
339
340
        queue.log << "    report=" << report << " cnt=" << cnt <<
            "  seid=" << sw->seid << logger::endl;
341
#endif
342
343
344
345
346
347
348

        // create temporary contiguous buffer
        size_t buflen = sizeof(hr) + sizeof(els[0]) * report;
        uint8_t buf[buflen];
        memcpy(buf, &hr, sizeof(hr));
        memcpy(buf + sizeof(hr), els + first, sizeof(els[0]) * report);

349
        desc_complete_indir(0, buf, buflen);
350
    } else if (d->opcode == i40e_aqc_opc_set_switch_config) {
351
#ifdef DEBUG_ADMINQ
352
        queue.log << "  set switch config" << logger::endl;
353
#endif
354
355
356
357
358
359
        /* TODO: lots of interesting things here like l2 filtering etc. that are
         * relevant.
        struct i40e_aqc_set_switch_config *sc =
            reinterpret_cast<struct i40e_aqc_set_switch_config *>(
                    d->params.raw);
        */
360
        desc_complete(0);
361
    } else if (d->opcode == i40e_aqc_opc_get_vsi_parameters) {
362
#ifdef DEBUG_ADMINQ
363
        queue.log << "  get vsi parameters" << logger::endl;
364
#endif
Antoine Kaufmann's avatar
Antoine Kaufmann committed
365
        /*struct i40e_aqc_add_get_update_vsi *v =
366
            reinterpret_cast<struct i40e_aqc_add_get_update_vsi *>(
Antoine Kaufmann's avatar
Antoine Kaufmann committed
367
                    d->params.raw);*/
368
369
370
371
372
373
374

        struct i40e_aqc_vsi_properties_data pd;
        memset(&pd, 0, sizeof(pd));
        pd.valid_sections |= I40E_AQ_VSI_PROP_SWITCH_VALID |
            I40E_AQ_VSI_PROP_QUEUE_MAP_VALID |
            I40E_AQ_VSI_PROP_QUEUE_OPT_VALID |
            I40E_AQ_VSI_PROP_SCHED_VALID;
375
        desc_complete_indir(0, &pd, sizeof(pd));
376
    } else if (d->opcode == i40e_aqc_opc_update_vsi_parameters) {
377
#ifdef DEBUG_ADMINQ
378
        queue.log << "  update vsi parameters" << logger::endl;
379
#endif
380
        /* TODO */
381
        desc_complete(0);
382
    } else if (d->opcode == i40e_aqc_opc_set_dcb_parameters) {
383
#ifdef DEBUG_ADMINQ
384
        queue.log << "  set dcb parameters" << logger::endl;
385
#endif
386
        /* TODO */
387
        desc_complete(0);
388
    } else if (d->opcode == i40e_aqc_opc_configure_vsi_bw_limit) {
389
#ifdef DEBUG_ADMINQ
390
        queue.log << "  configure vsi bw limit" << logger::endl;
391
#endif
392
        desc_complete(0);
393
    } else if (d->opcode == i40e_aqc_opc_query_vsi_bw_config) {
394
#ifdef DEBUG_ADMINQ
395
        queue.log << "  query vsi bw config" << logger::endl;
396
#endif
397
398
399
400
        struct i40e_aqc_query_vsi_bw_config_resp bwc;
        memset(&bwc, 0, sizeof(bwc));
        for (size_t i = 0; i < 8; i++)
            bwc.qs_handles[i] = 0xffff;
401
        desc_complete_indir(0, &bwc, sizeof(bwc));
402
    } else if (d->opcode == i40e_aqc_opc_query_vsi_ets_sla_config) {
403
#ifdef DEBUG_ADMINQ
404
        queue.log << "  query vsi ets sla config" << logger::endl;
405
#endif
406
407
408
409
        struct i40e_aqc_query_vsi_ets_sla_config_resp sla;
        memset(&sla, 0, sizeof(sla));
        for (size_t i = 0; i < 8; i++)
            sla.share_credits[i] = 127;
410
        desc_complete_indir(0, &sla, sizeof(sla));
411
    } else if (d->opcode == i40e_aqc_opc_remove_macvlan) {
412
#ifdef DEBUG_ADMINQ
413
        queue.log << "  remove macvlan" << logger::endl;
414
#endif
415
416
417
418
419
420
421
422
        struct i40e_aqc_macvlan *m = reinterpret_cast<
            struct i40e_aqc_macvlan *>(d->params.raw);
        struct i40e_aqc_remove_macvlan_element_data *rve =
            reinterpret_cast<struct i40e_aqc_remove_macvlan_element_data *>(
                    data);
        for (uint16_t i = 0; i < m->num_addresses; i++)
            rve[i].error_code = I40E_AQC_REMOVE_MACVLAN_SUCCESS;

423
        desc_complete_indir(0, data, d->datalen);
424
    } else {
425
#ifdef DEBUG_ADMINQ
426
        queue.log << "  uknown opcode=" << d->opcode << logger::endl;
427
#endif
428
429
        //desc_complete(I40E_AQ_RC_ESRCH);
        desc_complete(0);
430
431
    }
}