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