1 /* 2 * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33 #include <linux/mlx5/driver.h> 34 #include "mlx5_core.h" 35 36 static LIST_HEAD(intf_list); 37 static LIST_HEAD(mlx5_dev_list); 38 /* intf dev list mutex */ 39 static DEFINE_MUTEX(mlx5_intf_mutex); 40 41 struct mlx5_device_context { 42 struct list_head list; 43 struct mlx5_interface *intf; 44 void *context; 45 unsigned long state; 46 }; 47 48 enum { 49 MLX5_INTERFACE_ADDED, 50 MLX5_INTERFACE_ATTACHED, 51 }; 52 53 54 void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv) 55 { 56 struct mlx5_device_context *dev_ctx; 57 struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv); 58 59 if (!mlx5_lag_intf_add(intf, priv)) 60 return; 61 62 dev_ctx = kzalloc(sizeof(*dev_ctx), GFP_KERNEL); 63 if (!dev_ctx) 64 return; 65 66 dev_ctx->intf = intf; 67 68 dev_ctx->context = intf->add(dev); 69 if (dev_ctx->context) { 70 set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state); 71 if (intf->attach) 72 set_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state); 73 74 spin_lock_irq(&priv->ctx_lock); 75 list_add_tail(&dev_ctx->list, &priv->ctx_list); 76 spin_unlock_irq(&priv->ctx_lock); 77 } 78 79 if (!dev_ctx->context) 80 kfree(dev_ctx); 81 } 82 83 static struct mlx5_device_context *mlx5_get_device(struct mlx5_interface *intf, 84 struct mlx5_priv *priv) 85 { 86 struct mlx5_device_context *dev_ctx; 87 88 list_for_each_entry(dev_ctx, &priv->ctx_list, list) 89 if (dev_ctx->intf == intf) 90 return dev_ctx; 91 return NULL; 92 } 93 94 void mlx5_remove_device(struct mlx5_interface *intf, struct mlx5_priv *priv) 95 { 96 struct mlx5_device_context *dev_ctx; 97 struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv); 98 99 dev_ctx = mlx5_get_device(intf, priv); 100 if (!dev_ctx) 101 return; 102 103 spin_lock_irq(&priv->ctx_lock); 104 list_del(&dev_ctx->list); 105 spin_unlock_irq(&priv->ctx_lock); 106 107 if (test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state)) 108 intf->remove(dev, dev_ctx->context); 109 110 kfree(dev_ctx); 111 } 112 113 static void mlx5_attach_interface(struct mlx5_interface *intf, struct mlx5_priv *priv) 114 { 115 struct mlx5_device_context *dev_ctx; 116 struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv); 117 118 dev_ctx = mlx5_get_device(intf, priv); 119 if (!dev_ctx) 120 return; 121 122 if (intf->attach) { 123 if (test_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state)) 124 return; 125 if (intf->attach(dev, dev_ctx->context)) 126 return; 127 set_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state); 128 } else { 129 if (test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state)) 130 return; 131 dev_ctx->context = intf->add(dev); 132 if (!dev_ctx->context) 133 return; 134 set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state); 135 } 136 } 137 138 void mlx5_attach_device(struct mlx5_core_dev *dev) 139 { 140 struct mlx5_priv *priv = &dev->priv; 141 struct mlx5_interface *intf; 142 143 mutex_lock(&mlx5_intf_mutex); 144 list_for_each_entry(intf, &intf_list, list) 145 mlx5_attach_interface(intf, priv); 146 mutex_unlock(&mlx5_intf_mutex); 147 } 148 149 static void mlx5_detach_interface(struct mlx5_interface *intf, struct mlx5_priv *priv) 150 { 151 struct mlx5_device_context *dev_ctx; 152 struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv); 153 154 dev_ctx = mlx5_get_device(intf, priv); 155 if (!dev_ctx) 156 return; 157 158 if (intf->detach) { 159 if (!test_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state)) 160 return; 161 intf->detach(dev, dev_ctx->context); 162 clear_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state); 163 } else { 164 if (!test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state)) 165 return; 166 intf->remove(dev, dev_ctx->context); 167 clear_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state); 168 } 169 } 170 171 void mlx5_detach_device(struct mlx5_core_dev *dev) 172 { 173 struct mlx5_priv *priv = &dev->priv; 174 struct mlx5_interface *intf; 175 176 mutex_lock(&mlx5_intf_mutex); 177 list_for_each_entry(intf, &intf_list, list) 178 mlx5_detach_interface(intf, priv); 179 mutex_unlock(&mlx5_intf_mutex); 180 } 181 182 bool mlx5_device_registered(struct mlx5_core_dev *dev) 183 { 184 struct mlx5_priv *priv; 185 bool found = false; 186 187 mutex_lock(&mlx5_intf_mutex); 188 list_for_each_entry(priv, &mlx5_dev_list, dev_list) 189 if (priv == &dev->priv) 190 found = true; 191 mutex_unlock(&mlx5_intf_mutex); 192 193 return found; 194 } 195 196 int mlx5_register_device(struct mlx5_core_dev *dev) 197 { 198 struct mlx5_priv *priv = &dev->priv; 199 struct mlx5_interface *intf; 200 201 mutex_lock(&mlx5_intf_mutex); 202 list_add_tail(&priv->dev_list, &mlx5_dev_list); 203 list_for_each_entry(intf, &intf_list, list) 204 mlx5_add_device(intf, priv); 205 mutex_unlock(&mlx5_intf_mutex); 206 207 return 0; 208 } 209 210 void mlx5_unregister_device(struct mlx5_core_dev *dev) 211 { 212 struct mlx5_priv *priv = &dev->priv; 213 struct mlx5_interface *intf; 214 215 mutex_lock(&mlx5_intf_mutex); 216 list_for_each_entry(intf, &intf_list, list) 217 mlx5_remove_device(intf, priv); 218 list_del(&priv->dev_list); 219 mutex_unlock(&mlx5_intf_mutex); 220 } 221 222 int mlx5_register_interface(struct mlx5_interface *intf) 223 { 224 struct mlx5_priv *priv; 225 226 if (!intf->add || !intf->remove) 227 return -EINVAL; 228 229 mutex_lock(&mlx5_intf_mutex); 230 list_add_tail(&intf->list, &intf_list); 231 list_for_each_entry(priv, &mlx5_dev_list, dev_list) 232 mlx5_add_device(intf, priv); 233 mutex_unlock(&mlx5_intf_mutex); 234 235 return 0; 236 } 237 EXPORT_SYMBOL(mlx5_register_interface); 238 239 void mlx5_unregister_interface(struct mlx5_interface *intf) 240 { 241 struct mlx5_priv *priv; 242 243 mutex_lock(&mlx5_intf_mutex); 244 list_for_each_entry(priv, &mlx5_dev_list, dev_list) 245 mlx5_remove_device(intf, priv); 246 list_del(&intf->list); 247 mutex_unlock(&mlx5_intf_mutex); 248 } 249 EXPORT_SYMBOL(mlx5_unregister_interface); 250 251 void mlx5_reload_interface(struct mlx5_core_dev *mdev, int protocol) 252 { 253 mutex_lock(&mlx5_intf_mutex); 254 mlx5_remove_dev_by_protocol(mdev, protocol); 255 mlx5_add_dev_by_protocol(mdev, protocol); 256 mutex_unlock(&mlx5_intf_mutex); 257 } 258 259 /* Must be called with intf_mutex held */ 260 void mlx5_add_dev_by_protocol(struct mlx5_core_dev *dev, int protocol) 261 { 262 struct mlx5_interface *intf; 263 264 list_for_each_entry(intf, &intf_list, list) 265 if (intf->protocol == protocol) { 266 mlx5_add_device(intf, &dev->priv); 267 break; 268 } 269 } 270 271 /* Must be called with intf_mutex held */ 272 void mlx5_remove_dev_by_protocol(struct mlx5_core_dev *dev, int protocol) 273 { 274 struct mlx5_interface *intf; 275 276 list_for_each_entry(intf, &intf_list, list) 277 if (intf->protocol == protocol) { 278 mlx5_remove_device(intf, &dev->priv); 279 break; 280 } 281 } 282 283 static u32 mlx5_gen_pci_id(struct mlx5_core_dev *dev) 284 { 285 return (u32)((pci_domain_nr(dev->pdev->bus) << 16) | 286 (dev->pdev->bus->number << 8) | 287 PCI_SLOT(dev->pdev->devfn)); 288 } 289 290 /* Must be called with intf_mutex held */ 291 struct mlx5_core_dev *mlx5_get_next_phys_dev(struct mlx5_core_dev *dev) 292 { 293 u32 pci_id = mlx5_gen_pci_id(dev); 294 struct mlx5_core_dev *res = NULL; 295 struct mlx5_core_dev *tmp_dev; 296 struct mlx5_priv *priv; 297 298 list_for_each_entry(priv, &mlx5_dev_list, dev_list) { 299 tmp_dev = container_of(priv, struct mlx5_core_dev, priv); 300 if ((dev != tmp_dev) && (mlx5_gen_pci_id(tmp_dev) == pci_id)) { 301 res = tmp_dev; 302 break; 303 } 304 } 305 306 return res; 307 } 308 309 310 void mlx5_dev_list_lock(void) 311 { 312 mutex_lock(&mlx5_intf_mutex); 313 } 314 315 void mlx5_dev_list_unlock(void) 316 { 317 mutex_unlock(&mlx5_intf_mutex); 318 } 319 320 int mlx5_dev_list_trylock(void) 321 { 322 return mutex_trylock(&mlx5_intf_mutex); 323 } 324