Commit b40f4757 authored by Christoph Lameter's avatar Christoph Lameter Committed by Doug Ledford

IB/core: Make device counter infrastructure dynamic

In practice, each RDMA device has a unique set of counters that the
hardware implements.  Having a central set of counters that they must
all adhere to is limiting and causes many useful counters to not be
available.

Therefore we create a dynamic counter registration infrastructure.

The driver must implement a stats structure allocation routine, in
which the driver must place the directory name it wants, a list of
names for all of the counters, an array of u64 counters themselves,
plus a few generic configuration options.

We then implement a core routine to create a sysfs file for each
of the named stats elements, and a core routine to retrieve the
stats when any of the sysfs attribute files are read.

To avoid excessive beating on the stats generation routine in the
drivers, the core code also caches the stats for a short period of
time so that someone attempting to read all of the stats in a
given device's directory will not result in a stats generation
call per file read.

Future work will attempt to standardize just the shared stats
elements, and possibly add a method to get the stats via netlink
in addition to sysfs.
Signed-off-by: default avatarChristoph Lameter <cl@linux.com>
Signed-off-by: default avatarMark Bloch <markb@mellanox.com>
Reviewed-by: default avatarSteve Wise <swise@opengridcomputing.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
[ Add caching, make structure names more informative, add i40iw support,
  other significant rewrites from the original patch ]
parent 8779e765
...@@ -56,6 +56,18 @@ SYSFS FILES ...@@ -56,6 +56,18 @@ SYSFS FILES
ports/1/pkeys/10 contains the value at index 10 in port 1's P_Key ports/1/pkeys/10 contains the value at index 10 in port 1's P_Key
table. table.
There is an optional "hw_counters" subdirectory that may be under either
the parent device or the port subdirectories or both. If present,
there are a list of counters provided by the hardware. They may match
some of the counters in the counters directory, but they often include
many other counters. In addition to the various counters, there will
be a file named "lifespan" that configures how frequently the core
should update the counters when they are being accessed (counters are
not updated if they are not being accessed). The lifespan is in milli-
seconds and defaults to 10 unless set to something else by the driver.
Users may echo a value between 0 - 10000 to the lifespan file to set
the length of time between updates in milliseconds.
MTHCA MTHCA
The Mellanox HCA driver also creates the files: The Mellanox HCA driver also creates the files:
......
This diff is collapsed.
...@@ -1218,59 +1218,119 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr, ...@@ -1218,59 +1218,119 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr,
iwch_dev->rdev.rnic_info.pdev->device); iwch_dev->rdev.rnic_info.pdev->device);
} }
static int iwch_get_mib(struct ib_device *ibdev, enum counters {
union rdma_protocol_stats *stats) IPINRECEIVES,
IPINHDRERRORS,
IPINADDRERRORS,
IPINUNKNOWNPROTOS,
IPINDISCARDS,
IPINDELIVERS,
IPOUTREQUESTS,
IPOUTDISCARDS,
IPOUTNOROUTES,
IPREASMTIMEOUT,
IPREASMREQDS,
IPREASMOKS,
IPREASMFAILS,
TCPACTIVEOPENS,
TCPPASSIVEOPENS,
TCPATTEMPTFAILS,
TCPESTABRESETS,
TCPCURRESTAB,
TCPINSEGS,
TCPOUTSEGS,
TCPRETRANSSEGS,
TCPINERRS,
TCPOUTRSTS,
TCPRTOMIN,
TCPRTOMAX,
NR_COUNTERS
};
static const char * const names[] = {
[IPINRECEIVES] = "ipInReceives",
[IPINHDRERRORS] = "ipInHdrErrors",
[IPINADDRERRORS] = "ipInAddrErrors",
[IPINUNKNOWNPROTOS] = "ipInUnknownProtos",
[IPINDISCARDS] = "ipInDiscards",
[IPINDELIVERS] = "ipInDelivers",
[IPOUTREQUESTS] = "ipOutRequests",
[IPOUTDISCARDS] = "ipOutDiscards",
[IPOUTNOROUTES] = "ipOutNoRoutes",
[IPREASMTIMEOUT] = "ipReasmTimeout",
[IPREASMREQDS] = "ipReasmReqds",
[IPREASMOKS] = "ipReasmOKs",
[IPREASMFAILS] = "ipReasmFails",
[TCPACTIVEOPENS] = "tcpActiveOpens",
[TCPPASSIVEOPENS] = "tcpPassiveOpens",
[TCPATTEMPTFAILS] = "tcpAttemptFails",
[TCPESTABRESETS] = "tcpEstabResets",
[TCPCURRESTAB] = "tcpCurrEstab",
[TCPINSEGS] = "tcpInSegs",
[TCPOUTSEGS] = "tcpOutSegs",
[TCPRETRANSSEGS] = "tcpRetransSegs",
[TCPINERRS] = "tcpInErrs",
[TCPOUTRSTS] = "tcpOutRsts",
[TCPRTOMIN] = "tcpRtoMin",
[TCPRTOMAX] = "tcpRtoMax",
};
static struct rdma_hw_stats *iwch_alloc_stats(struct ib_device *ibdev,
u8 port_num)
{
BUILD_BUG_ON(ARRAY_SIZE(names) != NR_COUNTERS);
/* Our driver only supports device level stats */
if (port_num != 0)
return NULL;
return rdma_alloc_hw_stats_struct(names, NR_COUNTERS,
RDMA_HW_STATS_DEFAULT_LIFESPAN);
}
static int iwch_get_mib(struct ib_device *ibdev, struct rdma_hw_stats *stats,
u8 port, int index)
{ {
struct iwch_dev *dev; struct iwch_dev *dev;
struct tp_mib_stats m; struct tp_mib_stats m;
int ret; int ret;
if (port != 0 || !stats)
return -ENOSYS;
PDBG("%s ibdev %p\n", __func__, ibdev); PDBG("%s ibdev %p\n", __func__, ibdev);
dev = to_iwch_dev(ibdev); dev = to_iwch_dev(ibdev);
ret = dev->rdev.t3cdev_p->ctl(dev->rdev.t3cdev_p, RDMA_GET_MIB, &m); ret = dev->rdev.t3cdev_p->ctl(dev->rdev.t3cdev_p, RDMA_GET_MIB, &m);
if (ret) if (ret)
return -ENOSYS; return -ENOSYS;
memset(stats, 0, sizeof *stats); stats->value[IPINRECEIVES] = ((u64)m.ipInReceive_hi << 32) + m.ipInReceive_lo;
stats->iw.ipInReceives = ((u64) m.ipInReceive_hi << 32) + stats->value[IPINHDRERRORS] = ((u64)m.ipInHdrErrors_hi << 32) + m.ipInHdrErrors_lo;
m.ipInReceive_lo; stats->value[IPINADDRERRORS] = ((u64)m.ipInAddrErrors_hi << 32) + m.ipInAddrErrors_lo;
stats->iw.ipInHdrErrors = ((u64) m.ipInHdrErrors_hi << 32) + stats->value[IPINUNKNOWNPROTOS] = ((u64)m.ipInUnknownProtos_hi << 32) + m.ipInUnknownProtos_lo;
m.ipInHdrErrors_lo; stats->value[IPINDISCARDS] = ((u64)m.ipInDiscards_hi << 32) + m.ipInDiscards_lo;
stats->iw.ipInAddrErrors = ((u64) m.ipInAddrErrors_hi << 32) + stats->value[IPINDELIVERS] = ((u64)m.ipInDelivers_hi << 32) + m.ipInDelivers_lo;
m.ipInAddrErrors_lo; stats->value[IPOUTREQUESTS] = ((u64)m.ipOutRequests_hi << 32) + m.ipOutRequests_lo;
stats->iw.ipInUnknownProtos = ((u64) m.ipInUnknownProtos_hi << 32) + stats->value[IPOUTDISCARDS] = ((u64)m.ipOutDiscards_hi << 32) + m.ipOutDiscards_lo;
m.ipInUnknownProtos_lo; stats->value[IPOUTNOROUTES] = ((u64)m.ipOutNoRoutes_hi << 32) + m.ipOutNoRoutes_lo;
stats->iw.ipInDiscards = ((u64) m.ipInDiscards_hi << 32) + stats->value[IPREASMTIMEOUT] = m.ipReasmTimeout;
m.ipInDiscards_lo; stats->value[IPREASMREQDS] = m.ipReasmReqds;
stats->iw.ipInDelivers = ((u64) m.ipInDelivers_hi << 32) + stats->value[IPREASMOKS] = m.ipReasmOKs;
m.ipInDelivers_lo; stats->value[IPREASMFAILS] = m.ipReasmFails;
stats->iw.ipOutRequests = ((u64) m.ipOutRequests_hi << 32) + stats->value[TCPACTIVEOPENS] = m.tcpActiveOpens;
m.ipOutRequests_lo; stats->value[TCPPASSIVEOPENS] = m.tcpPassiveOpens;
stats->iw.ipOutDiscards = ((u64) m.ipOutDiscards_hi << 32) + stats->value[TCPATTEMPTFAILS] = m.tcpAttemptFails;
m.ipOutDiscards_lo; stats->value[TCPESTABRESETS] = m.tcpEstabResets;
stats->iw.ipOutNoRoutes = ((u64) m.ipOutNoRoutes_hi << 32) + stats->value[TCPCURRESTAB] = m.tcpOutRsts;
m.ipOutNoRoutes_lo; stats->value[TCPINSEGS] = m.tcpCurrEstab;
stats->iw.ipReasmTimeout = (u64) m.ipReasmTimeout; stats->value[TCPOUTSEGS] = ((u64)m.tcpInSegs_hi << 32) + m.tcpInSegs_lo;
stats->iw.ipReasmReqds = (u64) m.ipReasmReqds; stats->value[TCPRETRANSSEGS] = ((u64)m.tcpOutSegs_hi << 32) + m.tcpOutSegs_lo;
stats->iw.ipReasmOKs = (u64) m.ipReasmOKs; stats->value[TCPINERRS] = ((u64)m.tcpRetransSeg_hi << 32) + m.tcpRetransSeg_lo,
stats->iw.ipReasmFails = (u64) m.ipReasmFails; stats->value[TCPOUTRSTS] = ((u64)m.tcpInErrs_hi << 32) + m.tcpInErrs_lo;
stats->iw.tcpActiveOpens = (u64) m.tcpActiveOpens; stats->value[TCPRTOMIN] = m.tcpRtoMin;
stats->iw.tcpPassiveOpens = (u64) m.tcpPassiveOpens; stats->value[TCPRTOMAX] = m.tcpRtoMax;
stats->iw.tcpAttemptFails = (u64) m.tcpAttemptFails;
stats->iw.tcpEstabResets = (u64) m.tcpEstabResets; return stats->num_counters;
stats->iw.tcpOutRsts = (u64) m.tcpOutRsts;
stats->iw.tcpCurrEstab = (u64) m.tcpCurrEstab;
stats->iw.tcpInSegs = ((u64) m.tcpInSegs_hi << 32) +
m.tcpInSegs_lo;
stats->iw.tcpOutSegs = ((u64) m.tcpOutSegs_hi << 32) +
m.tcpOutSegs_lo;
stats->iw.tcpRetransSegs = ((u64) m.tcpRetransSeg_hi << 32) +
m.tcpRetransSeg_lo;
stats->iw.tcpInErrs = ((u64) m.tcpInErrs_hi << 32) +
m.tcpInErrs_lo;
stats->iw.tcpRtoMin = (u64) m.tcpRtoMin;
stats->iw.tcpRtoMax = (u64) m.tcpRtoMax;
return 0;
} }
static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
...@@ -1373,7 +1433,8 @@ int iwch_register_device(struct iwch_dev *dev) ...@@ -1373,7 +1433,8 @@ int iwch_register_device(struct iwch_dev *dev)
dev->ibdev.req_notify_cq = iwch_arm_cq; dev->ibdev.req_notify_cq = iwch_arm_cq;
dev->ibdev.post_send = iwch_post_send; dev->ibdev.post_send = iwch_post_send;
dev->ibdev.post_recv = iwch_post_receive; dev->ibdev.post_recv = iwch_post_receive;
dev->ibdev.get_protocol_stats = iwch_get_mib; dev->ibdev.alloc_hw_stats = iwch_alloc_stats;
dev->ibdev.get_hw_stats = iwch_get_mib;
dev->ibdev.uverbs_abi_ver = IWCH_UVERBS_ABI_VERSION; dev->ibdev.uverbs_abi_ver = IWCH_UVERBS_ABI_VERSION;
dev->ibdev.get_port_immutable = iwch_port_immutable; dev->ibdev.get_port_immutable = iwch_port_immutable;
......
...@@ -446,20 +446,59 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr, ...@@ -446,20 +446,59 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr,
c4iw_dev->rdev.lldi.pdev->device); c4iw_dev->rdev.lldi.pdev->device);
} }
enum counters {
IP4INSEGS,
IP4OUTSEGS,
IP4RETRANSSEGS,
IP4OUTRSTS,
IP6INSEGS,
IP6OUTSEGS,
IP6RETRANSSEGS,
IP6OUTRSTS,
NR_COUNTERS
};
static const char * const names[] = {
[IP4INSEGS] = "ip4InSegs",
[IP4OUTSEGS] = "ip4OutSegs",
[IP4RETRANSSEGS] = "ip4RetransSegs",
[IP4OUTRSTS] = "ip4OutRsts",
[IP6INSEGS] = "ip6InSegs",
[IP6OUTSEGS] = "ip6OutSegs",
[IP6RETRANSSEGS] = "ip6RetransSegs",
[IP6OUTRSTS] = "ip6OutRsts"
};
static struct rdma_hw_stats *c4iw_alloc_stats(struct ib_device *ibdev,
u8 port_num)
{
BUILD_BUG_ON(ARRAY_SIZE(names) != NR_COUNTERS);
if (port_num != 0)
return NULL;
return rdma_alloc_hw_stats_struct(names, NR_COUNTERS,
RDMA_HW_STATS_DEFAULT_LIFESPAN);
}
static int c4iw_get_mib(struct ib_device *ibdev, static int c4iw_get_mib(struct ib_device *ibdev,
union rdma_protocol_stats *stats) struct rdma_hw_stats *stats,
u8 port, int index)
{ {
struct tp_tcp_stats v4, v6; struct tp_tcp_stats v4, v6;
struct c4iw_dev *c4iw_dev = to_c4iw_dev(ibdev); struct c4iw_dev *c4iw_dev = to_c4iw_dev(ibdev);
cxgb4_get_tcp_stats(c4iw_dev->rdev.lldi.pdev, &v4, &v6); cxgb4_get_tcp_stats(c4iw_dev->rdev.lldi.pdev, &v4, &v6);
memset(stats, 0, sizeof *stats); stats->value[IP4INSEGS] = v4.tcp_in_segs;
stats->iw.tcpInSegs = v4.tcp_in_segs + v6.tcp_in_segs; stats->value[IP4OUTSEGS] = v4.tcp_out_segs;
stats->iw.tcpOutSegs = v4.tcp_out_segs + v6.tcp_out_segs; stats->value[IP4RETRANSSEGS] = v4.tcp_retrans_segs;
stats->iw.tcpRetransSegs = v4.tcp_retrans_segs + v6.tcp_retrans_segs; stats->value[IP4OUTRSTS] = v4.tcp_out_rsts;
stats->iw.tcpOutRsts = v4.tcp_out_rsts + v6.tcp_out_rsts; stats->value[IP6INSEGS] = v6.tcp_in_segs;
stats->value[IP6OUTSEGS] = v6.tcp_out_segs;
return 0; stats->value[IP6RETRANSSEGS] = v6.tcp_retrans_segs;
stats->value[IP6OUTRSTS] = v6.tcp_out_rsts;
return stats->num_counters;
} }
static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
...@@ -562,7 +601,8 @@ int c4iw_register_device(struct c4iw_dev *dev) ...@@ -562,7 +601,8 @@ int c4iw_register_device(struct c4iw_dev *dev)
dev->ibdev.req_notify_cq = c4iw_arm_cq; dev->ibdev.req_notify_cq = c4iw_arm_cq;
dev->ibdev.post_send = c4iw_post_send; dev->ibdev.post_send = c4iw_post_send;
dev->ibdev.post_recv = c4iw_post_receive; dev->ibdev.post_recv = c4iw_post_receive;
dev->ibdev.get_protocol_stats = c4iw_get_mib; dev->ibdev.alloc_hw_stats = c4iw_alloc_stats;
dev->ibdev.get_hw_stats = c4iw_get_mib;
dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION; dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION;
dev->ibdev.get_port_immutable = c4iw_port_immutable; dev->ibdev.get_port_immutable = c4iw_port_immutable;
dev->ibdev.drain_sq = c4iw_drain_sq; dev->ibdev.drain_sq = c4iw_drain_sq;
......
...@@ -2361,58 +2361,130 @@ static int i40iw_port_immutable(struct ib_device *ibdev, u8 port_num, ...@@ -2361,58 +2361,130 @@ static int i40iw_port_immutable(struct ib_device *ibdev, u8 port_num,
return 0; return 0;
} }
static const char * const i40iw_hw_stat_names[] = {
// 32bit names
[I40IW_HW_STAT_INDEX_IP4RXDISCARD] = "ip4InDiscards",
[I40IW_HW_STAT_INDEX_IP4RXTRUNC] = "ip4InTruncatedPkts",
[I40IW_HW_STAT_INDEX_IP4TXNOROUTE] = "ip4OutNoRoutes",
[I40IW_HW_STAT_INDEX_IP6RXDISCARD] = "ip6InDiscards",
[I40IW_HW_STAT_INDEX_IP6RXTRUNC] = "ip6InTruncatedPkts",
[I40IW_HW_STAT_INDEX_IP6TXNOROUTE] = "ip6OutNoRoutes",
[I40IW_HW_STAT_INDEX_TCPRTXSEG] = "tcpRetransSegs",
[I40IW_HW_STAT_INDEX_TCPRXOPTERR] = "tcpInOptErrors",
[I40IW_HW_STAT_INDEX_TCPRXPROTOERR] = "tcpInProtoErrors",
// 64bit names
[I40IW_HW_STAT_INDEX_IP4RXOCTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip4InOctets",
[I40IW_HW_STAT_INDEX_IP4RXPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip4InPkts",
[I40IW_HW_STAT_INDEX_IP4RXFRAGS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip4InReasmRqd",
[I40IW_HW_STAT_INDEX_IP4RXMCPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip4InMcastPkts",
[I40IW_HW_STAT_INDEX_IP4TXOCTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip4OutOctets",
[I40IW_HW_STAT_INDEX_IP4TXPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip4OutPkts",
[I40IW_HW_STAT_INDEX_IP4TXFRAGS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip4OutSegRqd",
[I40IW_HW_STAT_INDEX_IP4TXMCPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip4OutMcastPkts",
[I40IW_HW_STAT_INDEX_IP6RXOCTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip6InOctets",
[I40IW_HW_STAT_INDEX_IP6RXPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip6InPkts",
[I40IW_HW_STAT_INDEX_IP6RXFRAGS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip6InReasmRqd",
[I40IW_HW_STAT_INDEX_IP6RXMCPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip6InMcastPkts",
[I40IW_HW_STAT_INDEX_IP6TXOCTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip6OutOctets",
[I40IW_HW_STAT_INDEX_IP6TXPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip6OutPkts",
[I40IW_HW_STAT_INDEX_IP6TXFRAGS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip6OutSegRqd",
[I40IW_HW_STAT_INDEX_IP6TXMCPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
"ip6OutMcastPkts",
[I40IW_HW_STAT_INDEX_TCPRXSEGS + I40IW_HW_STAT_INDEX_MAX_32] =
"tcpInSegs",
[I40IW_HW_STAT_INDEX_TCPTXSEG + I40IW_HW_STAT_INDEX_MAX_32] =
"tcpOutSegs",
[I40IW_HW_STAT_INDEX_RDMARXRDS + I40IW_HW_STAT_INDEX_MAX_32] =
"iwInRdmaReads",
[I40IW_HW_STAT_INDEX_RDMARXSNDS + I40IW_HW_STAT_INDEX_MAX_32] =
"iwInRdmaSends",
[I40IW_HW_STAT_INDEX_RDMARXWRS + I40IW_HW_STAT_INDEX_MAX_32] =
"iwInRdmaWrites",
[I40IW_HW_STAT_INDEX_RDMATXRDS + I40IW_HW_STAT_INDEX_MAX_32] =
"iwOutRdmaReads",
[I40IW_HW_STAT_INDEX_RDMATXSNDS + I40IW_HW_STAT_INDEX_MAX_32] =
"iwOutRdmaSends",
[I40IW_HW_STAT_INDEX_RDMATXWRS + I40IW_HW_STAT_INDEX_MAX_32] =
"iwOutRdmaWrites",
[I40IW_HW_STAT_INDEX_RDMAVBND + I40IW_HW_STAT_INDEX_MAX_32] =
"iwRdmaBnd",
[I40IW_HW_STAT_INDEX_RDMAVINV + I40IW_HW_STAT_INDEX_MAX_32] =
"iwRdmaInv"
};
/** /**
* i40iw_get_protocol_stats - Populates the rdma_stats structure * i40iw_alloc_hw_stats - Allocate a hw stats structure
* @ibdev: ib dev struct * @ibdev: device pointer from stack
* @stats: iw protocol stats struct * @port_num: port number
*/ */
static int i40iw_get_protocol_stats(struct ib_device *ibdev, static struct rdma_hw_stats *i40iw_alloc_hw_stats(struct ib_device *ibdev,
union rdma_protocol_stats *stats) u8 port_num)
{
struct i40iw_device *iwdev = to_iwdev(ibdev);
struct i40iw_sc_dev *dev = &iwdev->sc_dev;
int num_counters = I40IW_HW_STAT_INDEX_MAX_32 +
I40IW_HW_STAT_INDEX_MAX_64;
unsigned long lifespan = RDMA_HW_STATS_DEFAULT_LIFESPAN;
BUILD_BUG_ON(ARRAY_SIZE(i40iw_hw_stat_names) !=
(I40IW_HW_STAT_INDEX_MAX_32 +
I40IW_HW_STAT_INDEX_MAX_64));
/*
* PFs get the default update lifespan, but VFs only update once
* per second
*/
if (!dev->is_pf)
lifespan = 1000;
return rdma_alloc_hw_stats_struct(i40iw_hw_stat_names, num_counters,
lifespan);
}
/**
* i40iw_get_hw_stats - Populates the rdma_hw_stats structure
* @ibdev: device pointer from stack
* @stats: stats pointer from stack
* @port_num: port number
* @index: which hw counter the stack is requesting we update
*/
static int i40iw_get_hw_stats(struct ib_device *ibdev,
struct rdma_hw_stats *stats,
u8 port_num, int index)
{ {
struct i40iw_device *iwdev = to_iwdev(ibdev); struct i40iw_device *iwdev = to_iwdev(ibdev);
struct i40iw_sc_dev *dev = &iwdev->sc_dev; struct i40iw_sc_dev *dev = &iwdev->sc_dev;
struct i40iw_dev_pestat *devstat = &dev->dev_pestat; struct i40iw_dev_pestat *devstat = &dev->dev_pestat;
struct i40iw_dev_hw_stats *hw_stats = &devstat->hw_stats; struct i40iw_dev_hw_stats *hw_stats = &devstat->hw_stats;
struct timespec curr_time;
static struct timespec last_rd_time = {0, 0};
unsigned long flags; unsigned long flags;
curr_time = current_kernel_time();
memset(stats, 0, sizeof(*stats));
if (dev->is_pf) { if (dev->is_pf) {
spin_lock_irqsave(&devstat->stats_lock, flags); spin_lock_irqsave(&devstat->stats_lock, flags);
devstat->ops.iw_hw_stat_read_all(devstat, devstat->ops.iw_hw_stat_read_all(devstat,
&devstat->hw_stats); &devstat->hw_stats);
spin_unlock_irqrestore(&devstat->stats_lock, flags); spin_unlock_irqrestore(&devstat->stats_lock, flags);
} else { } else {
if (((u64)curr_time.tv_sec - (u64)last_rd_time.tv_sec) > 1) if (i40iw_vchnl_vf_get_pe_stats(dev, &devstat->hw_stats))
if (i40iw_vchnl_vf_get_pe_stats(dev, &devstat->hw_stats)) return -ENOSYS;
return -ENOSYS;
} }
stats->iw.ipInReceives = hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_IP4RXPKTS] + memcpy(&stats->value[0], &hw_stats, sizeof(*hw_stats));
hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_IP6RXPKTS];
stats->iw.ipInTruncatedPkts = hw_stats->stat_value_32[I40IW_HW_STAT_INDEX_IP4RXTRUNC] + return stats->num_counters;
hw_stats->stat_value_32[I40IW_HW_STAT_INDEX_IP6RXTRUNC];
stats->iw.ipInDiscards = hw_stats->stat_value_32[I40IW_HW_STAT_INDEX_IP4RXDISCARD] +
hw_stats->stat_value_32[I40IW_HW_STAT_INDEX_IP6RXDISCARD];
stats->iw.ipOutNoRoutes = hw_stats->stat_value_32[I40IW_HW_STAT_INDEX_IP4TXNOROUTE] +
hw_stats->stat_value_32[I40IW_HW_STAT_INDEX_IP6TXNOROUTE];
stats->iw.ipReasmReqds = hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_IP4RXFRAGS] +
hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_IP6RXFRAGS];
stats->iw.ipFragCreates = hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_IP4TXFRAGS] +
hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_IP6TXFRAGS];
stats->iw.ipInMcastPkts = hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_IP4RXMCPKTS] +
hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_IP6RXMCPKTS];
stats->iw.ipOutMcastPkts = hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_IP4TXMCPKTS] +
hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_IP6TXMCPKTS];
stats->iw.tcpOutSegs = hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_TCPTXSEG];
stats->iw.tcpInSegs = hw_stats->stat_value_64[I40IW_HW_STAT_INDEX_TCPRXSEGS];
stats->iw.tcpRetransSegs = hw_stats->stat_value_32[I40IW_HW_STAT_INDEX_TCPRTXSEG];
last_rd_time = curr_time;
return 0;
} }
/** /**
...@@ -2551,7 +2623,8 @@ static struct i40iw_ib_device *i40iw_init_rdma_device(struct i40iw_device *iwdev ...@@ -2551,7 +2623,8 @@ static struct i40iw_ib_device *i40iw_init_rdma_device(struct i40iw_device *iwdev
iwibdev->ibdev.get_dma_mr = i40iw_get_dma_mr; iwibdev->ibdev.get_dma_mr = i40iw_get_dma_mr;
iwibdev->ibdev.reg_user_mr = i40iw_reg_user_mr; iwibdev->ibdev.reg_user_mr = i40iw_reg_user_mr;
iwibdev->ibdev.dereg_mr = i40iw_dereg_mr; iwibdev->ibdev.dereg_mr = i40iw_dereg_mr;
iwibdev->ibdev.get_protocol_stats = i40iw_get_protocol_stats; iwibdev->ibdev.alloc_hw_stats = i40iw_alloc_hw_stats;
iwibdev->ibdev.get_hw_stats = i40iw_get_hw_stats;
iwibdev->ibdev.query_device = i40iw_query_device; iwibdev->ibdev.query_device = i40iw_query_device;
iwibdev->ibdev.create_ah = i40iw_create_ah; iwibdev->ibdev.create_ah = i40iw_create_ah;
iwibdev->ibdev.destroy_ah = i40iw_destroy_ah; iwibdev->ibdev.destroy_ah = i40iw_destroy_ah;
......
...@@ -403,56 +403,55 @@ enum ib_port_speed { ...@@ -403,56 +403,55 @@ enum ib_port_speed {
IB_SPEED_EDR = 32 IB_SPEED_EDR = 32
}; };
struct ib_protocol_stats { /**
/* TBD... */ * struct rdma_hw_stats
}; * @timestamp - Used by the core code to track when the last update was
* @lifespan - Used by the core code to determine how old the counters
struct iw_protocol_stats { * should be before being updated again. Stored in jiffies, defaults
u64 ipInReceives; * to 10 milliseconds, drivers can override the default be specifying
u64 ipInHdrErrors; * their own value during their allocation routine.
u64 ipInTooBigErrors; * @name - Array of pointers to static names used for the counters in
u64 ipInNoRoutes; * directory.
u64 ipInAddrErrors; * @num_counters - How many hardware counters there are. If name is
u64 ipInUnknownProtos; * shorter than this number, a kernel oops will result. Driver authors
u64 ipInTruncatedPkts; * are encouraged to leave BUILD_BUG_ON(ARRAY_SIZE(@name) < num_counters)
u64 ipInDiscards; * in their code to prevent this.
u64 ipInDelivers; * @value - Array of u64 counters that are accessed by the sysfs code and
u64 ipOutForwDatagrams; * filled in by the drivers get_stats routine
u64 ipOutRequests; */
u64 ipOutDiscards; struct rdma_hw_stats {
u64 ipOutNoRoutes; unsigned long timestamp;
u64 ipReasmTimeout; unsigned long lifespan;
u64 ipReasmReqds; const char * const *names;
u64 ipReasmOKs; int num_counters;
u64 ipReasmFails; u64 value[];
u64 ipFragOKs; };
u64 ipFragFails;
u64 ipFragCreates; #define RDMA_HW_STATS_DEFAULT_LIFESPAN 10
u64 ipInMcastPkts; /**
u64 ipOutMcastPkts; * rdma_alloc_hw_stats_struct - Helper function to allocate dynamic struct
u64 ipInBcastPkts; * for drivers.
u64 ipOutBcastPkts; * @names - Array of static const char *
* @num_counters - How many elements in array
u64 tcpRtoAlgorithm; * @lifespan - How many milliseconds between updates
u64 tcpRtoMin; */
u64 tcpRtoMax; static inline struct rdma_hw_stats *rdma_alloc_hw_stats_struct(
u64 tcpMaxConn; const char * const *names, int num_counters,
u64 tcpActiveOpens; unsigned long lifespan)
u64 tcpPassiveOpens; {
u64 tcpAttemptFails; struct rdma_hw_stats *stats;
u64 tcpEstabResets;
u64 tcpCurrEstab; stats = kzalloc(sizeof(*stats) + num_counters * sizeof(u64),
u64 tcpInSegs; GFP_KERNEL);
u64 tcpOutSegs; if (!stats)
u64 tcpRetransSegs; return NULL;
u64 tcpInErrs; stats->names = names;
u64 tcpOutRsts; stats->num_counters = num_counters;
}; stats->lifespan = msecs_to_jiffies(lifespan);
union rdma_protocol_stats { return stats;
struct ib_protocol_stats ib; }
struct iw_protocol_stats iw;
};
/* Define bits for the various functionality this port needs to be supported by /* Define bits for the various functionality this port needs to be supported by
* the core. * the core.
...@@ -1707,8 +1706,29 @@ struct ib_device { ...@@ -1707,8 +1706,29 @@ struct ib_device {
struct iw_cm_verbs *iwcm; struct iw_cm_verbs *iwcm;
int (*get_protocol_stats)(struct ib_device *device, /**
union rdma_protocol_stats *stats); * alloc_hw_stats - Allocate a struct rdma_hw_stats and fill in the
* driver initialized data. The struct is kfree()'ed by the sysfs
* core when the device is removed. A lifespan of -1 in the return
* struct tells the core to set a default lifespan.
*/
struct rdma_hw_stats *(*alloc_hw_stats)(struct ib_device *device,
u8 port_num);
/**
* get_hw_stats - Fill in the counter value(s) in the stats struct.
* @index - The index in the value array we wish to have updated, or
* num_counters if we want all stats updated
* Return codes -
* < 0 - Error, no counters updated
* index - Updated the single counter pointed to by index
* num_counters - Updated all counters (will reset the timestamp
* and prevent further calls for lifespan milliseconds)
* Drivers are allowed to update all counters in leiu of just the
* one given in index at their option
*/
int (*get_hw_stats)(struct ib_device *device,
struct rdma_hw_stats *stats,
u8 port, int index);
int (*query_device)(struct ib_device *device, int (*query_device)(struct ib_device *device,
struct ib_device_attr *device_attr, struct ib_device_attr *device_attr,
struct ib_udata *udata); struct ib_udata *udata);
...@@ -1926,6 +1946,8 @@ struct ib_device { ...@@ -1926,6 +1946,8 @@ struct ib_device {
u8 node_type; u8 node_type;
u8 phys_port_cnt; u8 phys_port_cnt;
struct ib_device_attr attrs; struct ib_device_attr attrs;
struct attribute_group *hw_stats_ag;
struct rdma_hw_stats *hw_stats;
/** /**
* The following mandatory functions are used only at device * The following mandatory functions are used only at device
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment