linux/drivers/net/mlx4/intf.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
   3 * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
   4 *
   5 * This software is available to you under a choice of one of two
   6 * licenses.  You may choose to be licensed under the terms of the GNU
   7 * General Public License (GPL) Version 2, available from the file
   8 * COPYING in the main directory of this source tree, or the
   9 * OpenIB.org BSD license below:
  10 *
  11 *     Redistribution and use in source and binary forms, with or
  12 *     without modification, are permitted provided that the following
  13 *     conditions are met:
  14 *
  15 *      - Redistributions of source code must retain the above
  16 *        copyright notice, this list of conditions and the following
  17 *        disclaimer.
  18 *
  19 *      - Redistributions in binary form must reproduce the above
  20 *        copyright notice, this list of conditions and the following
  21 *        disclaimer in the documentation and/or other materials
  22 *        provided with the distribution.
  23 *
  24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  31 * SOFTWARE.
  32 */
  33
  34#include <linux/slab.h>
  35
  36#include "mlx4.h"
  37
  38struct mlx4_device_context {
  39        struct list_head        list;
  40        struct mlx4_interface  *intf;
  41        void                   *context;
  42};
  43
  44static LIST_HEAD(intf_list);
  45static LIST_HEAD(dev_list);
  46static DEFINE_MUTEX(intf_mutex);
  47
  48static void mlx4_add_device(struct mlx4_interface *intf, struct mlx4_priv *priv)
  49{
  50        struct mlx4_device_context *dev_ctx;
  51
  52        dev_ctx = kmalloc(sizeof *dev_ctx, GFP_KERNEL);
  53        if (!dev_ctx)
  54                return;
  55
  56        dev_ctx->intf    = intf;
  57        dev_ctx->context = intf->add(&priv->dev);
  58
  59        if (dev_ctx->context) {
  60                spin_lock_irq(&priv->ctx_lock);
  61                list_add_tail(&dev_ctx->list, &priv->ctx_list);
  62                spin_unlock_irq(&priv->ctx_lock);
  63        } else
  64                kfree(dev_ctx);
  65}
  66
  67static void mlx4_remove_device(struct mlx4_interface *intf, struct mlx4_priv *priv)
  68{
  69        struct mlx4_device_context *dev_ctx;
  70
  71        list_for_each_entry(dev_ctx, &priv->ctx_list, list)
  72                if (dev_ctx->intf == intf) {
  73                        spin_lock_irq(&priv->ctx_lock);
  74                        list_del(&dev_ctx->list);
  75                        spin_unlock_irq(&priv->ctx_lock);
  76
  77                        intf->remove(&priv->dev, dev_ctx->context);
  78                        kfree(dev_ctx);
  79                        return;
  80                }
  81}
  82
  83int mlx4_register_interface(struct mlx4_interface *intf)
  84{
  85        struct mlx4_priv *priv;
  86
  87        if (!intf->add || !intf->remove)
  88                return -EINVAL;
  89
  90        mutex_lock(&intf_mutex);
  91
  92        list_add_tail(&intf->list, &intf_list);
  93        list_for_each_entry(priv, &dev_list, dev_list)
  94                mlx4_add_device(intf, priv);
  95
  96        mutex_unlock(&intf_mutex);
  97
  98        return 0;
  99}
 100EXPORT_SYMBOL_GPL(mlx4_register_interface);
 101
 102void mlx4_unregister_interface(struct mlx4_interface *intf)
 103{
 104        struct mlx4_priv *priv;
 105
 106        mutex_lock(&intf_mutex);
 107
 108        list_for_each_entry(priv, &dev_list, dev_list)
 109                mlx4_remove_device(intf, priv);
 110
 111        list_del(&intf->list);
 112
 113        mutex_unlock(&intf_mutex);
 114}
 115EXPORT_SYMBOL_GPL(mlx4_unregister_interface);
 116
 117void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, int port)
 118{
 119        struct mlx4_priv *priv = mlx4_priv(dev);
 120        struct mlx4_device_context *dev_ctx;
 121        unsigned long flags;
 122
 123        spin_lock_irqsave(&priv->ctx_lock, flags);
 124
 125        list_for_each_entry(dev_ctx, &priv->ctx_list, list)
 126                if (dev_ctx->intf->event)
 127                        dev_ctx->intf->event(dev, dev_ctx->context, type, port);
 128
 129        spin_unlock_irqrestore(&priv->ctx_lock, flags);
 130}
 131
 132int mlx4_register_device(struct mlx4_dev *dev)
 133{
 134        struct mlx4_priv *priv = mlx4_priv(dev);
 135        struct mlx4_interface *intf;
 136
 137        mutex_lock(&intf_mutex);
 138
 139        list_add_tail(&priv->dev_list, &dev_list);
 140        list_for_each_entry(intf, &intf_list, list)
 141                mlx4_add_device(intf, priv);
 142
 143        mutex_unlock(&intf_mutex);
 144        mlx4_start_catas_poll(dev);
 145
 146        return 0;
 147}
 148
 149void mlx4_unregister_device(struct mlx4_dev *dev)
 150{
 151        struct mlx4_priv *priv = mlx4_priv(dev);
 152        struct mlx4_interface *intf;
 153
 154        mlx4_stop_catas_poll(dev);
 155        mutex_lock(&intf_mutex);
 156
 157        list_for_each_entry(intf, &intf_list, list)
 158                mlx4_remove_device(intf, priv);
 159
 160        list_del(&priv->dev_list);
 161
 162        mutex_unlock(&intf_mutex);
 163}
 164
 165void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port)
 166{
 167        struct mlx4_priv *priv = mlx4_priv(dev);
 168        struct mlx4_device_context *dev_ctx;
 169        unsigned long flags;
 170        void *result = NULL;
 171
 172        spin_lock_irqsave(&priv->ctx_lock, flags);
 173
 174        list_for_each_entry(dev_ctx, &priv->ctx_list, list)
 175                if (dev_ctx->intf->protocol == proto && dev_ctx->intf->get_dev) {
 176                        result = dev_ctx->intf->get_dev(dev, dev_ctx->context, port);
 177                        break;
 178                }
 179
 180        spin_unlock_irqrestore(&priv->ctx_lock, flags);
 181
 182        return result;
 183}
 184EXPORT_SYMBOL_GPL(mlx4_get_protocol_dev);
 185