1e0e4b8faSGuvenc Gulce /* SPDX-License-Identifier: GPL-2.0 */ 2e0e4b8faSGuvenc Gulce /* 3e0e4b8faSGuvenc Gulce * Shared Memory Communications over RDMA (SMC-R) and RoCE 4e0e4b8faSGuvenc Gulce * 5e0e4b8faSGuvenc Gulce * Macros for SMC statistics 6e0e4b8faSGuvenc Gulce * 7e0e4b8faSGuvenc Gulce * Copyright IBM Corp. 2021 8e0e4b8faSGuvenc Gulce * 9e0e4b8faSGuvenc Gulce * Author(s): Guvenc Gulce 10e0e4b8faSGuvenc Gulce */ 11e0e4b8faSGuvenc Gulce 12e0e4b8faSGuvenc Gulce #ifndef NET_SMC_SMC_STATS_H_ 13e0e4b8faSGuvenc Gulce #define NET_SMC_SMC_STATS_H_ 14e0e4b8faSGuvenc Gulce #include <linux/init.h> 15e0e4b8faSGuvenc Gulce #include <linux/mutex.h> 16e0e4b8faSGuvenc Gulce #include <linux/percpu.h> 17e0e4b8faSGuvenc Gulce #include <linux/ctype.h> 18e0e4b8faSGuvenc Gulce #include <linux/smc.h> 19e0e4b8faSGuvenc Gulce 20e0e4b8faSGuvenc Gulce #include "smc_clc.h" 21e0e4b8faSGuvenc Gulce 22*f7dc578aSZhengchao Shao #define SMC_MAX_FBACK_RSN_CNT 36 23e0e4b8faSGuvenc Gulce 24e0e4b8faSGuvenc Gulce enum { 25e0e4b8faSGuvenc Gulce SMC_BUF_8K, 26e0e4b8faSGuvenc Gulce SMC_BUF_16K, 27e0e4b8faSGuvenc Gulce SMC_BUF_32K, 28e0e4b8faSGuvenc Gulce SMC_BUF_64K, 29e0e4b8faSGuvenc Gulce SMC_BUF_128K, 30e0e4b8faSGuvenc Gulce SMC_BUF_256K, 31e0e4b8faSGuvenc Gulce SMC_BUF_512K, 32e0e4b8faSGuvenc Gulce SMC_BUF_1024K, 33e0e4b8faSGuvenc Gulce SMC_BUF_G_1024K, 34e0e4b8faSGuvenc Gulce SMC_BUF_MAX, 35e0e4b8faSGuvenc Gulce }; 36e0e4b8faSGuvenc Gulce 37e0e4b8faSGuvenc Gulce struct smc_stats_fback { 38e0e4b8faSGuvenc Gulce int fback_code; 39e0e4b8faSGuvenc Gulce u16 count; 40e0e4b8faSGuvenc Gulce }; 41e0e4b8faSGuvenc Gulce 42194730a9SGuvenc Gulce struct smc_stats_rsn { 43e0e4b8faSGuvenc Gulce struct smc_stats_fback srv[SMC_MAX_FBACK_RSN_CNT]; 44e0e4b8faSGuvenc Gulce struct smc_stats_fback clnt[SMC_MAX_FBACK_RSN_CNT]; 45e0e4b8faSGuvenc Gulce u64 srv_fback_cnt; 46e0e4b8faSGuvenc Gulce u64 clnt_fback_cnt; 47e0e4b8faSGuvenc Gulce }; 48e0e4b8faSGuvenc Gulce 49e0e4b8faSGuvenc Gulce struct smc_stats_rmbcnt { 50e0e4b8faSGuvenc Gulce u64 buf_size_small_peer_cnt; 51e0e4b8faSGuvenc Gulce u64 buf_size_small_cnt; 52e0e4b8faSGuvenc Gulce u64 buf_full_peer_cnt; 53e0e4b8faSGuvenc Gulce u64 buf_full_cnt; 54e0e4b8faSGuvenc Gulce u64 reuse_cnt; 55e0e4b8faSGuvenc Gulce u64 alloc_cnt; 56e0e4b8faSGuvenc Gulce u64 dgrade_cnt; 57e0e4b8faSGuvenc Gulce }; 58e0e4b8faSGuvenc Gulce 59e0e4b8faSGuvenc Gulce struct smc_stats_memsize { 60e0e4b8faSGuvenc Gulce u64 buf[SMC_BUF_MAX]; 61e0e4b8faSGuvenc Gulce }; 62e0e4b8faSGuvenc Gulce 63e0e4b8faSGuvenc Gulce struct smc_stats_tech { 64e0e4b8faSGuvenc Gulce struct smc_stats_memsize tx_rmbsize; 65e0e4b8faSGuvenc Gulce struct smc_stats_memsize rx_rmbsize; 66e0e4b8faSGuvenc Gulce struct smc_stats_memsize tx_pd; 67e0e4b8faSGuvenc Gulce struct smc_stats_memsize rx_pd; 68e0e4b8faSGuvenc Gulce struct smc_stats_rmbcnt rmb_tx; 69e0e4b8faSGuvenc Gulce struct smc_stats_rmbcnt rmb_rx; 70e0e4b8faSGuvenc Gulce u64 clnt_v1_succ_cnt; 71e0e4b8faSGuvenc Gulce u64 clnt_v2_succ_cnt; 72e0e4b8faSGuvenc Gulce u64 srv_v1_succ_cnt; 73e0e4b8faSGuvenc Gulce u64 srv_v2_succ_cnt; 74e0e4b8faSGuvenc Gulce u64 urg_data_cnt; 75e0e4b8faSGuvenc Gulce u64 splice_cnt; 76e0e4b8faSGuvenc Gulce u64 cork_cnt; 77e0e4b8faSGuvenc Gulce u64 ndly_cnt; 78e0e4b8faSGuvenc Gulce u64 rx_bytes; 79e0e4b8faSGuvenc Gulce u64 tx_bytes; 80e0e4b8faSGuvenc Gulce u64 rx_cnt; 81e0e4b8faSGuvenc Gulce u64 tx_cnt; 82e0e4b8faSGuvenc Gulce }; 83e0e4b8faSGuvenc Gulce 84e0e4b8faSGuvenc Gulce struct smc_stats { 85e0e4b8faSGuvenc Gulce struct smc_stats_tech smc[2]; 86e0e4b8faSGuvenc Gulce u64 clnt_hshake_err_cnt; 87e0e4b8faSGuvenc Gulce u64 srv_hshake_err_cnt; 88e0e4b8faSGuvenc Gulce }; 89e0e4b8faSGuvenc Gulce 90194730a9SGuvenc Gulce #define SMC_STAT_PAYLOAD_SUB(_smc_stats, _tech, key, _len, _rc) \ 91e0e4b8faSGuvenc Gulce do { \ 92194730a9SGuvenc Gulce typeof(_smc_stats) stats = (_smc_stats); \ 93e0e4b8faSGuvenc Gulce typeof(_tech) t = (_tech); \ 94e0e4b8faSGuvenc Gulce typeof(_len) l = (_len); \ 95a950a592SNils Hoppmann int _pos; \ 96e0e4b8faSGuvenc Gulce typeof(_rc) r = (_rc); \ 97e0e4b8faSGuvenc Gulce int m = SMC_BUF_MAX - 1; \ 98194730a9SGuvenc Gulce this_cpu_inc((*stats).smc[t].key ## _cnt); \ 99a950a592SNils Hoppmann if (r <= 0 || l <= 0) \ 100e0e4b8faSGuvenc Gulce break; \ 101a950a592SNils Hoppmann _pos = fls64((l - 1) >> 13); \ 102a950a592SNils Hoppmann _pos = (_pos <= m) ? _pos : m; \ 103194730a9SGuvenc Gulce this_cpu_inc((*stats).smc[t].key ## _pd.buf[_pos]); \ 104194730a9SGuvenc Gulce this_cpu_add((*stats).smc[t].key ## _bytes, r); \ 105e0e4b8faSGuvenc Gulce } \ 106e0e4b8faSGuvenc Gulce while (0) 107e0e4b8faSGuvenc Gulce 108e0e4b8faSGuvenc Gulce #define SMC_STAT_TX_PAYLOAD(_smc, length, rcode) \ 109e0e4b8faSGuvenc Gulce do { \ 110e0e4b8faSGuvenc Gulce typeof(_smc) __smc = _smc; \ 111194730a9SGuvenc Gulce struct net *_net = sock_net(&__smc->sk); \ 112194730a9SGuvenc Gulce struct smc_stats __percpu *_smc_stats = _net->smc.smc_stats; \ 113e0e4b8faSGuvenc Gulce typeof(length) _len = (length); \ 114e0e4b8faSGuvenc Gulce typeof(rcode) _rc = (rcode); \ 115e0e4b8faSGuvenc Gulce bool is_smcd = !__smc->conn.lnk; \ 116e0e4b8faSGuvenc Gulce if (is_smcd) \ 117194730a9SGuvenc Gulce SMC_STAT_PAYLOAD_SUB(_smc_stats, SMC_TYPE_D, tx, _len, _rc); \ 118e0e4b8faSGuvenc Gulce else \ 119194730a9SGuvenc Gulce SMC_STAT_PAYLOAD_SUB(_smc_stats, SMC_TYPE_R, tx, _len, _rc); \ 120e0e4b8faSGuvenc Gulce } \ 121e0e4b8faSGuvenc Gulce while (0) 122e0e4b8faSGuvenc Gulce 123e0e4b8faSGuvenc Gulce #define SMC_STAT_RX_PAYLOAD(_smc, length, rcode) \ 124e0e4b8faSGuvenc Gulce do { \ 125e0e4b8faSGuvenc Gulce typeof(_smc) __smc = _smc; \ 126194730a9SGuvenc Gulce struct net *_net = sock_net(&__smc->sk); \ 127194730a9SGuvenc Gulce struct smc_stats __percpu *_smc_stats = _net->smc.smc_stats; \ 128e0e4b8faSGuvenc Gulce typeof(length) _len = (length); \ 129e0e4b8faSGuvenc Gulce typeof(rcode) _rc = (rcode); \ 130e0e4b8faSGuvenc Gulce bool is_smcd = !__smc->conn.lnk; \ 131e0e4b8faSGuvenc Gulce if (is_smcd) \ 132194730a9SGuvenc Gulce SMC_STAT_PAYLOAD_SUB(_smc_stats, SMC_TYPE_D, rx, _len, _rc); \ 133e0e4b8faSGuvenc Gulce else \ 134194730a9SGuvenc Gulce SMC_STAT_PAYLOAD_SUB(_smc_stats, SMC_TYPE_R, rx, _len, _rc); \ 135e0e4b8faSGuvenc Gulce } \ 136e0e4b8faSGuvenc Gulce while (0) 137e0e4b8faSGuvenc Gulce 138194730a9SGuvenc Gulce #define SMC_STAT_RMB_SIZE_SUB(_smc_stats, _tech, k, _len) \ 139e0e4b8faSGuvenc Gulce do { \ 140e0e4b8faSGuvenc Gulce typeof(_len) _l = (_len); \ 141e0e4b8faSGuvenc Gulce typeof(_tech) t = (_tech); \ 142a950a592SNils Hoppmann int _pos; \ 143e0e4b8faSGuvenc Gulce int m = SMC_BUF_MAX - 1; \ 144a950a592SNils Hoppmann if (_l <= 0) \ 145a950a592SNils Hoppmann break; \ 146a950a592SNils Hoppmann _pos = fls((_l - 1) >> 13); \ 147a950a592SNils Hoppmann _pos = (_pos <= m) ? _pos : m; \ 148194730a9SGuvenc Gulce this_cpu_inc((*(_smc_stats)).smc[t].k ## _rmbsize.buf[_pos]); \ 149e0e4b8faSGuvenc Gulce } \ 150e0e4b8faSGuvenc Gulce while (0) 151e0e4b8faSGuvenc Gulce 152194730a9SGuvenc Gulce #define SMC_STAT_RMB_SUB(_smc_stats, type, t, key) \ 153194730a9SGuvenc Gulce this_cpu_inc((*(_smc_stats)).smc[t].rmb ## _ ## key.type ## _cnt) 154e0e4b8faSGuvenc Gulce 155194730a9SGuvenc Gulce #define SMC_STAT_RMB_SIZE(_smc, _is_smcd, _is_rx, _len) \ 156e0e4b8faSGuvenc Gulce do { \ 157194730a9SGuvenc Gulce struct net *_net = sock_net(&(_smc)->sk); \ 158194730a9SGuvenc Gulce struct smc_stats __percpu *_smc_stats = _net->smc.smc_stats; \ 159e0e4b8faSGuvenc Gulce typeof(_is_smcd) is_d = (_is_smcd); \ 160e0e4b8faSGuvenc Gulce typeof(_is_rx) is_r = (_is_rx); \ 161e0e4b8faSGuvenc Gulce typeof(_len) l = (_len); \ 162e0e4b8faSGuvenc Gulce if ((is_d) && (is_r)) \ 163194730a9SGuvenc Gulce SMC_STAT_RMB_SIZE_SUB(_smc_stats, SMC_TYPE_D, rx, l); \ 164e0e4b8faSGuvenc Gulce if ((is_d) && !(is_r)) \ 165194730a9SGuvenc Gulce SMC_STAT_RMB_SIZE_SUB(_smc_stats, SMC_TYPE_D, tx, l); \ 166e0e4b8faSGuvenc Gulce if (!(is_d) && (is_r)) \ 167194730a9SGuvenc Gulce SMC_STAT_RMB_SIZE_SUB(_smc_stats, SMC_TYPE_R, rx, l); \ 168e0e4b8faSGuvenc Gulce if (!(is_d) && !(is_r)) \ 169194730a9SGuvenc Gulce SMC_STAT_RMB_SIZE_SUB(_smc_stats, SMC_TYPE_R, tx, l); \ 170e0e4b8faSGuvenc Gulce } \ 171e0e4b8faSGuvenc Gulce while (0) 172e0e4b8faSGuvenc Gulce 173194730a9SGuvenc Gulce #define SMC_STAT_RMB(_smc, type, _is_smcd, _is_rx) \ 174e0e4b8faSGuvenc Gulce do { \ 175194730a9SGuvenc Gulce struct net *net = sock_net(&(_smc)->sk); \ 176194730a9SGuvenc Gulce struct smc_stats __percpu *_smc_stats = net->smc.smc_stats; \ 177e0e4b8faSGuvenc Gulce typeof(_is_smcd) is_d = (_is_smcd); \ 178e0e4b8faSGuvenc Gulce typeof(_is_rx) is_r = (_is_rx); \ 179e0e4b8faSGuvenc Gulce if ((is_d) && (is_r)) \ 180194730a9SGuvenc Gulce SMC_STAT_RMB_SUB(_smc_stats, type, SMC_TYPE_D, rx); \ 181e0e4b8faSGuvenc Gulce if ((is_d) && !(is_r)) \ 182194730a9SGuvenc Gulce SMC_STAT_RMB_SUB(_smc_stats, type, SMC_TYPE_D, tx); \ 183e0e4b8faSGuvenc Gulce if (!(is_d) && (is_r)) \ 184194730a9SGuvenc Gulce SMC_STAT_RMB_SUB(_smc_stats, type, SMC_TYPE_R, rx); \ 185e0e4b8faSGuvenc Gulce if (!(is_d) && !(is_r)) \ 186194730a9SGuvenc Gulce SMC_STAT_RMB_SUB(_smc_stats, type, SMC_TYPE_R, tx); \ 187e0e4b8faSGuvenc Gulce } \ 188e0e4b8faSGuvenc Gulce while (0) 189e0e4b8faSGuvenc Gulce 190194730a9SGuvenc Gulce #define SMC_STAT_BUF_REUSE(smc, is_smcd, is_rx) \ 191194730a9SGuvenc Gulce SMC_STAT_RMB(smc, reuse, is_smcd, is_rx) 192e0e4b8faSGuvenc Gulce 193194730a9SGuvenc Gulce #define SMC_STAT_RMB_ALLOC(smc, is_smcd, is_rx) \ 194194730a9SGuvenc Gulce SMC_STAT_RMB(smc, alloc, is_smcd, is_rx) 195e0e4b8faSGuvenc Gulce 196194730a9SGuvenc Gulce #define SMC_STAT_RMB_DOWNGRADED(smc, is_smcd, is_rx) \ 197194730a9SGuvenc Gulce SMC_STAT_RMB(smc, dgrade, is_smcd, is_rx) 198e0e4b8faSGuvenc Gulce 199194730a9SGuvenc Gulce #define SMC_STAT_RMB_TX_PEER_FULL(smc, is_smcd) \ 200194730a9SGuvenc Gulce SMC_STAT_RMB(smc, buf_full_peer, is_smcd, false) 201e0e4b8faSGuvenc Gulce 202194730a9SGuvenc Gulce #define SMC_STAT_RMB_TX_FULL(smc, is_smcd) \ 203194730a9SGuvenc Gulce SMC_STAT_RMB(smc, buf_full, is_smcd, false) 204e0e4b8faSGuvenc Gulce 205194730a9SGuvenc Gulce #define SMC_STAT_RMB_TX_PEER_SIZE_SMALL(smc, is_smcd) \ 206194730a9SGuvenc Gulce SMC_STAT_RMB(smc, buf_size_small_peer, is_smcd, false) 207e0e4b8faSGuvenc Gulce 208194730a9SGuvenc Gulce #define SMC_STAT_RMB_TX_SIZE_SMALL(smc, is_smcd) \ 209194730a9SGuvenc Gulce SMC_STAT_RMB(smc, buf_size_small, is_smcd, false) 210e0e4b8faSGuvenc Gulce 211194730a9SGuvenc Gulce #define SMC_STAT_RMB_RX_SIZE_SMALL(smc, is_smcd) \ 212194730a9SGuvenc Gulce SMC_STAT_RMB(smc, buf_size_small, is_smcd, true) 213e0e4b8faSGuvenc Gulce 214194730a9SGuvenc Gulce #define SMC_STAT_RMB_RX_FULL(smc, is_smcd) \ 215194730a9SGuvenc Gulce SMC_STAT_RMB(smc, buf_full, is_smcd, true) 216e0e4b8faSGuvenc Gulce 217194730a9SGuvenc Gulce #define SMC_STAT_INC(_smc, type) \ 218e0e4b8faSGuvenc Gulce do { \ 219194730a9SGuvenc Gulce typeof(_smc) __smc = _smc; \ 220194730a9SGuvenc Gulce bool is_smcd = !(__smc)->conn.lnk; \ 221194730a9SGuvenc Gulce struct net *net = sock_net(&(__smc)->sk); \ 222194730a9SGuvenc Gulce struct smc_stats __percpu *smc_stats = net->smc.smc_stats; \ 223e0e4b8faSGuvenc Gulce if ((is_smcd)) \ 224e0e4b8faSGuvenc Gulce this_cpu_inc(smc_stats->smc[SMC_TYPE_D].type); \ 225e0e4b8faSGuvenc Gulce else \ 226e0e4b8faSGuvenc Gulce this_cpu_inc(smc_stats->smc[SMC_TYPE_R].type); \ 227e0e4b8faSGuvenc Gulce } \ 228e0e4b8faSGuvenc Gulce while (0) 229e0e4b8faSGuvenc Gulce 230194730a9SGuvenc Gulce #define SMC_STAT_CLNT_SUCC_INC(net, _aclc) \ 231e0e4b8faSGuvenc Gulce do { \ 232e0e4b8faSGuvenc Gulce typeof(_aclc) acl = (_aclc); \ 233e0e4b8faSGuvenc Gulce bool is_v2 = (acl->hdr.version == SMC_V2); \ 234e0e4b8faSGuvenc Gulce bool is_smcd = (acl->hdr.typev1 == SMC_TYPE_D); \ 235194730a9SGuvenc Gulce struct smc_stats __percpu *smc_stats = (net)->smc.smc_stats; \ 236e0e4b8faSGuvenc Gulce if (is_v2 && is_smcd) \ 237e0e4b8faSGuvenc Gulce this_cpu_inc(smc_stats->smc[SMC_TYPE_D].clnt_v2_succ_cnt); \ 238e0e4b8faSGuvenc Gulce else if (is_v2 && !is_smcd) \ 239e0e4b8faSGuvenc Gulce this_cpu_inc(smc_stats->smc[SMC_TYPE_R].clnt_v2_succ_cnt); \ 240e0e4b8faSGuvenc Gulce else if (!is_v2 && is_smcd) \ 241e0e4b8faSGuvenc Gulce this_cpu_inc(smc_stats->smc[SMC_TYPE_D].clnt_v1_succ_cnt); \ 242e0e4b8faSGuvenc Gulce else if (!is_v2 && !is_smcd) \ 243e0e4b8faSGuvenc Gulce this_cpu_inc(smc_stats->smc[SMC_TYPE_R].clnt_v1_succ_cnt); \ 244e0e4b8faSGuvenc Gulce } \ 245e0e4b8faSGuvenc Gulce while (0) 246e0e4b8faSGuvenc Gulce 247194730a9SGuvenc Gulce #define SMC_STAT_SERV_SUCC_INC(net, _ini) \ 248e0e4b8faSGuvenc Gulce do { \ 249e0e4b8faSGuvenc Gulce typeof(_ini) i = (_ini); \ 250e0e4b8faSGuvenc Gulce bool is_smcd = (i->is_smcd); \ 2516912e724SGuangguan Wang u8 version = is_smcd ? i->smcd_version : i->smcr_version; \ 2526912e724SGuangguan Wang bool is_v2 = (version & SMC_V2); \ 253194730a9SGuvenc Gulce typeof(net->smc.smc_stats) smc_stats = (net)->smc.smc_stats; \ 254e0e4b8faSGuvenc Gulce if (is_v2 && is_smcd) \ 255e0e4b8faSGuvenc Gulce this_cpu_inc(smc_stats->smc[SMC_TYPE_D].srv_v2_succ_cnt); \ 256e0e4b8faSGuvenc Gulce else if (is_v2 && !is_smcd) \ 257e0e4b8faSGuvenc Gulce this_cpu_inc(smc_stats->smc[SMC_TYPE_R].srv_v2_succ_cnt); \ 258e0e4b8faSGuvenc Gulce else if (!is_v2 && is_smcd) \ 259e0e4b8faSGuvenc Gulce this_cpu_inc(smc_stats->smc[SMC_TYPE_D].srv_v1_succ_cnt); \ 260e0e4b8faSGuvenc Gulce else if (!is_v2 && !is_smcd) \ 261e0e4b8faSGuvenc Gulce this_cpu_inc(smc_stats->smc[SMC_TYPE_R].srv_v1_succ_cnt); \ 262e0e4b8faSGuvenc Gulce } \ 263e0e4b8faSGuvenc Gulce while (0) 264e0e4b8faSGuvenc Gulce 2658c40602bSGuvenc Gulce int smc_nl_get_stats(struct sk_buff *skb, struct netlink_callback *cb); 266f0dd7bf5SGuvenc Gulce int smc_nl_get_fback_stats(struct sk_buff *skb, struct netlink_callback *cb); 267194730a9SGuvenc Gulce int smc_stats_init(struct net *net); 268194730a9SGuvenc Gulce void smc_stats_exit(struct net *net); 269e0e4b8faSGuvenc Gulce 270e0e4b8faSGuvenc Gulce #endif /* NET_SMC_SMC_STATS_H_ */ 271