cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

counters.c (15449B)


      1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
      2/*
      3 * Copyright (c) 2019 Mellanox Technologies. All rights reserved.
      4 */
      5#include <rdma/ib_verbs.h>
      6#include <rdma/rdma_counter.h>
      7
      8#include "core_priv.h"
      9#include "restrack.h"
     10
     11#define ALL_AUTO_MODE_MASKS (RDMA_COUNTER_MASK_QP_TYPE | RDMA_COUNTER_MASK_PID)
     12
     13static int __counter_set_mode(struct rdma_port_counter *port_counter,
     14			      enum rdma_nl_counter_mode new_mode,
     15			      enum rdma_nl_counter_mask new_mask)
     16{
     17	if (new_mode == RDMA_COUNTER_MODE_AUTO) {
     18		if (new_mask & (~ALL_AUTO_MODE_MASKS))
     19			return -EINVAL;
     20		if (port_counter->num_counters)
     21			return -EBUSY;
     22	}
     23
     24	port_counter->mode.mode = new_mode;
     25	port_counter->mode.mask = new_mask;
     26	return 0;
     27}
     28
     29/*
     30 * rdma_counter_set_auto_mode() - Turn on/off per-port auto mode
     31 *
     32 * @dev: Device to operate
     33 * @port: Port to use
     34 * @mask: Mask to configure
     35 * @extack: Message to the user
     36 *
     37 * Return 0 on success. If counter mode wasn't changed then it is considered
     38 * as success as well.
     39 * Return -EBUSY when changing to auto mode while there are bounded counters.
     40 *
     41 */
     42int rdma_counter_set_auto_mode(struct ib_device *dev, u32 port,
     43			       enum rdma_nl_counter_mask mask,
     44			       struct netlink_ext_ack *extack)
     45{
     46	struct rdma_port_counter *port_counter;
     47	enum rdma_nl_counter_mode mode;
     48	int ret;
     49
     50	port_counter = &dev->port_data[port].port_counter;
     51	if (!port_counter->hstats)
     52		return -EOPNOTSUPP;
     53
     54	mutex_lock(&port_counter->lock);
     55	if (mask)
     56		mode = RDMA_COUNTER_MODE_AUTO;
     57	else
     58		mode = (port_counter->num_counters) ? RDMA_COUNTER_MODE_MANUAL :
     59						      RDMA_COUNTER_MODE_NONE;
     60
     61	if (port_counter->mode.mode == mode &&
     62	    port_counter->mode.mask == mask) {
     63		ret = 0;
     64		goto out;
     65	}
     66
     67	ret = __counter_set_mode(port_counter, mode, mask);
     68
     69out:
     70	mutex_unlock(&port_counter->lock);
     71	if (ret == -EBUSY)
     72		NL_SET_ERR_MSG(
     73			extack,
     74			"Modifying auto mode is not allowed when there is a bound QP");
     75	return ret;
     76}
     77
     78static void auto_mode_init_counter(struct rdma_counter *counter,
     79				   const struct ib_qp *qp,
     80				   enum rdma_nl_counter_mask new_mask)
     81{
     82	struct auto_mode_param *param = &counter->mode.param;
     83
     84	counter->mode.mode = RDMA_COUNTER_MODE_AUTO;
     85	counter->mode.mask = new_mask;
     86
     87	if (new_mask & RDMA_COUNTER_MASK_QP_TYPE)
     88		param->qp_type = qp->qp_type;
     89}
     90
     91static int __rdma_counter_bind_qp(struct rdma_counter *counter,
     92				  struct ib_qp *qp)
     93{
     94	int ret;
     95
     96	if (qp->counter)
     97		return -EINVAL;
     98
     99	if (!qp->device->ops.counter_bind_qp)
    100		return -EOPNOTSUPP;
    101
    102	mutex_lock(&counter->lock);
    103	ret = qp->device->ops.counter_bind_qp(counter, qp);
    104	mutex_unlock(&counter->lock);
    105
    106	return ret;
    107}
    108
    109int rdma_counter_modify(struct ib_device *dev, u32 port,
    110			unsigned int index, bool enable)
    111{
    112	struct rdma_hw_stats *stats;
    113	int ret = 0;
    114
    115	if (!dev->ops.modify_hw_stat)
    116		return -EOPNOTSUPP;
    117
    118	stats = ib_get_hw_stats_port(dev, port);
    119	if (!stats || index >= stats->num_counters ||
    120	    !(stats->descs[index].flags & IB_STAT_FLAG_OPTIONAL))
    121		return -EINVAL;
    122
    123	mutex_lock(&stats->lock);
    124
    125	if (enable != test_bit(index, stats->is_disabled))
    126		goto out;
    127
    128	ret = dev->ops.modify_hw_stat(dev, port, index, enable);
    129	if (ret)
    130		goto out;
    131
    132	if (enable)
    133		clear_bit(index, stats->is_disabled);
    134	else
    135		set_bit(index, stats->is_disabled);
    136out:
    137	mutex_unlock(&stats->lock);
    138	return ret;
    139}
    140
    141static struct rdma_counter *alloc_and_bind(struct ib_device *dev, u32 port,
    142					   struct ib_qp *qp,
    143					   enum rdma_nl_counter_mode mode)
    144{
    145	struct rdma_port_counter *port_counter;
    146	struct rdma_counter *counter;
    147	int ret;
    148
    149	if (!dev->ops.counter_dealloc || !dev->ops.counter_alloc_stats)
    150		return NULL;
    151
    152	counter = kzalloc(sizeof(*counter), GFP_KERNEL);
    153	if (!counter)
    154		return NULL;
    155
    156	counter->device    = dev;
    157	counter->port      = port;
    158
    159	rdma_restrack_new(&counter->res, RDMA_RESTRACK_COUNTER);
    160	counter->stats = dev->ops.counter_alloc_stats(counter);
    161	if (!counter->stats)
    162		goto err_stats;
    163
    164	port_counter = &dev->port_data[port].port_counter;
    165	mutex_lock(&port_counter->lock);
    166	switch (mode) {
    167	case RDMA_COUNTER_MODE_MANUAL:
    168		ret = __counter_set_mode(port_counter, RDMA_COUNTER_MODE_MANUAL,
    169					 0);
    170		if (ret) {
    171			mutex_unlock(&port_counter->lock);
    172			goto err_mode;
    173		}
    174		break;
    175	case RDMA_COUNTER_MODE_AUTO:
    176		auto_mode_init_counter(counter, qp, port_counter->mode.mask);
    177		break;
    178	default:
    179		ret = -EOPNOTSUPP;
    180		mutex_unlock(&port_counter->lock);
    181		goto err_mode;
    182	}
    183
    184	port_counter->num_counters++;
    185	mutex_unlock(&port_counter->lock);
    186
    187	counter->mode.mode = mode;
    188	kref_init(&counter->kref);
    189	mutex_init(&counter->lock);
    190
    191	ret = __rdma_counter_bind_qp(counter, qp);
    192	if (ret)
    193		goto err_mode;
    194
    195	rdma_restrack_parent_name(&counter->res, &qp->res);
    196	rdma_restrack_add(&counter->res);
    197	return counter;
    198
    199err_mode:
    200	rdma_free_hw_stats_struct(counter->stats);
    201err_stats:
    202	rdma_restrack_put(&counter->res);
    203	kfree(counter);
    204	return NULL;
    205}
    206
    207static void rdma_counter_free(struct rdma_counter *counter)
    208{
    209	struct rdma_port_counter *port_counter;
    210
    211	port_counter = &counter->device->port_data[counter->port].port_counter;
    212	mutex_lock(&port_counter->lock);
    213	port_counter->num_counters--;
    214	if (!port_counter->num_counters &&
    215	    (port_counter->mode.mode == RDMA_COUNTER_MODE_MANUAL))
    216		__counter_set_mode(port_counter, RDMA_COUNTER_MODE_NONE, 0);
    217
    218	mutex_unlock(&port_counter->lock);
    219
    220	rdma_restrack_del(&counter->res);
    221	rdma_free_hw_stats_struct(counter->stats);
    222	kfree(counter);
    223}
    224
    225static bool auto_mode_match(struct ib_qp *qp, struct rdma_counter *counter,
    226			    enum rdma_nl_counter_mask auto_mask)
    227{
    228	struct auto_mode_param *param = &counter->mode.param;
    229	bool match = true;
    230
    231	if (auto_mask & RDMA_COUNTER_MASK_QP_TYPE)
    232		match &= (param->qp_type == qp->qp_type);
    233
    234	if (auto_mask & RDMA_COUNTER_MASK_PID)
    235		match &= (task_pid_nr(counter->res.task) ==
    236			  task_pid_nr(qp->res.task));
    237
    238	return match;
    239}
    240
    241static int __rdma_counter_unbind_qp(struct ib_qp *qp)
    242{
    243	struct rdma_counter *counter = qp->counter;
    244	int ret;
    245
    246	if (!qp->device->ops.counter_unbind_qp)
    247		return -EOPNOTSUPP;
    248
    249	mutex_lock(&counter->lock);
    250	ret = qp->device->ops.counter_unbind_qp(qp);
    251	mutex_unlock(&counter->lock);
    252
    253	return ret;
    254}
    255
    256static void counter_history_stat_update(struct rdma_counter *counter)
    257{
    258	struct ib_device *dev = counter->device;
    259	struct rdma_port_counter *port_counter;
    260	int i;
    261
    262	port_counter = &dev->port_data[counter->port].port_counter;
    263	if (!port_counter->hstats)
    264		return;
    265
    266	rdma_counter_query_stats(counter);
    267
    268	for (i = 0; i < counter->stats->num_counters; i++)
    269		port_counter->hstats->value[i] += counter->stats->value[i];
    270}
    271
    272/*
    273 * rdma_get_counter_auto_mode - Find the counter that @qp should be bound
    274 *     with in auto mode
    275 *
    276 * Return: The counter (with ref-count increased) if found
    277 */
    278static struct rdma_counter *rdma_get_counter_auto_mode(struct ib_qp *qp,
    279						       u32 port)
    280{
    281	struct rdma_port_counter *port_counter;
    282	struct rdma_counter *counter = NULL;
    283	struct ib_device *dev = qp->device;
    284	struct rdma_restrack_entry *res;
    285	struct rdma_restrack_root *rt;
    286	unsigned long id = 0;
    287
    288	port_counter = &dev->port_data[port].port_counter;
    289	rt = &dev->res[RDMA_RESTRACK_COUNTER];
    290	xa_lock(&rt->xa);
    291	xa_for_each(&rt->xa, id, res) {
    292		counter = container_of(res, struct rdma_counter, res);
    293		if ((counter->device != qp->device) || (counter->port != port))
    294			goto next;
    295
    296		if (auto_mode_match(qp, counter, port_counter->mode.mask))
    297			break;
    298next:
    299		counter = NULL;
    300	}
    301
    302	if (counter && !kref_get_unless_zero(&counter->kref))
    303		counter = NULL;
    304
    305	xa_unlock(&rt->xa);
    306	return counter;
    307}
    308
    309static void counter_release(struct kref *kref)
    310{
    311	struct rdma_counter *counter;
    312
    313	counter = container_of(kref, struct rdma_counter, kref);
    314	counter_history_stat_update(counter);
    315	counter->device->ops.counter_dealloc(counter);
    316	rdma_counter_free(counter);
    317}
    318
    319/*
    320 * rdma_counter_bind_qp_auto - Check and bind the QP to a counter base on
    321 *   the auto-mode rule
    322 */
    323int rdma_counter_bind_qp_auto(struct ib_qp *qp, u32 port)
    324{
    325	struct rdma_port_counter *port_counter;
    326	struct ib_device *dev = qp->device;
    327	struct rdma_counter *counter;
    328	int ret;
    329
    330	if (!rdma_restrack_is_tracked(&qp->res) || rdma_is_kernel_res(&qp->res))
    331		return 0;
    332
    333	if (!rdma_is_port_valid(dev, port))
    334		return -EINVAL;
    335
    336	port_counter = &dev->port_data[port].port_counter;
    337	if (port_counter->mode.mode != RDMA_COUNTER_MODE_AUTO)
    338		return 0;
    339
    340	counter = rdma_get_counter_auto_mode(qp, port);
    341	if (counter) {
    342		ret = __rdma_counter_bind_qp(counter, qp);
    343		if (ret) {
    344			kref_put(&counter->kref, counter_release);
    345			return ret;
    346		}
    347	} else {
    348		counter = alloc_and_bind(dev, port, qp, RDMA_COUNTER_MODE_AUTO);
    349		if (!counter)
    350			return -ENOMEM;
    351	}
    352
    353	return 0;
    354}
    355
    356/*
    357 * rdma_counter_unbind_qp - Unbind a qp from a counter
    358 * @force:
    359 *   true - Decrease the counter ref-count anyway (e.g., qp destroy)
    360 */
    361int rdma_counter_unbind_qp(struct ib_qp *qp, bool force)
    362{
    363	struct rdma_counter *counter = qp->counter;
    364	int ret;
    365
    366	if (!counter)
    367		return -EINVAL;
    368
    369	ret = __rdma_counter_unbind_qp(qp);
    370	if (ret && !force)
    371		return ret;
    372
    373	kref_put(&counter->kref, counter_release);
    374	return 0;
    375}
    376
    377int rdma_counter_query_stats(struct rdma_counter *counter)
    378{
    379	struct ib_device *dev = counter->device;
    380	int ret;
    381
    382	if (!dev->ops.counter_update_stats)
    383		return -EINVAL;
    384
    385	mutex_lock(&counter->lock);
    386	ret = dev->ops.counter_update_stats(counter);
    387	mutex_unlock(&counter->lock);
    388
    389	return ret;
    390}
    391
    392static u64 get_running_counters_hwstat_sum(struct ib_device *dev,
    393					   u32 port, u32 index)
    394{
    395	struct rdma_restrack_entry *res;
    396	struct rdma_restrack_root *rt;
    397	struct rdma_counter *counter;
    398	unsigned long id = 0;
    399	u64 sum = 0;
    400
    401	rt = &dev->res[RDMA_RESTRACK_COUNTER];
    402	xa_lock(&rt->xa);
    403	xa_for_each(&rt->xa, id, res) {
    404		if (!rdma_restrack_get(res))
    405			continue;
    406
    407		xa_unlock(&rt->xa);
    408
    409		counter = container_of(res, struct rdma_counter, res);
    410		if ((counter->device != dev) || (counter->port != port) ||
    411		    rdma_counter_query_stats(counter))
    412			goto next;
    413
    414		sum += counter->stats->value[index];
    415
    416next:
    417		xa_lock(&rt->xa);
    418		rdma_restrack_put(res);
    419	}
    420
    421	xa_unlock(&rt->xa);
    422	return sum;
    423}
    424
    425/*
    426 * rdma_counter_get_hwstat_value() - Get the sum value of all counters on a
    427 *   specific port, including the running ones and history data
    428 */
    429u64 rdma_counter_get_hwstat_value(struct ib_device *dev, u32 port, u32 index)
    430{
    431	struct rdma_port_counter *port_counter;
    432	u64 sum;
    433
    434	port_counter = &dev->port_data[port].port_counter;
    435	if (!port_counter->hstats)
    436		return 0;
    437
    438	sum = get_running_counters_hwstat_sum(dev, port, index);
    439	sum += port_counter->hstats->value[index];
    440
    441	return sum;
    442}
    443
    444static struct ib_qp *rdma_counter_get_qp(struct ib_device *dev, u32 qp_num)
    445{
    446	struct rdma_restrack_entry *res = NULL;
    447	struct ib_qp *qp = NULL;
    448
    449	res = rdma_restrack_get_byid(dev, RDMA_RESTRACK_QP, qp_num);
    450	if (IS_ERR(res))
    451		return NULL;
    452
    453	qp = container_of(res, struct ib_qp, res);
    454	if (qp->qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
    455		goto err;
    456
    457	return qp;
    458
    459err:
    460	rdma_restrack_put(res);
    461	return NULL;
    462}
    463
    464static struct rdma_counter *rdma_get_counter_by_id(struct ib_device *dev,
    465						   u32 counter_id)
    466{
    467	struct rdma_restrack_entry *res;
    468	struct rdma_counter *counter;
    469
    470	res = rdma_restrack_get_byid(dev, RDMA_RESTRACK_COUNTER, counter_id);
    471	if (IS_ERR(res))
    472		return NULL;
    473
    474	counter = container_of(res, struct rdma_counter, res);
    475	kref_get(&counter->kref);
    476	rdma_restrack_put(res);
    477
    478	return counter;
    479}
    480
    481/*
    482 * rdma_counter_bind_qpn() - Bind QP @qp_num to counter @counter_id
    483 */
    484int rdma_counter_bind_qpn(struct ib_device *dev, u32 port,
    485			  u32 qp_num, u32 counter_id)
    486{
    487	struct rdma_port_counter *port_counter;
    488	struct rdma_counter *counter;
    489	struct ib_qp *qp;
    490	int ret;
    491
    492	port_counter = &dev->port_data[port].port_counter;
    493	if (port_counter->mode.mode == RDMA_COUNTER_MODE_AUTO)
    494		return -EINVAL;
    495
    496	qp = rdma_counter_get_qp(dev, qp_num);
    497	if (!qp)
    498		return -ENOENT;
    499
    500	counter = rdma_get_counter_by_id(dev, counter_id);
    501	if (!counter) {
    502		ret = -ENOENT;
    503		goto err;
    504	}
    505
    506	if (rdma_is_kernel_res(&counter->res) != rdma_is_kernel_res(&qp->res)) {
    507		ret = -EINVAL;
    508		goto err_task;
    509	}
    510
    511	if ((counter->device != qp->device) || (counter->port != qp->port)) {
    512		ret = -EINVAL;
    513		goto err_task;
    514	}
    515
    516	ret = __rdma_counter_bind_qp(counter, qp);
    517	if (ret)
    518		goto err_task;
    519
    520	rdma_restrack_put(&qp->res);
    521	return 0;
    522
    523err_task:
    524	kref_put(&counter->kref, counter_release);
    525err:
    526	rdma_restrack_put(&qp->res);
    527	return ret;
    528}
    529
    530/*
    531 * rdma_counter_bind_qpn_alloc() - Alloc a counter and bind QP @qp_num to it
    532 *   The id of new counter is returned in @counter_id
    533 */
    534int rdma_counter_bind_qpn_alloc(struct ib_device *dev, u32 port,
    535				u32 qp_num, u32 *counter_id)
    536{
    537	struct rdma_port_counter *port_counter;
    538	struct rdma_counter *counter;
    539	struct ib_qp *qp;
    540	int ret;
    541
    542	if (!rdma_is_port_valid(dev, port))
    543		return -EINVAL;
    544
    545	port_counter = &dev->port_data[port].port_counter;
    546	if (!port_counter->hstats)
    547		return -EOPNOTSUPP;
    548
    549	if (port_counter->mode.mode == RDMA_COUNTER_MODE_AUTO)
    550		return -EINVAL;
    551
    552	qp = rdma_counter_get_qp(dev, qp_num);
    553	if (!qp)
    554		return -ENOENT;
    555
    556	if (rdma_is_port_valid(dev, qp->port) && (qp->port != port)) {
    557		ret = -EINVAL;
    558		goto err;
    559	}
    560
    561	counter = alloc_and_bind(dev, port, qp, RDMA_COUNTER_MODE_MANUAL);
    562	if (!counter) {
    563		ret = -ENOMEM;
    564		goto err;
    565	}
    566
    567	if (counter_id)
    568		*counter_id = counter->id;
    569
    570	rdma_restrack_put(&qp->res);
    571	return 0;
    572
    573err:
    574	rdma_restrack_put(&qp->res);
    575	return ret;
    576}
    577
    578/*
    579 * rdma_counter_unbind_qpn() - Unbind QP @qp_num from a counter
    580 */
    581int rdma_counter_unbind_qpn(struct ib_device *dev, u32 port,
    582			    u32 qp_num, u32 counter_id)
    583{
    584	struct rdma_port_counter *port_counter;
    585	struct ib_qp *qp;
    586	int ret;
    587
    588	if (!rdma_is_port_valid(dev, port))
    589		return -EINVAL;
    590
    591	qp = rdma_counter_get_qp(dev, qp_num);
    592	if (!qp)
    593		return -ENOENT;
    594
    595	if (rdma_is_port_valid(dev, qp->port) && (qp->port != port)) {
    596		ret = -EINVAL;
    597		goto out;
    598	}
    599
    600	port_counter = &dev->port_data[port].port_counter;
    601	if (!qp->counter || qp->counter->id != counter_id ||
    602	    port_counter->mode.mode != RDMA_COUNTER_MODE_MANUAL) {
    603		ret = -EINVAL;
    604		goto out;
    605	}
    606
    607	ret = rdma_counter_unbind_qp(qp, false);
    608
    609out:
    610	rdma_restrack_put(&qp->res);
    611	return ret;
    612}
    613
    614int rdma_counter_get_mode(struct ib_device *dev, u32 port,
    615			  enum rdma_nl_counter_mode *mode,
    616			  enum rdma_nl_counter_mask *mask)
    617{
    618	struct rdma_port_counter *port_counter;
    619
    620	port_counter = &dev->port_data[port].port_counter;
    621	*mode = port_counter->mode.mode;
    622	*mask = port_counter->mode.mask;
    623
    624	return 0;
    625}
    626
    627void rdma_counter_init(struct ib_device *dev)
    628{
    629	struct rdma_port_counter *port_counter;
    630	u32 port, i;
    631
    632	if (!dev->port_data)
    633		return;
    634
    635	rdma_for_each_port(dev, port) {
    636		port_counter = &dev->port_data[port].port_counter;
    637		port_counter->mode.mode = RDMA_COUNTER_MODE_NONE;
    638		mutex_init(&port_counter->lock);
    639
    640		if (!dev->ops.alloc_hw_port_stats)
    641			continue;
    642
    643		port_counter->hstats = dev->ops.alloc_hw_port_stats(dev, port);
    644		if (!port_counter->hstats)
    645			goto fail;
    646	}
    647
    648	return;
    649
    650fail:
    651	for (i = port; i >= rdma_start_port(dev); i--) {
    652		port_counter = &dev->port_data[port].port_counter;
    653		rdma_free_hw_stats_struct(port_counter->hstats);
    654		port_counter->hstats = NULL;
    655		mutex_destroy(&port_counter->lock);
    656	}
    657}
    658
    659void rdma_counter_release(struct ib_device *dev)
    660{
    661	struct rdma_port_counter *port_counter;
    662	u32 port;
    663
    664	rdma_for_each_port(dev, port) {
    665		port_counter = &dev->port_data[port].port_counter;
    666		rdma_free_hw_stats_struct(port_counter->hstats);
    667		mutex_destroy(&port_counter->lock);
    668	}
    669}