Skip to content

Commit

Permalink
nvme: add virtualization management
Browse files Browse the repository at this point in the history
Add support for Virtualization Management through a set of helpers.

Signed-off-by: Klaus Jensen <[email protected]>
  • Loading branch information
birkelund committed Sep 23, 2024
1 parent 5a3cd91 commit 60b06fe
Show file tree
Hide file tree
Showing 5 changed files with 292 additions and 1 deletion.
1 change: 1 addition & 0 deletions examples/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ examples = {
'io': ['io.c'],
'perf': ['perf.c'],
'regs': ['regs.c'],
'sriov': ['sriov.c'],
}

foreach example, sources : examples
Expand Down
86 changes: 86 additions & 0 deletions examples/sriov.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: GPL-2.0-or-later

/*
* This file is part of libvfn.
*
* Copyright (C) 2022 The libvfn Authors. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/

#include <vfn/nvme.h>
#include <vfn/pci.h>

#include <nvme/types.h>

#include "ccan/err/err.h"
#include "ccan/opt/opt.h"
#include "ccan/str/str.h"

#include "common.h"

static int vfnum;

static struct opt_table opts[] = {
OPT_SUBTABLE(opts_base, NULL),
OPT_WITH_ARG("-s|--secondary VFNUM", opt_set_intval, opt_show_intval, &vfnum,
"secondary controller virtual function number"),
OPT_ENDTABLE,
};

int main(int argc, char **argv)
{
char *vf_bdf;
uint16_t scid;

struct nvme_ctrl ctrl = {}, sctrl = {};

opt_register_table(opts, NULL);
opt_parse(&argc, argv, opt_log_stderr_exit);

if (show_usage)
opt_usage_and_exit(NULL);

if (streq(bdf, ""))
opt_usage_exit_fail("missing --device parameter");

opt_free_table();

if (nvme_init(&ctrl, bdf, NULL))
err(1, "failed to init nvme controller");

vf_bdf = pci_get_vf_bdf(bdf, vfnum);
if (!vf_bdf)
err(1, "pci_get_vf_bdf");

if (vfio_pci_open(&sctrl.pci, vf_bdf))
err(1, "vfio_pci_open");

if (nvme_get_vf_cntlid(&ctrl, vfnum, &scid))
err(1, "nvme_get_vf_cntlid");

if (nvme_vm_set_offline(&ctrl, scid))
err(1, "could not offline secondary controller");

if (nvme_vm_assign_max_flexible(&ctrl, scid))
err(1, "could not assign resources");

if (vfio_reset(&sctrl.pci.dev))
err(1, "vfio_reset");

if (nvme_vm_set_online(&ctrl, scid))
err(1, "could not online secondary controller");

if (nvme_init(&sctrl, vf_bdf, NULL))
err(1, "failed to init nvme controller");

return 0;
}
54 changes: 54 additions & 0 deletions include/vfn/nvme/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,58 @@ int nvme_sync(struct nvme_ctrl *ctrl, struct nvme_sq *sq, union nvme_cmd *sqe, v
int nvme_admin(struct nvme_ctrl *ctrl, union nvme_cmd *sqe, void *buf, size_t len,
struct nvme_cqe *cqe_copy);

/**
* nvme_vm_assign_max_flexible - Assign the maximum number of flexible resources
* to secondary controller
* @ctrl: primary controller &struct nvme_ctrl
* @scid: secondary controller identifier
*
* Use the VQFRSM and VIFRSM fields of the Primary Controller Capabilities
* Identify data structure to determine the maximum number of flexible resources
* that can be assigned to a single VF and assign that.
*
* Return: On success, returns ``0``; on error, returns ``-1`` and sets
* ``errno``.
*/
int nvme_vm_assign_max_flexible(struct nvme_ctrl *ctrl, uint16_t scid);

/**
* nvme_vm_set_online - Online a secondary controller
* @ctrl: primary controller &struct nvme_ctrl
* @scid: secondary controller identifier
*
* Online a secondary controller.
*
* Return: On success, returns ``0``; on error, returns ``-1`` and sets
* ``errno``.
*/
int nvme_vm_set_online(struct nvme_ctrl *ctrl, uint16_t scid);

/**
* nvme_vm_set_offline - Offline a secondary controller
* @ctrl: primary controller &struct nvme_ctrl
* @scid: secondary controller identifier
*
* Offline a secondary controller.
*
* Return: On success, returns ``0``; on error, returns ``-1`` and sets
* ``errno``.
*/
int nvme_vm_set_offline(struct nvme_ctrl *ctrl, uint16_t scid);

/**
* nvme_get_vf_cntlid - Get the controller identifier for a VF
* @ctrl: primary controller &struct nvme_ctrl
* @vfnum: virtual function number
* @cntlid: output parameter for the secondary controller identifier
*
* Use the Secondary Controller List Identify data structure to determine the
* controller identifier of the secondary controller identified by a Virtual
* Function Number.
*
* Return: On success, returns ``0``; on error, returns ``-1`` and sets
* ``errno``.
*/
int nvme_get_vf_cntlid(struct nvme_ctrl *ctrl, int vfnum, uint16_t *cntlid);

#endif /* LIBVFN_NVME_UTIL_H */
57 changes: 56 additions & 1 deletion src/nvme/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,14 @@ enum nvme_admin_opcode {
NVME_ADMIN_IDENTIFY = 0x06,
NVME_ADMIN_SET_FEATURES = 0x09,
NVME_ADMIN_ASYNC_EVENT = 0x0c,
NVME_ADMIN_VIRT_MGMT = 0x1c,
NVME_ADMIN_DBCONFIG = 0x7c,
};

enum nvme_identify_cns {
NVME_IDENTIFY_CNS_CTRL = 0x01,
NVME_IDENTIFY_CNS_CTRL = 0x01,
NVME_IDENTIFY_CNS_PRIMARY_CTRL_CAP = 0x14,
NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST = 0x15,
};

enum nvme_identify_ctrl_offset {
Expand All @@ -117,3 +120,55 @@ enum nvme_identify_ctrl_sgls {
NVME_IDENTIFY_CTRL_SGLS_ALIGNMENT_NONE = 0x1,
NVME_IDENTIFY_CTRL_SGLS_ALIGNMENT_DWORD = 0x2,
};

struct nvme_primary_ctrl_cap {
leint16_t cntlid;
leint16_t portid;
uint8_t crt;
uint8_t rsvd5[27];
leint32_t vqfrt;
leint32_t vqrfa;
leint16_t vqrfap;
leint16_t vqprt;
leint16_t vqfrsm;
leint16_t vqgran;
uint8_t rsvd48[16];
leint32_t vifrt;
leint32_t virfa;
leint16_t virfap;
leint16_t viprt;
leint16_t vifrsm;
leint16_t vigran;
uint8_t rsvd80[4016];
};

struct nvme_secondary_ctrl {
leint16_t scid;
leint16_t pcid;
uint8_t scs;
uint8_t rsvd5[3];
leint16_t vfn;
leint16_t nvq;
leint16_t nvi;
uint8_t rsvd14[18];
};

#define NVME_ID_SECONDARY_CTRL_MAX 127

struct nvme_secondary_ctrl_list {
uint8_t num;
uint8_t rsvd[31];
struct nvme_secondary_ctrl sc_entry[NVME_ID_SECONDARY_CTRL_MAX];
};

enum nvme_virt_mgmt_rt {
NVME_VIRT_MGMT_RESOURCE_TYPE_VQ = 0x0,
NVME_VIRT_MGMT_RESOURCE_TYPE_VI = 0x1,
};

enum nvme_virt_mgmt_act {
NVME_VIRT_MGMT_ACTION_PRIMARY_ALLOC_FLEXIBLE = 0x1,
NVME_VIRT_MGMT_ACTION_SECONDARY_OFFLINE = 0x7,
NVME_VIRT_MGMT_ACTION_SECONDARY_ASSIGN_FLEXIBLE = 0x8,
NVME_VIRT_MGMT_ACTION_SECONDARY_ONLINE = 0x9,
};
95 changes: 95 additions & 0 deletions src/nvme/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,98 @@ int nvme_admin(struct nvme_ctrl *ctrl, union nvme_cmd *sqe, void *buf, size_t le
{
return nvme_sync(ctrl, ctrl->adminq.sq, sqe, buf, len, cqe_copy);
}

static int nvme_virt_mgmt(struct nvme_ctrl *ctrl, uint16_t cntlid, enum nvme_virt_mgmt_rt rt,
enum nvme_virt_mgmt_act act, uint16_t nr)
{
union nvme_cmd cmd = {
.opcode = NVME_ADMIN_VIRT_MGMT,

.cdw10 = cpu_to_le32(cntlid << 16 | rt << 8 | act),
.cdw11 = cpu_to_le32(nr),
};

return nvme_admin(ctrl, &cmd, NULL, 0, NULL);
}

int nvme_vm_assign_max_flexible(struct nvme_ctrl *ctrl, uint16_t scid)
{
struct iommu_ctx *ctx = __iommu_ctx(ctrl);

union nvme_cmd cmd;
struct nvme_primary_ctrl_cap *cap;

__autovar_s(iommu_dmabuf) buffer;

if (iommu_get_dmabuf(ctx, &buffer, NVME_IDENTIFY_DATA_SIZE, IOMMU_MAP_EPHEMERAL))
return -1;

cmd.identify = (struct nvme_cmd_identify) {
.opcode = NVME_ADMIN_IDENTIFY,
.cns = NVME_IDENTIFY_CNS_PRIMARY_CTRL_CAP,
};

if (nvme_admin(ctrl, &cmd, buffer.vaddr, buffer.len, NULL))
return -1;

cap = buffer.vaddr;

if (nvme_virt_mgmt(ctrl, scid, NVME_VIRT_MGMT_RESOURCE_TYPE_VQ,
NVME_VIRT_MGMT_ACTION_SECONDARY_ASSIGN_FLEXIBLE,
le16_to_cpu(cap->vqfrsm)))
return -1;

if (nvme_virt_mgmt(ctrl, scid, NVME_VIRT_MGMT_RESOURCE_TYPE_VI,
NVME_VIRT_MGMT_ACTION_SECONDARY_ASSIGN_FLEXIBLE,
le16_to_cpu(cap->vifrsm)))
return -1;

return 0;
}

int nvme_get_vf_cntlid(struct nvme_ctrl *ctrl, int vfnum, uint16_t *cntlid)
{
struct iommu_ctx *ctx = __iommu_ctx(ctrl);

union nvme_cmd cmd;
struct nvme_secondary_ctrl_list *list;

__autovar_s(iommu_dmabuf) buffer;

if (iommu_get_dmabuf(ctx, &buffer, NVME_IDENTIFY_DATA_SIZE, IOMMU_MAP_EPHEMERAL))
return -1;

cmd.identify = (struct nvme_cmd_identify) {
.opcode = NVME_ADMIN_IDENTIFY,
.cns = NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST,
};

if (nvme_admin(ctrl, &cmd, buffer.vaddr, buffer.len, NULL))
return -1;

list = buffer.vaddr;

for (uint8_t i = 0; i < list->num; i++) {
struct nvme_secondary_ctrl *sctrl = &list->sc_entry[i];

if (le16_to_cpu(sctrl->vfn) == vfnum) {
*cntlid = le16_to_cpu(sctrl->scid);

return 0;
}
}

errno = ENOENT;

return -1;
}

int nvme_vm_set_online(struct nvme_ctrl *ctrl, uint16_t scid)
{
return nvme_virt_mgmt(ctrl, scid, 0, NVME_VIRT_MGMT_ACTION_SECONDARY_ONLINE, 0);
}

int nvme_vm_set_offline(struct nvme_ctrl *ctrl, uint16_t scid)
{
return nvme_virt_mgmt(ctrl, scid, 0, NVME_VIRT_MGMT_ACTION_SECONDARY_OFFLINE, 0);
}

0 comments on commit 60b06fe

Please sign in to comment.