Skip to content

Commit d176ec3

Browse files
committed
nvme: Add support for set-reg command to write nvme register
Note: For fabrics properties not supported to set by the command. Signed-off-by: Tokunori Ikegami <ikegami.t@gmail.com>
1 parent 71d9a9a commit d176ec3

File tree

3 files changed

+95
-4
lines changed

3 files changed

+95
-4
lines changed

common.h

+18-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,24 @@ static inline uint64_t mmio_read64(void *addr)
3232
low = le32_to_cpu(*p);
3333
high = le32_to_cpu(*(p + 1));
3434

35-
return ((uint64_t) high << 32) | low;
35+
return ((uint64_t)high << 32) | low;
3636
}
3737

38+
static inline void mmio_write32(void *addr, uint32_t value)
39+
{
40+
leint32_t *p = addr;
41+
42+
*p = cpu_to_le32(value);
43+
}
44+
45+
/* Access 64-bit registers as 2 32-bit; Some devices fail 64-bit MMIO. */
46+
static inline void mmio_write64(void *addr, uint64_t value)
47+
{
48+
uint32_t *p = addr;
49+
uint32_t low = value;
50+
uint32_t high = value >> 32;
51+
52+
*p = cpu_to_le32(low);
53+
*(p + 1) = cpu_to_le32(high);
54+
}
3855
#endif

nvme-builtin.h

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ COMMAND_LIST(
8989
ENTRY("subsystem-reset", "Resets the subsystem", subsystem_reset)
9090
ENTRY("ns-rescan", "Rescans the NVME namespaces", ns_rescan)
9191
ENTRY("show-regs", "Shows the controller registers or properties. Requires character device", show_registers)
92+
ENTRY("set-reg", "Set a register and show the resulting value", set_register)
9293
ENTRY("get-reg", "Get a register and show the resulting value", get_register)
9394
ENTRY("discover", "Discover NVMeoF subsystems", discover_cmd)
9495
ENTRY("connect-all", "Discover and Connect to NVMeoF subsystems", connect_all_cmd)

nvme.c

+76-3
Original file line numberDiff line numberDiff line change
@@ -5214,14 +5214,15 @@ static int nvme_get_properties(int fd, void **pbar)
52145214
return err;
52155215
}
52165216

5217-
static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev)
5217+
static void *mmap_registers_prot(nvme_root_t r, struct nvme_dev *dev, int prot)
52185218
{
52195219
nvme_ctrl_t c = NULL;
52205220
nvme_ns_t n = NULL;
52215221

52225222
char path[512];
52235223
void *membase;
52245224
int fd;
5225+
int flags = prot | PROT_WRITE ? O_RDWR : O_RDONLY;
52255226

52265227
c = nvme_scan_ctrl(r, dev->name);
52275228
if (c) {
@@ -5239,15 +5240,15 @@ static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev)
52395240
nvme_free_ns(n);
52405241
}
52415242

5242-
fd = open(path, O_RDONLY);
5243+
fd = open(path, flags);
52435244
if (fd < 0) {
52445245
if (map_log_level(0, false) >= LOG_DEBUG)
52455246
nvme_show_error("%s did not find a pci resource, open failed %s",
52465247
dev->name, strerror(errno));
52475248
return NULL;
52485249
}
52495250

5250-
membase = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd, 0);
5251+
membase = mmap(NULL, getpagesize(), prot, MAP_SHARED, fd, 0);
52515252
if (membase == MAP_FAILED) {
52525253
if (map_log_level(0, false) >= LOG_DEBUG) {
52535254
fprintf(stderr, "%s failed to map. ", dev->name);
@@ -5260,6 +5261,11 @@ static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev)
52605261
return membase;
52615262
}
52625263

5264+
static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev)
5265+
{
5266+
return mmap_registers_prot(r, dev, PROT_READ);
5267+
}
5268+
52635269
static int show_registers(int argc, char **argv, struct command *cmd, struct plugin *plugin)
52645270
{
52655271
const char *desc = "Reads and shows the defined NVMe controller registers\n"
@@ -5393,6 +5399,7 @@ static int get_register(int argc, char **argv, struct command *cmd, struct plugi
53935399
r = nvme_scan(NULL);
53945400
bar = mmap_registers(r, dev);
53955401
if (!bar) {
5402+
err = -errno;
53965403
err = nvme_get_properties(dev_fd(dev), &bar);
53975404
if (err)
53985405
goto free_tree;
@@ -5409,6 +5416,72 @@ static int get_register(int argc, char **argv, struct command *cmd, struct plugi
54095416
return err;
54105417
}
54115418

5419+
static void nvme_set_register(void *bar, int offset, uint64_t value)
5420+
{
5421+
if (nvme_is_64bit_reg(offset))
5422+
mmio_write64(bar + offset, value);
5423+
else
5424+
mmio_write32(bar + offset, value);
5425+
}
5426+
5427+
static int set_register(int argc, char **argv, struct command *cmd, struct plugin *plugin)
5428+
{
5429+
const char *desc =
5430+
"Writes and shows the defined NVMe controller register";
5431+
const char *offset = "the offset of the register";
5432+
const char *value = "the value of the register to be set";
5433+
5434+
_cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
5435+
int err;
5436+
nvme_root_t r;
5437+
void *bar;
5438+
5439+
struct config {
5440+
int offset;
5441+
uint64_t value;
5442+
};
5443+
5444+
struct config cfg = {
5445+
.offset = -1,
5446+
.value = 0,
5447+
};
5448+
5449+
NVME_ARGS(opts, cfg,
5450+
OPT_UINT("offset", 'O', &cfg.offset, offset),
5451+
OPT_SUFFIX("value", 'V', &cfg.value, value));
5452+
5453+
err = parse_and_open(&dev, argc, argv, desc, opts);
5454+
if (err)
5455+
return err;
5456+
5457+
if (!argconfig_parse_seen(opts, "offset")) {
5458+
nvme_show_error("offset required param");
5459+
return -EINVAL;
5460+
}
5461+
5462+
if (!argconfig_parse_seen(opts, "value")) {
5463+
nvme_show_error("value required param");
5464+
return -EINVAL;
5465+
}
5466+
5467+
r = nvme_scan(NULL);
5468+
bar = mmap_registers_prot(r, dev, PROT_READ | PROT_WRITE);
5469+
if (!bar) {
5470+
nvme_show_error("Failed to map");
5471+
return -EINVAL;
5472+
}
5473+
5474+
nvme_set_register(bar, cfg.offset, cfg.value);
5475+
5476+
printf("set-register: %02x (%s), value: %"PRIx64"\n", cfg.offset,
5477+
nvme_register_to_string(cfg.offset), cfg.value);
5478+
5479+
munmap(bar, getpagesize());
5480+
nvme_free_tree(r);
5481+
5482+
return err;
5483+
}
5484+
54125485
static int get_property(int argc, char **argv, struct command *cmd, struct plugin *plugin)
54135486
{
54145487
const char *desc = "Reads and shows the defined NVMe controller property\n"

0 commit comments

Comments
 (0)