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