xref: /linux/drivers/infiniband/hw/ionic/ionic_hw_stats.c (revision ea4c399642b85dc30f44d90ee805c6a18fa03062)
1*ea4c3996SAbhijit Gangurde // SPDX-License-Identifier: GPL-2.0
2*ea4c3996SAbhijit Gangurde /* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
3*ea4c3996SAbhijit Gangurde 
4*ea4c3996SAbhijit Gangurde #include <linux/dma-mapping.h>
5*ea4c3996SAbhijit Gangurde 
6*ea4c3996SAbhijit Gangurde #include "ionic_fw.h"
7*ea4c3996SAbhijit Gangurde #include "ionic_ibdev.h"
8*ea4c3996SAbhijit Gangurde 
9*ea4c3996SAbhijit Gangurde static int ionic_v1_stat_normalize(struct ionic_v1_stat *hw_stats,
10*ea4c3996SAbhijit Gangurde 				   int hw_stats_count)
11*ea4c3996SAbhijit Gangurde {
12*ea4c3996SAbhijit Gangurde 	int hw_stat_i;
13*ea4c3996SAbhijit Gangurde 
14*ea4c3996SAbhijit Gangurde 	for (hw_stat_i = 0; hw_stat_i < hw_stats_count; ++hw_stat_i) {
15*ea4c3996SAbhijit Gangurde 		struct ionic_v1_stat *stat = &hw_stats[hw_stat_i];
16*ea4c3996SAbhijit Gangurde 
17*ea4c3996SAbhijit Gangurde 		stat->type_off = be32_to_cpu(stat->be_type_off);
18*ea4c3996SAbhijit Gangurde 		stat->name[sizeof(stat->name) - 1] = 0;
19*ea4c3996SAbhijit Gangurde 		if (ionic_v1_stat_type(stat) == IONIC_V1_STAT_TYPE_NONE)
20*ea4c3996SAbhijit Gangurde 			break;
21*ea4c3996SAbhijit Gangurde 	}
22*ea4c3996SAbhijit Gangurde 
23*ea4c3996SAbhijit Gangurde 	return hw_stat_i;
24*ea4c3996SAbhijit Gangurde }
25*ea4c3996SAbhijit Gangurde 
26*ea4c3996SAbhijit Gangurde static void ionic_fill_stats_desc(struct rdma_stat_desc *hw_stats_hdrs,
27*ea4c3996SAbhijit Gangurde 				  struct ionic_v1_stat *hw_stats,
28*ea4c3996SAbhijit Gangurde 				  int hw_stats_count)
29*ea4c3996SAbhijit Gangurde {
30*ea4c3996SAbhijit Gangurde 	int hw_stat_i;
31*ea4c3996SAbhijit Gangurde 
32*ea4c3996SAbhijit Gangurde 	for (hw_stat_i = 0; hw_stat_i < hw_stats_count; ++hw_stat_i) {
33*ea4c3996SAbhijit Gangurde 		struct ionic_v1_stat *stat = &hw_stats[hw_stat_i];
34*ea4c3996SAbhijit Gangurde 
35*ea4c3996SAbhijit Gangurde 		hw_stats_hdrs[hw_stat_i].name = stat->name;
36*ea4c3996SAbhijit Gangurde 	}
37*ea4c3996SAbhijit Gangurde }
38*ea4c3996SAbhijit Gangurde 
39*ea4c3996SAbhijit Gangurde static u64 ionic_v1_stat_val(struct ionic_v1_stat *stat,
40*ea4c3996SAbhijit Gangurde 			     void *vals_buf, size_t vals_len)
41*ea4c3996SAbhijit Gangurde {
42*ea4c3996SAbhijit Gangurde 	unsigned int off = ionic_v1_stat_off(stat);
43*ea4c3996SAbhijit Gangurde 	int type = ionic_v1_stat_type(stat);
44*ea4c3996SAbhijit Gangurde 
45*ea4c3996SAbhijit Gangurde #define __ionic_v1_stat_validate(__type)		\
46*ea4c3996SAbhijit Gangurde 	((off + sizeof(__type) <= vals_len) &&		\
47*ea4c3996SAbhijit Gangurde 	 (IS_ALIGNED(off, sizeof(__type))))
48*ea4c3996SAbhijit Gangurde 
49*ea4c3996SAbhijit Gangurde 	switch (type) {
50*ea4c3996SAbhijit Gangurde 	case IONIC_V1_STAT_TYPE_8:
51*ea4c3996SAbhijit Gangurde 		if (__ionic_v1_stat_validate(u8))
52*ea4c3996SAbhijit Gangurde 			return *(u8 *)(vals_buf + off);
53*ea4c3996SAbhijit Gangurde 		break;
54*ea4c3996SAbhijit Gangurde 	case IONIC_V1_STAT_TYPE_LE16:
55*ea4c3996SAbhijit Gangurde 		if (__ionic_v1_stat_validate(__le16))
56*ea4c3996SAbhijit Gangurde 			return le16_to_cpu(*(__le16 *)(vals_buf + off));
57*ea4c3996SAbhijit Gangurde 		break;
58*ea4c3996SAbhijit Gangurde 	case IONIC_V1_STAT_TYPE_LE32:
59*ea4c3996SAbhijit Gangurde 		if (__ionic_v1_stat_validate(__le32))
60*ea4c3996SAbhijit Gangurde 			return le32_to_cpu(*(__le32 *)(vals_buf + off));
61*ea4c3996SAbhijit Gangurde 		break;
62*ea4c3996SAbhijit Gangurde 	case IONIC_V1_STAT_TYPE_LE64:
63*ea4c3996SAbhijit Gangurde 		if (__ionic_v1_stat_validate(__le64))
64*ea4c3996SAbhijit Gangurde 			return le64_to_cpu(*(__le64 *)(vals_buf + off));
65*ea4c3996SAbhijit Gangurde 		break;
66*ea4c3996SAbhijit Gangurde 	case IONIC_V1_STAT_TYPE_BE16:
67*ea4c3996SAbhijit Gangurde 		if (__ionic_v1_stat_validate(__be16))
68*ea4c3996SAbhijit Gangurde 			return be16_to_cpu(*(__be16 *)(vals_buf + off));
69*ea4c3996SAbhijit Gangurde 		break;
70*ea4c3996SAbhijit Gangurde 	case IONIC_V1_STAT_TYPE_BE32:
71*ea4c3996SAbhijit Gangurde 		if (__ionic_v1_stat_validate(__be32))
72*ea4c3996SAbhijit Gangurde 			return be32_to_cpu(*(__be32 *)(vals_buf + off));
73*ea4c3996SAbhijit Gangurde 		break;
74*ea4c3996SAbhijit Gangurde 	case IONIC_V1_STAT_TYPE_BE64:
75*ea4c3996SAbhijit Gangurde 		if (__ionic_v1_stat_validate(__be64))
76*ea4c3996SAbhijit Gangurde 			return be64_to_cpu(*(__be64 *)(vals_buf + off));
77*ea4c3996SAbhijit Gangurde 		break;
78*ea4c3996SAbhijit Gangurde 	}
79*ea4c3996SAbhijit Gangurde 
80*ea4c3996SAbhijit Gangurde 	return ~0ull;
81*ea4c3996SAbhijit Gangurde #undef __ionic_v1_stat_validate
82*ea4c3996SAbhijit Gangurde }
83*ea4c3996SAbhijit Gangurde 
84*ea4c3996SAbhijit Gangurde static int ionic_hw_stats_cmd(struct ionic_ibdev *dev,
85*ea4c3996SAbhijit Gangurde 			      dma_addr_t dma, size_t len, int qid, int op)
86*ea4c3996SAbhijit Gangurde {
87*ea4c3996SAbhijit Gangurde 	struct ionic_admin_wr wr = {
88*ea4c3996SAbhijit Gangurde 		.work = COMPLETION_INITIALIZER_ONSTACK(wr.work),
89*ea4c3996SAbhijit Gangurde 		.wqe = {
90*ea4c3996SAbhijit Gangurde 			.op = op,
91*ea4c3996SAbhijit Gangurde 			.len = cpu_to_le16(IONIC_ADMIN_STATS_HDRS_IN_V1_LEN),
92*ea4c3996SAbhijit Gangurde 			.cmd.stats = {
93*ea4c3996SAbhijit Gangurde 				.dma_addr = cpu_to_le64(dma),
94*ea4c3996SAbhijit Gangurde 				.length = cpu_to_le32(len),
95*ea4c3996SAbhijit Gangurde 				.id_ver = cpu_to_le32(qid),
96*ea4c3996SAbhijit Gangurde 			},
97*ea4c3996SAbhijit Gangurde 		}
98*ea4c3996SAbhijit Gangurde 	};
99*ea4c3996SAbhijit Gangurde 
100*ea4c3996SAbhijit Gangurde 	if (dev->lif_cfg.admin_opcodes <= op)
101*ea4c3996SAbhijit Gangurde 		return -EBADRQC;
102*ea4c3996SAbhijit Gangurde 
103*ea4c3996SAbhijit Gangurde 	ionic_admin_post(dev, &wr);
104*ea4c3996SAbhijit Gangurde 
105*ea4c3996SAbhijit Gangurde 	return ionic_admin_wait(dev, &wr, IONIC_ADMIN_F_INTERRUPT);
106*ea4c3996SAbhijit Gangurde }
107*ea4c3996SAbhijit Gangurde 
108*ea4c3996SAbhijit Gangurde static int ionic_init_hw_stats(struct ionic_ibdev *dev)
109*ea4c3996SAbhijit Gangurde {
110*ea4c3996SAbhijit Gangurde 	dma_addr_t hw_stats_dma;
111*ea4c3996SAbhijit Gangurde 	int rc, hw_stats_count;
112*ea4c3996SAbhijit Gangurde 
113*ea4c3996SAbhijit Gangurde 	if (dev->hw_stats_hdrs)
114*ea4c3996SAbhijit Gangurde 		return 0;
115*ea4c3996SAbhijit Gangurde 
116*ea4c3996SAbhijit Gangurde 	dev->hw_stats_count = 0;
117*ea4c3996SAbhijit Gangurde 
118*ea4c3996SAbhijit Gangurde 	/* buffer for current values from the device */
119*ea4c3996SAbhijit Gangurde 	dev->hw_stats_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
120*ea4c3996SAbhijit Gangurde 	if (!dev->hw_stats_buf) {
121*ea4c3996SAbhijit Gangurde 		rc = -ENOMEM;
122*ea4c3996SAbhijit Gangurde 		goto err_buf;
123*ea4c3996SAbhijit Gangurde 	}
124*ea4c3996SAbhijit Gangurde 
125*ea4c3996SAbhijit Gangurde 	/* buffer for names, sizes, offsets of values */
126*ea4c3996SAbhijit Gangurde 	dev->hw_stats = kzalloc(PAGE_SIZE, GFP_KERNEL);
127*ea4c3996SAbhijit Gangurde 	if (!dev->hw_stats) {
128*ea4c3996SAbhijit Gangurde 		rc = -ENOMEM;
129*ea4c3996SAbhijit Gangurde 		goto err_hw_stats;
130*ea4c3996SAbhijit Gangurde 	}
131*ea4c3996SAbhijit Gangurde 
132*ea4c3996SAbhijit Gangurde 	/* request the names, sizes, offsets */
133*ea4c3996SAbhijit Gangurde 	hw_stats_dma = dma_map_single(dev->lif_cfg.hwdev, dev->hw_stats,
134*ea4c3996SAbhijit Gangurde 				      PAGE_SIZE, DMA_FROM_DEVICE);
135*ea4c3996SAbhijit Gangurde 	rc = dma_mapping_error(dev->lif_cfg.hwdev, hw_stats_dma);
136*ea4c3996SAbhijit Gangurde 	if (rc)
137*ea4c3996SAbhijit Gangurde 		goto err_dma;
138*ea4c3996SAbhijit Gangurde 
139*ea4c3996SAbhijit Gangurde 	rc = ionic_hw_stats_cmd(dev, hw_stats_dma, PAGE_SIZE, 0,
140*ea4c3996SAbhijit Gangurde 				IONIC_V1_ADMIN_STATS_HDRS);
141*ea4c3996SAbhijit Gangurde 	if (rc)
142*ea4c3996SAbhijit Gangurde 		goto err_cmd;
143*ea4c3996SAbhijit Gangurde 
144*ea4c3996SAbhijit Gangurde 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma, PAGE_SIZE, DMA_FROM_DEVICE);
145*ea4c3996SAbhijit Gangurde 
146*ea4c3996SAbhijit Gangurde 	/* normalize and count the number of hw_stats */
147*ea4c3996SAbhijit Gangurde 	hw_stats_count =
148*ea4c3996SAbhijit Gangurde 		ionic_v1_stat_normalize(dev->hw_stats,
149*ea4c3996SAbhijit Gangurde 					PAGE_SIZE / sizeof(*dev->hw_stats));
150*ea4c3996SAbhijit Gangurde 	if (!hw_stats_count) {
151*ea4c3996SAbhijit Gangurde 		rc = -ENODATA;
152*ea4c3996SAbhijit Gangurde 		goto err_dma;
153*ea4c3996SAbhijit Gangurde 	}
154*ea4c3996SAbhijit Gangurde 
155*ea4c3996SAbhijit Gangurde 	dev->hw_stats_count = hw_stats_count;
156*ea4c3996SAbhijit Gangurde 
157*ea4c3996SAbhijit Gangurde 	/* alloc and init array of names, for alloc_hw_stats */
158*ea4c3996SAbhijit Gangurde 	dev->hw_stats_hdrs = kcalloc(hw_stats_count,
159*ea4c3996SAbhijit Gangurde 				     sizeof(*dev->hw_stats_hdrs),
160*ea4c3996SAbhijit Gangurde 				     GFP_KERNEL);
161*ea4c3996SAbhijit Gangurde 	if (!dev->hw_stats_hdrs) {
162*ea4c3996SAbhijit Gangurde 		rc = -ENOMEM;
163*ea4c3996SAbhijit Gangurde 		goto err_dma;
164*ea4c3996SAbhijit Gangurde 	}
165*ea4c3996SAbhijit Gangurde 
166*ea4c3996SAbhijit Gangurde 	ionic_fill_stats_desc(dev->hw_stats_hdrs, dev->hw_stats,
167*ea4c3996SAbhijit Gangurde 			      hw_stats_count);
168*ea4c3996SAbhijit Gangurde 
169*ea4c3996SAbhijit Gangurde 	return 0;
170*ea4c3996SAbhijit Gangurde 
171*ea4c3996SAbhijit Gangurde err_cmd:
172*ea4c3996SAbhijit Gangurde 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma, PAGE_SIZE, DMA_FROM_DEVICE);
173*ea4c3996SAbhijit Gangurde err_dma:
174*ea4c3996SAbhijit Gangurde 	kfree(dev->hw_stats);
175*ea4c3996SAbhijit Gangurde err_hw_stats:
176*ea4c3996SAbhijit Gangurde 	kfree(dev->hw_stats_buf);
177*ea4c3996SAbhijit Gangurde err_buf:
178*ea4c3996SAbhijit Gangurde 	dev->hw_stats_count = 0;
179*ea4c3996SAbhijit Gangurde 	dev->hw_stats = NULL;
180*ea4c3996SAbhijit Gangurde 	dev->hw_stats_buf = NULL;
181*ea4c3996SAbhijit Gangurde 	dev->hw_stats_hdrs = NULL;
182*ea4c3996SAbhijit Gangurde 	return rc;
183*ea4c3996SAbhijit Gangurde }
184*ea4c3996SAbhijit Gangurde 
185*ea4c3996SAbhijit Gangurde static struct rdma_hw_stats *ionic_alloc_hw_stats(struct ib_device *ibdev,
186*ea4c3996SAbhijit Gangurde 						  u32 port)
187*ea4c3996SAbhijit Gangurde {
188*ea4c3996SAbhijit Gangurde 	struct ionic_ibdev *dev = to_ionic_ibdev(ibdev);
189*ea4c3996SAbhijit Gangurde 
190*ea4c3996SAbhijit Gangurde 	if (port != 1)
191*ea4c3996SAbhijit Gangurde 		return NULL;
192*ea4c3996SAbhijit Gangurde 
193*ea4c3996SAbhijit Gangurde 	return rdma_alloc_hw_stats_struct(dev->hw_stats_hdrs,
194*ea4c3996SAbhijit Gangurde 					  dev->hw_stats_count,
195*ea4c3996SAbhijit Gangurde 					  RDMA_HW_STATS_DEFAULT_LIFESPAN);
196*ea4c3996SAbhijit Gangurde }
197*ea4c3996SAbhijit Gangurde 
198*ea4c3996SAbhijit Gangurde static int ionic_get_hw_stats(struct ib_device *ibdev,
199*ea4c3996SAbhijit Gangurde 			      struct rdma_hw_stats *hw_stats,
200*ea4c3996SAbhijit Gangurde 			      u32 port, int index)
201*ea4c3996SAbhijit Gangurde {
202*ea4c3996SAbhijit Gangurde 	struct ionic_ibdev *dev = to_ionic_ibdev(ibdev);
203*ea4c3996SAbhijit Gangurde 	dma_addr_t hw_stats_dma;
204*ea4c3996SAbhijit Gangurde 	int rc, hw_stat_i;
205*ea4c3996SAbhijit Gangurde 
206*ea4c3996SAbhijit Gangurde 	if (port != 1)
207*ea4c3996SAbhijit Gangurde 		return -EINVAL;
208*ea4c3996SAbhijit Gangurde 
209*ea4c3996SAbhijit Gangurde 	hw_stats_dma = dma_map_single(dev->lif_cfg.hwdev, dev->hw_stats_buf,
210*ea4c3996SAbhijit Gangurde 				      PAGE_SIZE, DMA_FROM_DEVICE);
211*ea4c3996SAbhijit Gangurde 	rc = dma_mapping_error(dev->lif_cfg.hwdev, hw_stats_dma);
212*ea4c3996SAbhijit Gangurde 	if (rc)
213*ea4c3996SAbhijit Gangurde 		goto err_dma;
214*ea4c3996SAbhijit Gangurde 
215*ea4c3996SAbhijit Gangurde 	rc = ionic_hw_stats_cmd(dev, hw_stats_dma, PAGE_SIZE,
216*ea4c3996SAbhijit Gangurde 				0, IONIC_V1_ADMIN_STATS_VALS);
217*ea4c3996SAbhijit Gangurde 	if (rc)
218*ea4c3996SAbhijit Gangurde 		goto err_cmd;
219*ea4c3996SAbhijit Gangurde 
220*ea4c3996SAbhijit Gangurde 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma,
221*ea4c3996SAbhijit Gangurde 			 PAGE_SIZE, DMA_FROM_DEVICE);
222*ea4c3996SAbhijit Gangurde 
223*ea4c3996SAbhijit Gangurde 	for (hw_stat_i = 0; hw_stat_i < dev->hw_stats_count; ++hw_stat_i)
224*ea4c3996SAbhijit Gangurde 		hw_stats->value[hw_stat_i] =
225*ea4c3996SAbhijit Gangurde 			ionic_v1_stat_val(&dev->hw_stats[hw_stat_i],
226*ea4c3996SAbhijit Gangurde 					  dev->hw_stats_buf, PAGE_SIZE);
227*ea4c3996SAbhijit Gangurde 
228*ea4c3996SAbhijit Gangurde 	return hw_stat_i;
229*ea4c3996SAbhijit Gangurde 
230*ea4c3996SAbhijit Gangurde err_cmd:
231*ea4c3996SAbhijit Gangurde 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma,
232*ea4c3996SAbhijit Gangurde 			 PAGE_SIZE, DMA_FROM_DEVICE);
233*ea4c3996SAbhijit Gangurde err_dma:
234*ea4c3996SAbhijit Gangurde 	return rc;
235*ea4c3996SAbhijit Gangurde }
236*ea4c3996SAbhijit Gangurde 
237*ea4c3996SAbhijit Gangurde static struct rdma_hw_stats *
238*ea4c3996SAbhijit Gangurde ionic_counter_alloc_stats(struct rdma_counter *counter)
239*ea4c3996SAbhijit Gangurde {
240*ea4c3996SAbhijit Gangurde 	struct ionic_ibdev *dev = to_ionic_ibdev(counter->device);
241*ea4c3996SAbhijit Gangurde 	struct ionic_counter *cntr;
242*ea4c3996SAbhijit Gangurde 	int err;
243*ea4c3996SAbhijit Gangurde 
244*ea4c3996SAbhijit Gangurde 	cntr = kzalloc(sizeof(*cntr), GFP_KERNEL);
245*ea4c3996SAbhijit Gangurde 	if (!cntr)
246*ea4c3996SAbhijit Gangurde 		return NULL;
247*ea4c3996SAbhijit Gangurde 
248*ea4c3996SAbhijit Gangurde 	/* buffer for current values from the device */
249*ea4c3996SAbhijit Gangurde 	cntr->vals = kzalloc(PAGE_SIZE, GFP_KERNEL);
250*ea4c3996SAbhijit Gangurde 	if (!cntr->vals)
251*ea4c3996SAbhijit Gangurde 		goto err_vals;
252*ea4c3996SAbhijit Gangurde 
253*ea4c3996SAbhijit Gangurde 	err = xa_alloc(&dev->counter_stats->xa_counters, &counter->id,
254*ea4c3996SAbhijit Gangurde 		       cntr,
255*ea4c3996SAbhijit Gangurde 		       XA_LIMIT(0, IONIC_MAX_QPID),
256*ea4c3996SAbhijit Gangurde 		       GFP_KERNEL);
257*ea4c3996SAbhijit Gangurde 	if (err)
258*ea4c3996SAbhijit Gangurde 		goto err_xa;
259*ea4c3996SAbhijit Gangurde 
260*ea4c3996SAbhijit Gangurde 	INIT_LIST_HEAD(&cntr->qp_list);
261*ea4c3996SAbhijit Gangurde 
262*ea4c3996SAbhijit Gangurde 	return rdma_alloc_hw_stats_struct(dev->counter_stats->stats_hdrs,
263*ea4c3996SAbhijit Gangurde 					 dev->counter_stats->queue_stats_count,
264*ea4c3996SAbhijit Gangurde 					 RDMA_HW_STATS_DEFAULT_LIFESPAN);
265*ea4c3996SAbhijit Gangurde err_xa:
266*ea4c3996SAbhijit Gangurde 	kfree(cntr->vals);
267*ea4c3996SAbhijit Gangurde err_vals:
268*ea4c3996SAbhijit Gangurde 	kfree(cntr);
269*ea4c3996SAbhijit Gangurde 
270*ea4c3996SAbhijit Gangurde 	return NULL;
271*ea4c3996SAbhijit Gangurde }
272*ea4c3996SAbhijit Gangurde 
273*ea4c3996SAbhijit Gangurde static int ionic_counter_dealloc(struct rdma_counter *counter)
274*ea4c3996SAbhijit Gangurde {
275*ea4c3996SAbhijit Gangurde 	struct ionic_ibdev *dev = to_ionic_ibdev(counter->device);
276*ea4c3996SAbhijit Gangurde 	struct ionic_counter *cntr;
277*ea4c3996SAbhijit Gangurde 
278*ea4c3996SAbhijit Gangurde 	cntr = xa_erase(&dev->counter_stats->xa_counters, counter->id);
279*ea4c3996SAbhijit Gangurde 	if (!cntr)
280*ea4c3996SAbhijit Gangurde 		return -EINVAL;
281*ea4c3996SAbhijit Gangurde 
282*ea4c3996SAbhijit Gangurde 	kfree(cntr->vals);
283*ea4c3996SAbhijit Gangurde 	kfree(cntr);
284*ea4c3996SAbhijit Gangurde 
285*ea4c3996SAbhijit Gangurde 	return 0;
286*ea4c3996SAbhijit Gangurde }
287*ea4c3996SAbhijit Gangurde 
288*ea4c3996SAbhijit Gangurde static int ionic_counter_bind_qp(struct rdma_counter *counter,
289*ea4c3996SAbhijit Gangurde 				 struct ib_qp *ibqp,
290*ea4c3996SAbhijit Gangurde 				 u32 port)
291*ea4c3996SAbhijit Gangurde {
292*ea4c3996SAbhijit Gangurde 	struct ionic_ibdev *dev = to_ionic_ibdev(counter->device);
293*ea4c3996SAbhijit Gangurde 	struct ionic_qp *qp = to_ionic_qp(ibqp);
294*ea4c3996SAbhijit Gangurde 	struct ionic_counter *cntr;
295*ea4c3996SAbhijit Gangurde 
296*ea4c3996SAbhijit Gangurde 	cntr = xa_load(&dev->counter_stats->xa_counters, counter->id);
297*ea4c3996SAbhijit Gangurde 	if (!cntr)
298*ea4c3996SAbhijit Gangurde 		return -EINVAL;
299*ea4c3996SAbhijit Gangurde 
300*ea4c3996SAbhijit Gangurde 	list_add_tail(&qp->qp_list_counter, &cntr->qp_list);
301*ea4c3996SAbhijit Gangurde 	ibqp->counter = counter;
302*ea4c3996SAbhijit Gangurde 
303*ea4c3996SAbhijit Gangurde 	return 0;
304*ea4c3996SAbhijit Gangurde }
305*ea4c3996SAbhijit Gangurde 
306*ea4c3996SAbhijit Gangurde static int ionic_counter_unbind_qp(struct ib_qp *ibqp, u32 port)
307*ea4c3996SAbhijit Gangurde {
308*ea4c3996SAbhijit Gangurde 	struct ionic_qp *qp = to_ionic_qp(ibqp);
309*ea4c3996SAbhijit Gangurde 
310*ea4c3996SAbhijit Gangurde 	if (ibqp->counter) {
311*ea4c3996SAbhijit Gangurde 		list_del(&qp->qp_list_counter);
312*ea4c3996SAbhijit Gangurde 		ibqp->counter = NULL;
313*ea4c3996SAbhijit Gangurde 	}
314*ea4c3996SAbhijit Gangurde 
315*ea4c3996SAbhijit Gangurde 	return 0;
316*ea4c3996SAbhijit Gangurde }
317*ea4c3996SAbhijit Gangurde 
318*ea4c3996SAbhijit Gangurde static int ionic_get_qp_stats(struct ib_device *ibdev,
319*ea4c3996SAbhijit Gangurde 			      struct rdma_hw_stats *hw_stats,
320*ea4c3996SAbhijit Gangurde 			      u32 counter_id)
321*ea4c3996SAbhijit Gangurde {
322*ea4c3996SAbhijit Gangurde 	struct ionic_ibdev *dev = to_ionic_ibdev(ibdev);
323*ea4c3996SAbhijit Gangurde 	struct ionic_counter_stats *cs;
324*ea4c3996SAbhijit Gangurde 	struct ionic_counter *cntr;
325*ea4c3996SAbhijit Gangurde 	dma_addr_t hw_stats_dma;
326*ea4c3996SAbhijit Gangurde 	struct ionic_qp *qp;
327*ea4c3996SAbhijit Gangurde 	int rc, stat_i = 0;
328*ea4c3996SAbhijit Gangurde 
329*ea4c3996SAbhijit Gangurde 	cs = dev->counter_stats;
330*ea4c3996SAbhijit Gangurde 	cntr = xa_load(&cs->xa_counters, counter_id);
331*ea4c3996SAbhijit Gangurde 	if (!cntr)
332*ea4c3996SAbhijit Gangurde 		return -EINVAL;
333*ea4c3996SAbhijit Gangurde 
334*ea4c3996SAbhijit Gangurde 	hw_stats_dma = dma_map_single(dev->lif_cfg.hwdev, cntr->vals,
335*ea4c3996SAbhijit Gangurde 				      PAGE_SIZE, DMA_FROM_DEVICE);
336*ea4c3996SAbhijit Gangurde 	rc = dma_mapping_error(dev->lif_cfg.hwdev, hw_stats_dma);
337*ea4c3996SAbhijit Gangurde 	if (rc)
338*ea4c3996SAbhijit Gangurde 		return rc;
339*ea4c3996SAbhijit Gangurde 
340*ea4c3996SAbhijit Gangurde 	memset(hw_stats->value, 0, sizeof(u64) * hw_stats->num_counters);
341*ea4c3996SAbhijit Gangurde 
342*ea4c3996SAbhijit Gangurde 	list_for_each_entry(qp, &cntr->qp_list, qp_list_counter) {
343*ea4c3996SAbhijit Gangurde 		rc = ionic_hw_stats_cmd(dev, hw_stats_dma, PAGE_SIZE,
344*ea4c3996SAbhijit Gangurde 					qp->qpid,
345*ea4c3996SAbhijit Gangurde 					IONIC_V1_ADMIN_QP_STATS_VALS);
346*ea4c3996SAbhijit Gangurde 		if (rc)
347*ea4c3996SAbhijit Gangurde 			goto err_cmd;
348*ea4c3996SAbhijit Gangurde 
349*ea4c3996SAbhijit Gangurde 		for (stat_i = 0; stat_i < cs->queue_stats_count; ++stat_i)
350*ea4c3996SAbhijit Gangurde 			hw_stats->value[stat_i] +=
351*ea4c3996SAbhijit Gangurde 				ionic_v1_stat_val(&cs->hdr[stat_i],
352*ea4c3996SAbhijit Gangurde 						  cntr->vals,
353*ea4c3996SAbhijit Gangurde 						  PAGE_SIZE);
354*ea4c3996SAbhijit Gangurde 	}
355*ea4c3996SAbhijit Gangurde 
356*ea4c3996SAbhijit Gangurde 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma, PAGE_SIZE, DMA_FROM_DEVICE);
357*ea4c3996SAbhijit Gangurde 	return stat_i;
358*ea4c3996SAbhijit Gangurde 
359*ea4c3996SAbhijit Gangurde err_cmd:
360*ea4c3996SAbhijit Gangurde 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma, PAGE_SIZE, DMA_FROM_DEVICE);
361*ea4c3996SAbhijit Gangurde 
362*ea4c3996SAbhijit Gangurde 	return rc;
363*ea4c3996SAbhijit Gangurde }
364*ea4c3996SAbhijit Gangurde 
365*ea4c3996SAbhijit Gangurde static int ionic_counter_update_stats(struct rdma_counter *counter)
366*ea4c3996SAbhijit Gangurde {
367*ea4c3996SAbhijit Gangurde 	return ionic_get_qp_stats(counter->device, counter->stats, counter->id);
368*ea4c3996SAbhijit Gangurde }
369*ea4c3996SAbhijit Gangurde 
370*ea4c3996SAbhijit Gangurde static int ionic_alloc_counters(struct ionic_ibdev *dev)
371*ea4c3996SAbhijit Gangurde {
372*ea4c3996SAbhijit Gangurde 	struct ionic_counter_stats *cs = dev->counter_stats;
373*ea4c3996SAbhijit Gangurde 	int rc, hw_stats_count;
374*ea4c3996SAbhijit Gangurde 	dma_addr_t hdr_dma;
375*ea4c3996SAbhijit Gangurde 
376*ea4c3996SAbhijit Gangurde 	/* buffer for names, sizes, offsets of values */
377*ea4c3996SAbhijit Gangurde 	cs->hdr = kzalloc(PAGE_SIZE, GFP_KERNEL);
378*ea4c3996SAbhijit Gangurde 	if (!cs->hdr)
379*ea4c3996SAbhijit Gangurde 		return -ENOMEM;
380*ea4c3996SAbhijit Gangurde 
381*ea4c3996SAbhijit Gangurde 	hdr_dma = dma_map_single(dev->lif_cfg.hwdev, cs->hdr,
382*ea4c3996SAbhijit Gangurde 				 PAGE_SIZE, DMA_FROM_DEVICE);
383*ea4c3996SAbhijit Gangurde 	rc = dma_mapping_error(dev->lif_cfg.hwdev, hdr_dma);
384*ea4c3996SAbhijit Gangurde 	if (rc)
385*ea4c3996SAbhijit Gangurde 		goto err_dma;
386*ea4c3996SAbhijit Gangurde 
387*ea4c3996SAbhijit Gangurde 	rc = ionic_hw_stats_cmd(dev, hdr_dma, PAGE_SIZE, 0,
388*ea4c3996SAbhijit Gangurde 				IONIC_V1_ADMIN_QP_STATS_HDRS);
389*ea4c3996SAbhijit Gangurde 	if (rc)
390*ea4c3996SAbhijit Gangurde 		goto err_cmd;
391*ea4c3996SAbhijit Gangurde 
392*ea4c3996SAbhijit Gangurde 	dma_unmap_single(dev->lif_cfg.hwdev, hdr_dma, PAGE_SIZE, DMA_FROM_DEVICE);
393*ea4c3996SAbhijit Gangurde 
394*ea4c3996SAbhijit Gangurde 	/* normalize and count the number of hw_stats */
395*ea4c3996SAbhijit Gangurde 	hw_stats_count = ionic_v1_stat_normalize(cs->hdr,
396*ea4c3996SAbhijit Gangurde 						 PAGE_SIZE / sizeof(*cs->hdr));
397*ea4c3996SAbhijit Gangurde 	if (!hw_stats_count) {
398*ea4c3996SAbhijit Gangurde 		rc = -ENODATA;
399*ea4c3996SAbhijit Gangurde 		goto err_dma;
400*ea4c3996SAbhijit Gangurde 	}
401*ea4c3996SAbhijit Gangurde 
402*ea4c3996SAbhijit Gangurde 	cs->queue_stats_count = hw_stats_count;
403*ea4c3996SAbhijit Gangurde 
404*ea4c3996SAbhijit Gangurde 	/* alloc and init array of names */
405*ea4c3996SAbhijit Gangurde 	cs->stats_hdrs = kcalloc(hw_stats_count, sizeof(*cs->stats_hdrs),
406*ea4c3996SAbhijit Gangurde 				 GFP_KERNEL);
407*ea4c3996SAbhijit Gangurde 	if (!cs->stats_hdrs) {
408*ea4c3996SAbhijit Gangurde 		rc = -ENOMEM;
409*ea4c3996SAbhijit Gangurde 		goto err_dma;
410*ea4c3996SAbhijit Gangurde 	}
411*ea4c3996SAbhijit Gangurde 
412*ea4c3996SAbhijit Gangurde 	ionic_fill_stats_desc(cs->stats_hdrs, cs->hdr, hw_stats_count);
413*ea4c3996SAbhijit Gangurde 
414*ea4c3996SAbhijit Gangurde 	return 0;
415*ea4c3996SAbhijit Gangurde 
416*ea4c3996SAbhijit Gangurde err_cmd:
417*ea4c3996SAbhijit Gangurde 	dma_unmap_single(dev->lif_cfg.hwdev, hdr_dma, PAGE_SIZE, DMA_FROM_DEVICE);
418*ea4c3996SAbhijit Gangurde err_dma:
419*ea4c3996SAbhijit Gangurde 	kfree(cs->hdr);
420*ea4c3996SAbhijit Gangurde 
421*ea4c3996SAbhijit Gangurde 	return rc;
422*ea4c3996SAbhijit Gangurde }
423*ea4c3996SAbhijit Gangurde 
424*ea4c3996SAbhijit Gangurde static const struct ib_device_ops ionic_hw_stats_ops = {
425*ea4c3996SAbhijit Gangurde 	.driver_id = RDMA_DRIVER_IONIC,
426*ea4c3996SAbhijit Gangurde 	.alloc_hw_port_stats = ionic_alloc_hw_stats,
427*ea4c3996SAbhijit Gangurde 	.get_hw_stats = ionic_get_hw_stats,
428*ea4c3996SAbhijit Gangurde };
429*ea4c3996SAbhijit Gangurde 
430*ea4c3996SAbhijit Gangurde static const struct ib_device_ops ionic_counter_stats_ops = {
431*ea4c3996SAbhijit Gangurde 	.counter_alloc_stats = ionic_counter_alloc_stats,
432*ea4c3996SAbhijit Gangurde 	.counter_dealloc = ionic_counter_dealloc,
433*ea4c3996SAbhijit Gangurde 	.counter_bind_qp = ionic_counter_bind_qp,
434*ea4c3996SAbhijit Gangurde 	.counter_unbind_qp = ionic_counter_unbind_qp,
435*ea4c3996SAbhijit Gangurde 	.counter_update_stats = ionic_counter_update_stats,
436*ea4c3996SAbhijit Gangurde };
437*ea4c3996SAbhijit Gangurde 
438*ea4c3996SAbhijit Gangurde void ionic_stats_init(struct ionic_ibdev *dev)
439*ea4c3996SAbhijit Gangurde {
440*ea4c3996SAbhijit Gangurde 	u16 stats_type = dev->lif_cfg.stats_type;
441*ea4c3996SAbhijit Gangurde 	int rc;
442*ea4c3996SAbhijit Gangurde 
443*ea4c3996SAbhijit Gangurde 	if (stats_type & IONIC_LIF_RDMA_STAT_GLOBAL) {
444*ea4c3996SAbhijit Gangurde 		rc = ionic_init_hw_stats(dev);
445*ea4c3996SAbhijit Gangurde 		if (rc)
446*ea4c3996SAbhijit Gangurde 			ibdev_dbg(&dev->ibdev, "Failed to init hw stats\n");
447*ea4c3996SAbhijit Gangurde 		else
448*ea4c3996SAbhijit Gangurde 			ib_set_device_ops(&dev->ibdev, &ionic_hw_stats_ops);
449*ea4c3996SAbhijit Gangurde 	}
450*ea4c3996SAbhijit Gangurde 
451*ea4c3996SAbhijit Gangurde 	if (stats_type & IONIC_LIF_RDMA_STAT_QP) {
452*ea4c3996SAbhijit Gangurde 		dev->counter_stats = kzalloc(sizeof(*dev->counter_stats),
453*ea4c3996SAbhijit Gangurde 					     GFP_KERNEL);
454*ea4c3996SAbhijit Gangurde 		if (!dev->counter_stats)
455*ea4c3996SAbhijit Gangurde 			return;
456*ea4c3996SAbhijit Gangurde 
457*ea4c3996SAbhijit Gangurde 		rc = ionic_alloc_counters(dev);
458*ea4c3996SAbhijit Gangurde 		if (rc) {
459*ea4c3996SAbhijit Gangurde 			ibdev_dbg(&dev->ibdev, "Failed to init counter stats\n");
460*ea4c3996SAbhijit Gangurde 			kfree(dev->counter_stats);
461*ea4c3996SAbhijit Gangurde 			dev->counter_stats = NULL;
462*ea4c3996SAbhijit Gangurde 			return;
463*ea4c3996SAbhijit Gangurde 		}
464*ea4c3996SAbhijit Gangurde 
465*ea4c3996SAbhijit Gangurde 		xa_init_flags(&dev->counter_stats->xa_counters, XA_FLAGS_ALLOC);
466*ea4c3996SAbhijit Gangurde 
467*ea4c3996SAbhijit Gangurde 		ib_set_device_ops(&dev->ibdev, &ionic_counter_stats_ops);
468*ea4c3996SAbhijit Gangurde 	}
469*ea4c3996SAbhijit Gangurde }
470*ea4c3996SAbhijit Gangurde 
471*ea4c3996SAbhijit Gangurde void ionic_stats_cleanup(struct ionic_ibdev *dev)
472*ea4c3996SAbhijit Gangurde {
473*ea4c3996SAbhijit Gangurde 	if (dev->counter_stats) {
474*ea4c3996SAbhijit Gangurde 		xa_destroy(&dev->counter_stats->xa_counters);
475*ea4c3996SAbhijit Gangurde 		kfree(dev->counter_stats->hdr);
476*ea4c3996SAbhijit Gangurde 		kfree(dev->counter_stats->stats_hdrs);
477*ea4c3996SAbhijit Gangurde 		kfree(dev->counter_stats);
478*ea4c3996SAbhijit Gangurde 		dev->counter_stats = NULL;
479*ea4c3996SAbhijit Gangurde 	}
480*ea4c3996SAbhijit Gangurde 
481*ea4c3996SAbhijit Gangurde 	kfree(dev->hw_stats);
482*ea4c3996SAbhijit Gangurde 	kfree(dev->hw_stats_buf);
483*ea4c3996SAbhijit Gangurde 	kfree(dev->hw_stats_hdrs);
484*ea4c3996SAbhijit Gangurde }
485