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 <linux/mlx5/device.h> 6 #include "mlx5_core.h" 7 #include "dev.h" 8 #include "sf/vhca_event.h" 9 #include "sf/sf.h" 10 #include "sf/mlx5_ifc_vhca_event.h" 11 #include "ecpf.h" 12 #define CREATE_TRACE_POINTS 13 #include "diag/dev_tracepoint.h" 14 15 struct mlx5_sf_dev_table { 16 struct xarray devices; 17 unsigned int max_sfs; 18 phys_addr_t base_address; 19 u64 sf_bar_length; 20 struct notifier_block nb; 21 struct mlx5_core_dev *dev; 22 }; 23 24 static bool mlx5_sf_dev_supported(const struct mlx5_core_dev *dev) 25 { 26 return MLX5_CAP_GEN(dev, sf) && mlx5_vhca_event_supported(dev); 27 } 28 29 bool mlx5_sf_dev_allocated(const struct mlx5_core_dev *dev) 30 { 31 struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table; 32 33 return table && !xa_empty(&table->devices); 34 } 35 36 static ssize_t sfnum_show(struct device *dev, struct device_attribute *attr, char *buf) 37 { 38 struct auxiliary_device *adev = container_of(dev, struct auxiliary_device, dev); 39 struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); 40 41 return sysfs_emit(buf, "%u\n", sf_dev->sfnum); 42 } 43 static DEVICE_ATTR_RO(sfnum); 44 45 static struct attribute *sf_device_attrs[] = { 46 &dev_attr_sfnum.attr, 47 NULL, 48 }; 49 50 static const struct attribute_group sf_attr_group = { 51 .attrs = sf_device_attrs, 52 }; 53 54 static const struct attribute_group *sf_attr_groups[2] = { 55 &sf_attr_group, 56 NULL 57 }; 58 59 static void mlx5_sf_dev_release(struct device *device) 60 { 61 struct auxiliary_device *adev = container_of(device, struct auxiliary_device, dev); 62 struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev); 63 64 mlx5_adev_idx_free(adev->id); 65 kfree(sf_dev); 66 } 67 68 static void mlx5_sf_dev_remove(struct mlx5_core_dev *dev, struct mlx5_sf_dev *sf_dev) 69 { 70 int id; 71 72 id = sf_dev->adev.id; 73 trace_mlx5_sf_dev_del(dev, sf_dev, id); 74 75 auxiliary_device_delete(&sf_dev->adev); 76 auxiliary_device_uninit(&sf_dev->adev); 77 } 78 79 static void mlx5_sf_dev_add(struct mlx5_core_dev *dev, u16 sf_index, u16 fn_id, u32 sfnum) 80 { 81 struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table; 82 struct mlx5_sf_dev *sf_dev; 83 struct pci_dev *pdev; 84 int err; 85 int id; 86 87 id = mlx5_adev_idx_alloc(); 88 if (id < 0) { 89 err = id; 90 goto add_err; 91 } 92 93 sf_dev = kzalloc(sizeof(*sf_dev), GFP_KERNEL); 94 if (!sf_dev) { 95 mlx5_adev_idx_free(id); 96 err = -ENOMEM; 97 goto add_err; 98 } 99 pdev = dev->pdev; 100 sf_dev->adev.id = id; 101 sf_dev->adev.name = MLX5_SF_DEV_ID_NAME; 102 sf_dev->adev.dev.release = mlx5_sf_dev_release; 103 sf_dev->adev.dev.parent = &pdev->dev; 104 sf_dev->adev.dev.groups = sf_attr_groups; 105 sf_dev->sfnum = sfnum; 106 sf_dev->parent_mdev = dev; 107 sf_dev->fn_id = fn_id; 108 109 if (!table->max_sfs) { 110 mlx5_adev_idx_free(id); 111 kfree(sf_dev); 112 err = -EOPNOTSUPP; 113 goto add_err; 114 } 115 sf_dev->bar_base_addr = table->base_address + (sf_index * table->sf_bar_length); 116 117 trace_mlx5_sf_dev_add(dev, sf_dev, id); 118 119 err = auxiliary_device_init(&sf_dev->adev); 120 if (err) { 121 mlx5_adev_idx_free(id); 122 kfree(sf_dev); 123 goto add_err; 124 } 125 126 err = auxiliary_device_add(&sf_dev->adev); 127 if (err) { 128 put_device(&sf_dev->adev.dev); 129 goto add_err; 130 } 131 132 err = xa_insert(&table->devices, sf_index, sf_dev, GFP_KERNEL); 133 if (err) 134 goto xa_err; 135 return; 136 137 xa_err: 138 mlx5_sf_dev_remove(dev, sf_dev); 139 add_err: 140 mlx5_core_err(dev, "SF DEV: fail device add for index=%d sfnum=%d err=%d\n", 141 sf_index, sfnum, err); 142 } 143 144 static void mlx5_sf_dev_del(struct mlx5_core_dev *dev, struct mlx5_sf_dev *sf_dev, u16 sf_index) 145 { 146 struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table; 147 148 xa_erase(&table->devices, sf_index); 149 mlx5_sf_dev_remove(dev, sf_dev); 150 } 151 152 static int 153 mlx5_sf_dev_state_change_handler(struct notifier_block *nb, unsigned long event_code, void *data) 154 { 155 struct mlx5_sf_dev_table *table = container_of(nb, struct mlx5_sf_dev_table, nb); 156 const struct mlx5_vhca_state_event *event = data; 157 struct mlx5_sf_dev *sf_dev; 158 u16 max_functions; 159 u16 sf_index; 160 u16 base_id; 161 162 max_functions = mlx5_sf_max_functions(table->dev); 163 if (!max_functions) 164 return 0; 165 166 base_id = MLX5_CAP_GEN(table->dev, sf_base_id); 167 if (event->function_id < base_id || event->function_id >= (base_id + max_functions)) 168 return 0; 169 170 sf_index = event->function_id - base_id; 171 sf_dev = xa_load(&table->devices, sf_index); 172 switch (event->new_vhca_state) { 173 case MLX5_VHCA_STATE_INVALID: 174 case MLX5_VHCA_STATE_ALLOCATED: 175 if (sf_dev) 176 mlx5_sf_dev_del(table->dev, sf_dev, sf_index); 177 break; 178 case MLX5_VHCA_STATE_TEARDOWN_REQUEST: 179 if (sf_dev) 180 mlx5_sf_dev_del(table->dev, sf_dev, sf_index); 181 else 182 mlx5_core_err(table->dev, 183 "SF DEV: teardown state for invalid dev index=%d fn_id=0x%x\n", 184 sf_index, event->sw_function_id); 185 break; 186 case MLX5_VHCA_STATE_ACTIVE: 187 if (!sf_dev) 188 mlx5_sf_dev_add(table->dev, sf_index, event->function_id, 189 event->sw_function_id); 190 break; 191 default: 192 break; 193 } 194 return 0; 195 } 196 197 static int mlx5_sf_dev_vhca_arm_all(struct mlx5_sf_dev_table *table) 198 { 199 struct mlx5_core_dev *dev = table->dev; 200 u16 max_functions; 201 u16 function_id; 202 int err = 0; 203 int i; 204 205 max_functions = mlx5_sf_max_functions(dev); 206 function_id = MLX5_CAP_GEN(dev, sf_base_id); 207 /* Arm the vhca context as the vhca event notifier */ 208 for (i = 0; i < max_functions; i++) { 209 err = mlx5_vhca_event_arm(dev, function_id); 210 if (err) 211 return err; 212 213 function_id++; 214 } 215 return 0; 216 } 217 218 void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev) 219 { 220 struct mlx5_sf_dev_table *table; 221 unsigned int max_sfs; 222 int err; 223 224 if (!mlx5_sf_dev_supported(dev) || !mlx5_vhca_event_supported(dev)) 225 return; 226 227 table = kzalloc(sizeof(*table), GFP_KERNEL); 228 if (!table) { 229 err = -ENOMEM; 230 goto table_err; 231 } 232 233 table->nb.notifier_call = mlx5_sf_dev_state_change_handler; 234 table->dev = dev; 235 if (MLX5_CAP_GEN(dev, max_num_sf)) 236 max_sfs = MLX5_CAP_GEN(dev, max_num_sf); 237 else 238 max_sfs = 1 << MLX5_CAP_GEN(dev, log_max_sf); 239 table->sf_bar_length = 1 << (MLX5_CAP_GEN(dev, log_min_sf_size) + 12); 240 table->base_address = pci_resource_start(dev->pdev, 2); 241 table->max_sfs = max_sfs; 242 xa_init(&table->devices); 243 dev->priv.sf_dev_table = table; 244 245 err = mlx5_vhca_event_notifier_register(dev, &table->nb); 246 if (err) 247 goto vhca_err; 248 err = mlx5_sf_dev_vhca_arm_all(table); 249 if (err) 250 goto arm_err; 251 mlx5_core_dbg(dev, "SF DEV: max sf devices=%d\n", max_sfs); 252 return; 253 254 arm_err: 255 mlx5_vhca_event_notifier_unregister(dev, &table->nb); 256 vhca_err: 257 table->max_sfs = 0; 258 kfree(table); 259 dev->priv.sf_dev_table = NULL; 260 table_err: 261 mlx5_core_err(dev, "SF DEV table create err = %d\n", err); 262 } 263 264 static void mlx5_sf_dev_destroy_all(struct mlx5_sf_dev_table *table) 265 { 266 struct mlx5_sf_dev *sf_dev; 267 unsigned long index; 268 269 xa_for_each(&table->devices, index, sf_dev) { 270 xa_erase(&table->devices, index); 271 mlx5_sf_dev_remove(table->dev, sf_dev); 272 } 273 } 274 275 void mlx5_sf_dev_table_destroy(struct mlx5_core_dev *dev) 276 { 277 struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table; 278 279 if (!table) 280 return; 281 282 mlx5_vhca_event_notifier_unregister(dev, &table->nb); 283 284 /* Now that event handler is not running, it is safe to destroy 285 * the sf device without race. 286 */ 287 mlx5_sf_dev_destroy_all(table); 288 289 WARN_ON(!xa_empty(&table->devices)); 290 kfree(table); 291 dev->priv.sf_dev_table = NULL; 292 } 293