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

devcom.c (5284B)


      1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
      2/* Copyright (c) 2018 Mellanox Technologies */
      3
      4#include <linux/mlx5/vport.h>
      5#include "lib/devcom.h"
      6
      7static LIST_HEAD(devcom_list);
      8
      9#define devcom_for_each_component(priv, comp, iter) \
     10	for (iter = 0; \
     11	     comp = &(priv)->components[iter], iter < MLX5_DEVCOM_NUM_COMPONENTS; \
     12	     iter++)
     13
     14struct mlx5_devcom_component {
     15	struct {
     16		void *data;
     17	} device[MLX5_DEVCOM_PORTS_SUPPORTED];
     18
     19	mlx5_devcom_event_handler_t handler;
     20	struct rw_semaphore sem;
     21	bool paired;
     22};
     23
     24struct mlx5_devcom_list {
     25	struct list_head list;
     26
     27	struct mlx5_devcom_component components[MLX5_DEVCOM_NUM_COMPONENTS];
     28	struct mlx5_core_dev *devs[MLX5_DEVCOM_PORTS_SUPPORTED];
     29};
     30
     31struct mlx5_devcom {
     32	struct mlx5_devcom_list *priv;
     33	int idx;
     34};
     35
     36static struct mlx5_devcom_list *mlx5_devcom_list_alloc(void)
     37{
     38	struct mlx5_devcom_component *comp;
     39	struct mlx5_devcom_list *priv;
     40	int i;
     41
     42	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
     43	if (!priv)
     44		return NULL;
     45
     46	devcom_for_each_component(priv, comp, i)
     47		init_rwsem(&comp->sem);
     48
     49	return priv;
     50}
     51
     52static struct mlx5_devcom *mlx5_devcom_alloc(struct mlx5_devcom_list *priv,
     53					     u8 idx)
     54{
     55	struct mlx5_devcom *devcom;
     56
     57	devcom = kzalloc(sizeof(*devcom), GFP_KERNEL);
     58	if (!devcom)
     59		return NULL;
     60
     61	devcom->priv = priv;
     62	devcom->idx = idx;
     63	return devcom;
     64}
     65
     66/* Must be called with intf_mutex held */
     67struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev)
     68{
     69	struct mlx5_devcom_list *priv = NULL, *iter;
     70	struct mlx5_devcom *devcom = NULL;
     71	bool new_priv = false;
     72	u64 sguid0, sguid1;
     73	int idx, i;
     74
     75	if (!mlx5_core_is_pf(dev))
     76		return NULL;
     77	if (MLX5_CAP_GEN(dev, num_lag_ports) != MLX5_DEVCOM_PORTS_SUPPORTED)
     78		return NULL;
     79
     80	sguid0 = mlx5_query_nic_system_image_guid(dev);
     81	list_for_each_entry(iter, &devcom_list, list) {
     82		struct mlx5_core_dev *tmp_dev = NULL;
     83
     84		idx = -1;
     85		for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) {
     86			if (iter->devs[i])
     87				tmp_dev = iter->devs[i];
     88			else
     89				idx = i;
     90		}
     91
     92		if (idx == -1)
     93			continue;
     94
     95		sguid1 = mlx5_query_nic_system_image_guid(tmp_dev);
     96		if (sguid0 != sguid1)
     97			continue;
     98
     99		priv = iter;
    100		break;
    101	}
    102
    103	if (!priv) {
    104		priv = mlx5_devcom_list_alloc();
    105		if (!priv)
    106			return ERR_PTR(-ENOMEM);
    107
    108		idx = 0;
    109		new_priv = true;
    110	}
    111
    112	priv->devs[idx] = dev;
    113	devcom = mlx5_devcom_alloc(priv, idx);
    114	if (!devcom) {
    115		kfree(priv);
    116		return ERR_PTR(-ENOMEM);
    117	}
    118
    119	if (new_priv)
    120		list_add(&priv->list, &devcom_list);
    121
    122	return devcom;
    123}
    124
    125/* Must be called with intf_mutex held */
    126void mlx5_devcom_unregister_device(struct mlx5_devcom *devcom)
    127{
    128	struct mlx5_devcom_list *priv;
    129	int i;
    130
    131	if (IS_ERR_OR_NULL(devcom))
    132		return;
    133
    134	priv = devcom->priv;
    135	priv->devs[devcom->idx] = NULL;
    136
    137	kfree(devcom);
    138
    139	for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++)
    140		if (priv->devs[i])
    141			break;
    142
    143	if (i != MLX5_DEVCOM_PORTS_SUPPORTED)
    144		return;
    145
    146	list_del(&priv->list);
    147	kfree(priv);
    148}
    149
    150void mlx5_devcom_register_component(struct mlx5_devcom *devcom,
    151				    enum mlx5_devcom_components id,
    152				    mlx5_devcom_event_handler_t handler,
    153				    void *data)
    154{
    155	struct mlx5_devcom_component *comp;
    156
    157	if (IS_ERR_OR_NULL(devcom))
    158		return;
    159
    160	WARN_ON(!data);
    161
    162	comp = &devcom->priv->components[id];
    163	down_write(&comp->sem);
    164	comp->handler = handler;
    165	comp->device[devcom->idx].data = data;
    166	up_write(&comp->sem);
    167}
    168
    169void mlx5_devcom_unregister_component(struct mlx5_devcom *devcom,
    170				      enum mlx5_devcom_components id)
    171{
    172	struct mlx5_devcom_component *comp;
    173
    174	if (IS_ERR_OR_NULL(devcom))
    175		return;
    176
    177	comp = &devcom->priv->components[id];
    178	down_write(&comp->sem);
    179	comp->device[devcom->idx].data = NULL;
    180	up_write(&comp->sem);
    181}
    182
    183int mlx5_devcom_send_event(struct mlx5_devcom *devcom,
    184			   enum mlx5_devcom_components id,
    185			   int event,
    186			   void *event_data)
    187{
    188	struct mlx5_devcom_component *comp;
    189	int err = -ENODEV, i;
    190
    191	if (IS_ERR_OR_NULL(devcom))
    192		return err;
    193
    194	comp = &devcom->priv->components[id];
    195	down_write(&comp->sem);
    196	for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++)
    197		if (i != devcom->idx && comp->device[i].data) {
    198			err = comp->handler(event, comp->device[i].data,
    199					    event_data);
    200			break;
    201		}
    202
    203	up_write(&comp->sem);
    204	return err;
    205}
    206
    207void mlx5_devcom_set_paired(struct mlx5_devcom *devcom,
    208			    enum mlx5_devcom_components id,
    209			    bool paired)
    210{
    211	struct mlx5_devcom_component *comp;
    212
    213	comp = &devcom->priv->components[id];
    214	WARN_ON(!rwsem_is_locked(&comp->sem));
    215
    216	comp->paired = paired;
    217}
    218
    219bool mlx5_devcom_is_paired(struct mlx5_devcom *devcom,
    220			   enum mlx5_devcom_components id)
    221{
    222	if (IS_ERR_OR_NULL(devcom))
    223		return false;
    224
    225	return devcom->priv->components[id].paired;
    226}
    227
    228void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom,
    229				enum mlx5_devcom_components id)
    230{
    231	struct mlx5_devcom_component *comp;
    232	int i;
    233
    234	if (IS_ERR_OR_NULL(devcom))
    235		return NULL;
    236
    237	comp = &devcom->priv->components[id];
    238	down_read(&comp->sem);
    239	if (!comp->paired) {
    240		up_read(&comp->sem);
    241		return NULL;
    242	}
    243
    244	for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++)
    245		if (i != devcom->idx)
    246			break;
    247
    248	return comp->device[i].data;
    249}
    250
    251void mlx5_devcom_release_peer_data(struct mlx5_devcom *devcom,
    252				   enum mlx5_devcom_components id)
    253{
    254	struct mlx5_devcom_component *comp = &devcom->priv->components[id];
    255
    256	up_read(&comp->sem);
    257}