FILE
vhca_event.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/sf/vhca_event.c
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2/* Copyright (c) 2020 Mellanox Technologies Ltd */ 3 4#include <linux/mlx5/driver.h> 5#include "mlx5_ifc_vhca_event.h" 6#include "mlx5_core.h" 7#include "vhca_event.h" 8#include "ecpf.h" 9#define CREATE_TRACE_POINTS 10#include "diag/vhca_tracepoint.h" 11 12struct mlx5_vhca_event_work { 13 struct work_struct work; 14 struct mlx5_core_dev *dev; 15 struct mlx5_vhca_state_event event; 16}; 17 18struct mlx5_vhca_event_handler { 19 struct workqueue_struct *wq; 20}; 21 22struct mlx5_vhca_events { 23 struct mlx5_core_dev *dev; 24 struct mlx5_vhca_event_handler handler[MLX5_DEV_MAX_WQS]; 25}; 26 27int mlx5_cmd_query_vhca_state(struct mlx5_core_dev *dev, u16 function_id, u32 *out, u32 outlen) 28{ 29 u32 in[MLX5_ST_SZ_DW(query_vhca_state_in)] = {}; 30 31 MLX5_SET(query_vhca_state_in, in, opcode, MLX5_CMD_OP_QUERY_VHCA_STATE); 32 MLX5_SET(query_vhca_state_in, in, function_id, function_id); 33 MLX5_SET(query_vhca_state_in, in, embedded_cpu_function, 0); 34 35 return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen); 36} 37 38static int mlx5_cmd_modify_vhca_state(struct mlx5_core_dev *dev, u16 function_id, 39 u32 *in, u32 inlen) 40{ 41 u32 out[MLX5_ST_SZ_DW(modify_vhca_state_out)] = {}; 42 43 MLX5_SET(modify_vhca_state_in, in, opcode, MLX5_CMD_OP_MODIFY_VHCA_STATE); 44 MLX5_SET(modify_vhca_state_in, in, function_id, function_id); 45 MLX5_SET(modify_vhca_state_in, in, embedded_cpu_function, 0); 46 47 return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); 48} 49 50int mlx5_modify_vhca_sw_id(struct mlx5_core_dev *dev, u16 function_id, u32 sw_fn_id) 51{ 52 u32 out[MLX5_ST_SZ_DW(modify_vhca_state_out)] = {}; 53 u32 in[MLX5_ST_SZ_DW(modify_vhca_state_in)] = {}; 54 55 MLX5_SET(modify_vhca_state_in, in, opcode, MLX5_CMD_OP_MODIFY_VHCA_STATE); 56 MLX5_SET(modify_vhca_state_in, in, function_id, function_id); 57 MLX5_SET(modify_vhca_state_in, in, embedded_cpu_function, 0); 58 MLX5_SET(modify_vhca_state_in, in, vhca_state_field_select.sw_function_id, 1); 59 MLX5_SET(modify_vhca_state_in, in, vhca_state_context.sw_function_id, sw_fn_id); 60 61 return mlx5_cmd_exec_inout(dev, modify_vhca_state, in, out); 62} 63 64int mlx5_vhca_event_arm(struct mlx5_core_dev *dev, u16 function_id) 65{ 66 u32 in[MLX5_ST_SZ_DW(modify_vhca_state_in)] = {}; 67 68 MLX5_SET(modify_vhca_state_in, in, vhca_state_context.arm_change_event, 1); 69 MLX5_SET(modify_vhca_state_in, in, vhca_state_field_select.arm_change_event, 1); 70 71 return mlx5_cmd_modify_vhca_state(dev, function_id, in, sizeof(in)); 72} 73 74static void 75mlx5_vhca_event_notify(struct mlx5_core_dev *dev, struct mlx5_vhca_state_event *event) 76{ 77 u32 out[MLX5_ST_SZ_DW(query_vhca_state_out)] = {}; 78 int err; 79 80 err = mlx5_cmd_query_vhca_state(dev, event->function_id, out, sizeof(out)); 81 if (err) 82 return; 83 84 event->sw_function_id = MLX5_GET(query_vhca_state_out, out, 85 vhca_state_context.sw_function_id); 86 event->new_vhca_state = MLX5_GET(query_vhca_state_out, out, 87 vhca_state_context.vhca_state); 88 89 mlx5_vhca_event_arm(dev, event->function_id); 90 trace_mlx5_sf_vhca_event(dev, event); 91 92 blocking_notifier_call_chain(&dev->priv.vhca_state_n_head, 0, event); 93} 94 95static void mlx5_vhca_state_work_handler(struct work_struct *_work) 96{ 97 struct mlx5_vhca_event_work *work = container_of(_work, struct mlx5_vhca_event_work, work); 98 99 mlx5_vhca_event_notify(work->dev, &work->event); 100 kfree(work); 101} 102 103void mlx5_vhca_events_work_enqueue(struct mlx5_core_dev *dev, int idx, struct work_struct *work) 104{ 105 queue_work(dev->priv.vhca_events->handler[idx].wq, work); 106} 107 108static int 109mlx5_vhca_state_change_notifier(struct notifier_block *nb, unsigned long type, void *data) 110{ 111 struct mlx5_core_dev *dev = mlx5_nb_cof(nb, struct mlx5_core_dev, 112 priv.vhca_state_nb); 113 struct mlx5_vhca_event_work *work; 114 struct mlx5_eqe *eqe = data; 115 int wq_idx; 116 117 work = kzalloc(sizeof(*work), GFP_ATOMIC); 118 if (!work) 119 return NOTIFY_DONE; 120 INIT_WORK(&work->work, &mlx5_vhca_state_work_handler); 121 work->dev = dev; 122 work->event.function_id = be16_to_cpu(eqe->data.vhca_state.function_id); 123 wq_idx = work->event.function_id % MLX5_DEV_MAX_WQS; 124 mlx5_vhca_events_work_enqueue(dev, wq_idx, &work->work); 125 return NOTIFY_OK; 126} 127 128void mlx5_vhca_state_cap_handle(struct mlx5_core_dev *dev, void *set_hca_cap) 129{ 130 if (!mlx5_vhca_event_supported(dev)) 131 return; 132 133 MLX5_SET(cmd_hca_cap, set_hca_cap, vhca_state, 1); 134 MLX5_SET(cmd_hca_cap, set_hca_cap, event_on_vhca_state_allocated, 1); 135 MLX5_SET(cmd_hca_cap, set_hca_cap, event_on_vhca_state_active, 1); 136 MLX5_SET(cmd_hca_cap, set_hca_cap, event_on_vhca_state_in_use, 1); 137 MLX5_SET(cmd_hca_cap, set_hca_cap, event_on_vhca_state_teardown_request, 1); 138} 139 140void mlx5_vhca_state_notifier_init(struct mlx5_core_dev *dev) 141{ 142 BLOCKING_INIT_NOTIFIER_HEAD(&dev->priv.vhca_state_n_head); 143 MLX5_NB_INIT(&dev->priv.vhca_state_nb, mlx5_vhca_state_change_notifier, 144 VHCA_STATE_CHANGE); 145} 146 147int mlx5_vhca_event_init(struct mlx5_core_dev *dev) 148{ 149 char wq_name[MLX5_CMD_WQ_MAX_NAME]; 150 struct mlx5_vhca_events *events; 151 int err, i; 152 153 if (!mlx5_vhca_event_supported(dev)) 154 return 0; 155 156 events = kzalloc(sizeof(*events), GFP_KERNEL); 157 if (!events) 158 return -ENOMEM; 159 160 events->dev = dev; 161 for (i = 0; i < MLX5_DEV_MAX_WQS; i++) { 162 snprintf(wq_name, MLX5_CMD_WQ_MAX_NAME, "mlx5_vhca_event%d", i); 163 events->handler[i].wq = create_singlethread_workqueue(wq_name); 164 if (!events->handler[i].wq) { 165 err = -ENOMEM; 166 goto err_create_wq; 167 } 168 } 169 dev->priv.vhca_events = events; 170 171 return 0; 172 173err_create_wq: 174 for (--i; i >= 0; i--) 175 destroy_workqueue(events->handler[i].wq); 176 kfree(events); 177 return err; 178} 179 180void mlx5_vhca_event_work_queues_flush(struct mlx5_core_dev *dev) 181{ 182 struct mlx5_vhca_events *vhca_events; 183 int i; 184 185 if (!mlx5_vhca_event_supported(dev)) 186 return; 187 188 vhca_events = dev->priv.vhca_events; 189 for (i = 0; i < MLX5_DEV_MAX_WQS; i++) 190 flush_workqueue(vhca_events->handler[i].wq); 191} 192 193void mlx5_vhca_event_cleanup(struct mlx5_core_dev *dev) 194{ 195 struct mlx5_vhca_events *vhca_events; 196 int i; 197 198 if (!mlx5_vhca_event_supported(dev)) 199 return; 200 201 vhca_events = dev->priv.vhca_events; 202 for (i = 0; i < MLX5_DEV_MAX_WQS; i++) 203 destroy_workqueue(vhca_events->handler[i].wq); 204 kvfree(vhca_events); 205} 206 207void mlx5_vhca_event_start(struct mlx5_core_dev *dev) 208{ 209 if (!mlx5_vhca_event_supported(dev)) 210 return; 211 212 mlx5_eq_notifier_register(dev, &dev->priv.vhca_state_nb); 213} 214 215void mlx5_vhca_event_stop(struct mlx5_core_dev *dev) 216{ 217 if (!mlx5_vhca_event_supported(dev)) 218 return; 219 220 mlx5_eq_notifier_unregister(dev, &dev->priv.vhca_state_nb); 221 222 /* Flush workqueues of all pending events. */ 223 mlx5_vhca_event_work_queues_flush(dev); 224} 225 226int mlx5_vhca_event_notifier_register(struct mlx5_core_dev *dev, struct notifier_block *nb) 227{ 228 return blocking_notifier_chain_register(&dev->priv.vhca_state_n_head, 229 nb); 230} 231 232void mlx5_vhca_event_notifier_unregister(struct mlx5_core_dev *dev, struct notifier_block *nb) 233{ 234 blocking_notifier_chain_unregister(&dev->priv.vhca_state_n_head, nb); 235}
~/
Read-only file preview.