i40e_adminq.cc 14.8 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
#include <stdlib.h>
#include <string.h>
27

28
29
30
#include <cassert>
#include <iostream>

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

using namespace i40e;

extern nicbm::Runner *runner;

queue_admin_tx::queue_admin_tx(i40e_bm &dev_, uint64_t &reg_base_,
39
40
41
42
43
44
45
46
                               uint32_t &reg_len_, uint32_t &reg_head_,
                               uint32_t &reg_tail_)
    : queue_base("atx", reg_head_, reg_tail_),
      dev(dev_),
      reg_base(reg_base_),
      reg_len(reg_len_) {
  desc_len = 32;
  ctxs_init();
47
48
}

49
50
queue_base::desc_ctx &queue_admin_tx::desc_ctx_create() {
  return *new admin_desc_ctx(*this, dev);
51
52
}

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

57
  if (!enabled && (reg_len & I40E_GL_ATQLEN_ATQENABLE_MASK)) {
58
#ifdef DEBUG_ADMINQ
59
    log << " enable base=" << base << " len=" << len << logger::endl;
60
#endif
61
62
    enabled = true;
  } else if (enabled && !(reg_len & I40E_GL_ATQLEN_ATQENABLE_MASK)) {
63
#ifdef DEBUG_ADMINQ
64
    log << " disable" << logger::endl;
65
#endif
66
67
    enabled = false;
  }
68

69
  queue_base::reg_updated();
70
71
72
}

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

78
79
void queue_admin_tx::admin_desc_ctx::data_written(uint64_t addr, size_t len) {
  processed();
80
81
82
}

void queue_admin_tx::admin_desc_ctx::desc_compl_prepare(uint16_t retval,
83
84
85
86
87
88
                                                        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
89
90

#ifdef DEBUG_ADMINQ
91
92
  queue.log << " desc_compl_prepare index=" << index << " retval=" << retval
            << logger::endl;
Antoine Kaufmann's avatar
Antoine Kaufmann committed
93
#endif
94
95
}

96
void queue_admin_tx::admin_desc_ctx::desc_complete(uint16_t retval,
97
98
99
                                                   uint16_t extra_flags) {
  desc_compl_prepare(retval, extra_flags);
  processed();
100
101
}

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

  desc_compl_prepare(retval, extra_flags);

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

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

135
void queue_admin_tx::admin_desc_ctx::process() {
136
#ifdef DEBUG_ADMINQ
137
  queue.log << " descriptor " << index << " fetched" << logger::endl;
138
#endif
139

140
  if (d->opcode == i40e_aqc_opc_get_version) {
141
#ifdef DEBUG_ADMINQ
142
    queue.log << "  get version" << logger::endl;
143
#endif
144
145
146
147
148
149
150
151
152
153
154
    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;

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

    if (sizeof(caps) <= d->datalen) {
202
#ifdef DEBUG_ADMINQ
203
      queue.log << "    data fits" << logger::endl;
204
#endif
205
206
207
208
      // data fits within the buffer
      lc->count = num_caps;
      desc_complete_indir(0, caps, sizeof(caps));
    } else {
209
#ifdef DEBUG_ADMINQ
210
      queue.log << "    data doesn't fit" << logger::endl;
211
#endif
212
213
214
215
216
      // data does not fit
      d->datalen = sizeof(caps);
      desc_complete(I40E_AQ_RC_ENOMEM);
    }
  } else if (d->opcode == i40e_aqc_opc_lldp_stop) {
217
#ifdef DEBUG_ADMINQ
218
    queue.log << "  lldp stop" << logger::endl;
219
#endif
220
221
    desc_complete(0);
  } else if (d->opcode == i40e_aqc_opc_mac_address_read) {
222
#ifdef DEBUG_ADMINQ
223
    queue.log << "  read mac" << logger::endl;
224
#endif
225
226
    struct i40e_aqc_mac_address_read *ar =
        reinterpret_cast<struct i40e_aqc_mac_address_read *>(d->params.raw);
227

228
    struct i40e_aqc_mac_address_read_data ard;
229
    uint64_t mac = runner->GetMacAddr();
230
#ifdef DEBUG_ADMINQ
231
    queue.log << "    mac = " << mac << logger::endl;
232
#endif
233
234
    memcpy(ard.pf_lan_mac, &mac, 6);
    memcpy(ard.port_mac, &mac, 6);
235

236
237
238
    ar->command_flags = I40E_AQC_LAN_ADDR_VALID | I40E_AQC_PORT_ADDR_VALID;
    desc_complete_indir(0, &ard, sizeof(ard));
  } else if (d->opcode == i40e_aqc_opc_get_phy_abilities) {
239
#ifdef DEBUG_ADMINQ
240
    queue.log << "  get phy abilities" << logger::endl;
241
#endif
242
243
    struct i40e_aq_get_phy_abilities_resp par;
    memset(&par, 0, sizeof(par));
244

245
246
247
248
    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;
249

250
251
    d->params.external.param0 = 0;
    d->params.external.param1 = 0;
252

253
254
    desc_complete_indir(0, &par, sizeof(par), 0, true);
  } else if (d->opcode == i40e_aqc_opc_get_link_status) {
255
#ifdef DEBUG_ADMINQ
256
    queue.log << "  link status" << logger::endl;
257
#endif
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
    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;
    // might need qualified module
    gls->an_info = I40E_AQ_AN_COMPLETED | I40E_AQ_LP_AN_ABILITY;
    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;

    desc_complete(0);
  } else if (d->opcode == i40e_aqc_opc_get_switch_config) {
277
#ifdef DEBUG_ADMINQ
278
    queue.log << "  get switch config" << logger::endl;
279
#endif
280
281
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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
    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;
    /* Not sure why dpdk doesn't like this?
    struct i40e_aqc_switch_config_element_resp els[] = {
        // EMC
        { I40E_AQ_SW_ELEM_TYPE_EMP, I40E_AQ_SW_ELEM_REV_1, 1, 513, 0, {},
            I40E_AQ_CONN_TYPE_REGULAR, 0, 0},
        // MAC
        { I40E_AQ_SW_ELEM_TYPE_MAC, I40E_AQ_SW_ELEM_REV_1, 2, 0, 0, {},
            I40E_AQ_CONN_TYPE_REGULAR, 0, 0},
        // PF
        { 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,
         {},
         I40E_AQ_CONN_TYPE_REGULAR,
         0,
         0},
    };

    // 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;
334
#ifdef DEBUG_ADMINQ
335
336
    queue.log << "    report=" << report << " cnt=" << cnt
              << "  seid=" << sw->seid << logger::endl;
337
#endif
338

339
340
341
342
343
    // 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);
344

345
346
    desc_complete_indir(0, buf, buflen);
  } else if (d->opcode == i40e_aqc_opc_set_switch_config) {
347
#ifdef DEBUG_ADMINQ
348
    queue.log << "  set switch config" << logger::endl;
349
#endif
350
351
352
353
354
355
356
357
    /* 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);
    */
    desc_complete(0);
  } else if (d->opcode == i40e_aqc_opc_get_vsi_parameters) {
358
#ifdef DEBUG_ADMINQ
359
    queue.log << "  get vsi parameters" << logger::endl;
360
#endif
361
362
363
364
365
366
367
368
369
370
371
    /*struct i40e_aqc_add_get_update_vsi *v =
        reinterpret_cast<struct i40e_aqc_add_get_update_vsi *>(
                d->params.raw);*/

    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;
    desc_complete_indir(0, &pd, sizeof(pd));
  } else if (d->opcode == i40e_aqc_opc_update_vsi_parameters) {
372
#ifdef DEBUG_ADMINQ
373
    queue.log << "  update vsi parameters" << logger::endl;
374
#endif
375
376
377
    /* TODO */
    desc_complete(0);
  } else if (d->opcode == i40e_aqc_opc_set_dcb_parameters) {
378
#ifdef DEBUG_ADMINQ
379
    queue.log << "  set dcb parameters" << logger::endl;
380
#endif
381
382
383
    /* TODO */
    desc_complete(0);
  } else if (d->opcode == i40e_aqc_opc_configure_vsi_bw_limit) {
384
#ifdef DEBUG_ADMINQ
385
    queue.log << "  configure vsi bw limit" << logger::endl;
386
#endif
387
388
    desc_complete(0);
  } else if (d->opcode == i40e_aqc_opc_query_vsi_bw_config) {
389
#ifdef DEBUG_ADMINQ
390
    queue.log << "  query vsi bw config" << logger::endl;
391
#endif
392
393
394
395
396
    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;
    desc_complete_indir(0, &bwc, sizeof(bwc));
  } else if (d->opcode == i40e_aqc_opc_query_vsi_ets_sla_config) {
397
#ifdef DEBUG_ADMINQ
398
    queue.log << "  query vsi ets sla config" << logger::endl;
399
#endif
400
401
402
403
404
    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;
    desc_complete_indir(0, &sla, sizeof(sla));
  } else if (d->opcode == i40e_aqc_opc_remove_macvlan) {
405
#ifdef DEBUG_ADMINQ
406
    queue.log << "  remove macvlan" << logger::endl;
407
#endif
408
409
410
411
412
413
414
415
416
    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;

    desc_complete_indir(0, data, d->datalen);
  } else {
417
#ifdef DEBUG_ADMINQ
418
    queue.log << "  uknown opcode=" << d->opcode << logger::endl;
419
#endif
420
421
422
    // desc_complete(I40E_AQ_RC_ESRCH);
    desc_complete(0);
  }
423
}