mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-05 09:21:05 +00:00

In kernel commit e1d2e8873369 ("IB/core: Add PCI write end padding flags for WQ and QP"), we introduced new device capability to advertise PCI write end padding. PCI write end padding is the device's ability to pad the ending of incoming packets (scatter) to full cache line such that the last upstream write generated by an incoming packet will be a full cache line. This commit updates RDMAtool to present this field. Signed-off-by: Leon Romanovsky <leonro@mellanox.com> Signed-off-by: David Ahern <dsahern@gmail.com>
260 lines
5.9 KiB
C
260 lines
5.9 KiB
C
/*
|
|
* dev.c RDMA tool
|
|
*
|
|
* 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.
|
|
*
|
|
* Authors: Leon Romanovsky <leonro@mellanox.com>
|
|
*/
|
|
|
|
#include "rdma.h"
|
|
|
|
static int dev_help(struct rd *rd)
|
|
{
|
|
pr_out("Usage: %s dev show [DEV]\n", rd->filename);
|
|
return 0;
|
|
}
|
|
|
|
static const char *dev_caps_to_str(uint32_t idx)
|
|
{
|
|
#define RDMA_DEV_FLAGS(x) \
|
|
x(RESIZE_MAX_WR, 0) \
|
|
x(BAD_PKEY_CNTR, 1) \
|
|
x(BAD_QKEY_CNTR, 2) \
|
|
x(RAW_MULTI, 3) \
|
|
x(AUTO_PATH_MIG, 4) \
|
|
x(CHANGE_PHY_PORT, 5) \
|
|
x(UD_AV_PORT_ENFORCE_PORT_ENFORCE, 6) \
|
|
x(CURR_QP_STATE_MOD, 7) \
|
|
x(SHUTDOWN_PORT, 8) \
|
|
x(INIT_TYPE, 9) \
|
|
x(PORT_ACTIVE_EVENT, 10) \
|
|
x(SYS_IMAGE_GUID, 11) \
|
|
x(RC_RNR_NAK_GEN, 12) \
|
|
x(SRQ_RESIZE, 13) \
|
|
x(N_NOTIFY_CQ, 14) \
|
|
x(LOCAL_DMA_LKEY, 15) \
|
|
x(MEM_WINDOW, 17) \
|
|
x(UD_IP_CSUM, 18) \
|
|
x(UD_TSO, 19) \
|
|
x(XRC, 20) \
|
|
x(MEM_MGT_EXTENSIONS, 21) \
|
|
x(BLOCK_MULTICAST_LOOPBACK, 22) \
|
|
x(MEM_WINDOW_TYPE_2A, 23) \
|
|
x(MEM_WINDOW_TYPE_2B, 24) \
|
|
x(RC_IP_CSUM, 25) \
|
|
x(RAW_IP_CSUM, 26) \
|
|
x(CROSS_CHANNEL, 27) \
|
|
x(MANAGED_FLOW_STEERING, 29) \
|
|
x(SIGNATURE_HANDOVER, 30) \
|
|
x(ON_DEMAND_PAGING, 31) \
|
|
x(SG_GAPS_REG, 32) \
|
|
x(VIRTUAL_FUNCTION, 33) \
|
|
x(RAW_SCATTER_FCS, 34) \
|
|
x(RDMA_NETDEV_OPA_VNIC, 35) \
|
|
x(PCI_WRITE_END_PADDING, 36)
|
|
|
|
enum { RDMA_DEV_FLAGS(RDMA_BITMAP_ENUM) };
|
|
|
|
static const char * const
|
|
rdma_dev_names[] = { RDMA_DEV_FLAGS(RDMA_BITMAP_NAMES) };
|
|
#undef RDMA_DEV_FLAGS
|
|
|
|
if (idx < ARRAY_SIZE(rdma_dev_names) && rdma_dev_names[idx])
|
|
return rdma_dev_names[idx];
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
static void dev_print_caps(struct rd *rd, struct nlattr **tb)
|
|
{
|
|
uint64_t caps;
|
|
uint32_t idx;
|
|
|
|
if (!tb[RDMA_NLDEV_ATTR_CAP_FLAGS])
|
|
return;
|
|
|
|
caps = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_CAP_FLAGS]);
|
|
|
|
if (rd->json_output) {
|
|
jsonw_name(rd->jw, "caps");
|
|
jsonw_start_array(rd->jw);
|
|
} else {
|
|
pr_out("\n caps: <");
|
|
}
|
|
for (idx = 0; caps; idx++) {
|
|
if (caps & 0x1) {
|
|
if (rd->json_output) {
|
|
jsonw_string(rd->jw, dev_caps_to_str(idx));
|
|
} else {
|
|
pr_out("%s", dev_caps_to_str(idx));
|
|
if (caps >> 0x1)
|
|
pr_out(", ");
|
|
}
|
|
}
|
|
caps >>= 0x1;
|
|
}
|
|
|
|
if (rd->json_output)
|
|
jsonw_end_array(rd->jw);
|
|
else
|
|
pr_out(">");
|
|
}
|
|
|
|
static void dev_print_fw(struct rd *rd, struct nlattr **tb)
|
|
{
|
|
const char *str;
|
|
if (!tb[RDMA_NLDEV_ATTR_FW_VERSION])
|
|
return;
|
|
|
|
str = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_FW_VERSION]);
|
|
if (rd->json_output)
|
|
jsonw_string_field(rd->jw, "fw", str);
|
|
else
|
|
pr_out("fw %s ", str);
|
|
}
|
|
|
|
static void dev_print_node_guid(struct rd *rd, struct nlattr **tb)
|
|
{
|
|
uint64_t node_guid;
|
|
uint16_t vp[4];
|
|
char str[32];
|
|
|
|
if (!tb[RDMA_NLDEV_ATTR_NODE_GUID])
|
|
return;
|
|
|
|
node_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_NODE_GUID]);
|
|
memcpy(vp, &node_guid, sizeof(uint64_t));
|
|
snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]);
|
|
if (rd->json_output)
|
|
jsonw_string_field(rd->jw, "node_guid", str);
|
|
else
|
|
pr_out("node_guid %s ", str);
|
|
}
|
|
|
|
static void dev_print_sys_image_guid(struct rd *rd, struct nlattr **tb)
|
|
{
|
|
uint64_t sys_image_guid;
|
|
uint16_t vp[4];
|
|
char str[32];
|
|
|
|
if (!tb[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID])
|
|
return;
|
|
|
|
sys_image_guid = mnl_attr_get_u64(tb[RDMA_NLDEV_ATTR_SYS_IMAGE_GUID]);
|
|
memcpy(vp, &sys_image_guid, sizeof(uint64_t));
|
|
snprintf(str, 32, "%04x:%04x:%04x:%04x", vp[3], vp[2], vp[1], vp[0]);
|
|
if (rd->json_output)
|
|
jsonw_string_field(rd->jw, "sys_image_guid", str);
|
|
else
|
|
pr_out("sys_image_guid %s ", str);
|
|
}
|
|
|
|
static const char *node_type_to_str(uint8_t node_type)
|
|
{
|
|
static const char * const node_type_str[] = { "unknown", "ca",
|
|
"switch", "router",
|
|
"rnic", "usnic",
|
|
"usnic_dp" };
|
|
if (node_type < ARRAY_SIZE(node_type_str))
|
|
return node_type_str[node_type];
|
|
return "unknown";
|
|
}
|
|
|
|
static void dev_print_node_type(struct rd *rd, struct nlattr **tb)
|
|
{
|
|
const char *node_str;
|
|
uint8_t node_type;
|
|
|
|
if (!tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE])
|
|
return;
|
|
|
|
node_type = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_DEV_NODE_TYPE]);
|
|
node_str = node_type_to_str(node_type);
|
|
if (rd->json_output)
|
|
jsonw_string_field(rd->jw, "node_type", node_str);
|
|
else
|
|
pr_out("node_type %s ", node_str);
|
|
}
|
|
|
|
static int dev_parse_cb(const struct nlmsghdr *nlh, void *data)
|
|
{
|
|
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
|
|
struct rd *rd = data;
|
|
const char *name;
|
|
uint32_t idx;
|
|
|
|
mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
|
|
if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
|
|
return MNL_CB_ERROR;
|
|
|
|
idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
|
|
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
|
|
if (rd->json_output) {
|
|
jsonw_uint_field(rd->jw, "ifindex", idx);
|
|
jsonw_string_field(rd->jw, "ifname", name);
|
|
} else {
|
|
pr_out("%u: %s: ", idx, name);
|
|
}
|
|
|
|
dev_print_node_type(rd, tb);
|
|
dev_print_fw(rd, tb);
|
|
dev_print_node_guid(rd, tb);
|
|
dev_print_sys_image_guid(rd, tb);
|
|
if (rd->show_details)
|
|
dev_print_caps(rd, tb);
|
|
|
|
if (!rd->json_output)
|
|
pr_out("\n");
|
|
return MNL_CB_OK;
|
|
}
|
|
|
|
static int dev_no_args(struct rd *rd)
|
|
{
|
|
uint32_t seq;
|
|
int ret;
|
|
|
|
rd_prepare_msg(rd, RDMA_NLDEV_CMD_GET,
|
|
&seq, (NLM_F_REQUEST | NLM_F_ACK));
|
|
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
|
|
ret = rd_send_msg(rd);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (rd->json_output)
|
|
jsonw_start_object(rd->jw);
|
|
ret = rd_recv_msg(rd, dev_parse_cb, rd, seq);
|
|
if (rd->json_output)
|
|
jsonw_end_object(rd->jw);
|
|
return ret;
|
|
}
|
|
|
|
static int dev_one_show(struct rd *rd)
|
|
{
|
|
const struct rd_cmd cmds[] = {
|
|
{ NULL, dev_no_args},
|
|
{ 0 }
|
|
};
|
|
|
|
return rd_exec_cmd(rd, cmds, "parameter");
|
|
}
|
|
|
|
static int dev_show(struct rd *rd)
|
|
{
|
|
return rd_exec_dev(rd, dev_one_show);
|
|
}
|
|
|
|
int cmd_dev(struct rd *rd)
|
|
{
|
|
const struct rd_cmd cmds[] = {
|
|
{ NULL, dev_show },
|
|
{ "show", dev_show },
|
|
{ "list", dev_show },
|
|
{ "help", dev_help },
|
|
{ 0 }
|
|
};
|
|
|
|
return rd_exec_cmd(rd, cmds, "dev command");
|
|
}
|