1219820Sjeff/*
2219820Sjeff * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
3272027Shselasky * Copyright (c) 2007, 2008, 2014 Mellanox Technologies. All rights reserved.
4219820Sjeff *
5219820Sjeff * This software is available to you under a choice of one of two
6219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
7219820Sjeff * General Public License (GPL) Version 2, available from the file
8219820Sjeff * COPYING in the main directory of this source tree, or the
9219820Sjeff * OpenIB.org BSD license below:
10219820Sjeff *
11219820Sjeff *     Redistribution and use in source and binary forms, with or
12219820Sjeff *     without modification, are permitted provided that the following
13219820Sjeff *     conditions are met:
14219820Sjeff *
15219820Sjeff *      - Redistributions of source code must retain the above
16219820Sjeff *        copyright notice, this list of conditions and the following
17219820Sjeff *        disclaimer.
18219820Sjeff *
19219820Sjeff *      - Redistributions in binary form must reproduce the above
20219820Sjeff *        copyright notice, this list of conditions and the following
21219820Sjeff *        disclaimer in the documentation and/or other materials
22219820Sjeff *        provided with the distribution.
23219820Sjeff *
24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31219820Sjeff * SOFTWARE.
32219820Sjeff */
33219820Sjeff
34255932Salfred#include <linux/slab.h>
35272027Shselasky#include <linux/module.h>
36255932Salfred
37219820Sjeff#include "mlx4.h"
38219820Sjeff
39219820Sjeffstruct mlx4_device_context {
40219820Sjeff	struct list_head	list;
41219820Sjeff	struct mlx4_interface  *intf;
42219820Sjeff	void		       *context;
43219820Sjeff};
44219820Sjeff
45219820Sjeffstatic LIST_HEAD(intf_list);
46219820Sjeffstatic LIST_HEAD(dev_list);
47219820Sjeffstatic DEFINE_MUTEX(intf_mutex);
48219820Sjeff
49219820Sjeffstatic void mlx4_add_device(struct mlx4_interface *intf, struct mlx4_priv *priv)
50219820Sjeff{
51219820Sjeff	struct mlx4_device_context *dev_ctx;
52219820Sjeff
53219820Sjeff	dev_ctx = kmalloc(sizeof *dev_ctx, GFP_KERNEL);
54219820Sjeff	if (!dev_ctx)
55219820Sjeff		return;
56219820Sjeff
57219820Sjeff	dev_ctx->intf    = intf;
58219820Sjeff	dev_ctx->context = intf->add(&priv->dev);
59219820Sjeff
60219820Sjeff	if (dev_ctx->context) {
61219820Sjeff		spin_lock_irq(&priv->ctx_lock);
62219820Sjeff		list_add_tail(&dev_ctx->list, &priv->ctx_list);
63219820Sjeff		spin_unlock_irq(&priv->ctx_lock);
64219820Sjeff	} else
65219820Sjeff		kfree(dev_ctx);
66219820Sjeff}
67219820Sjeff
68219820Sjeffstatic void mlx4_remove_device(struct mlx4_interface *intf, struct mlx4_priv *priv)
69219820Sjeff{
70219820Sjeff	struct mlx4_device_context *dev_ctx;
71219820Sjeff
72219820Sjeff	list_for_each_entry(dev_ctx, &priv->ctx_list, list)
73219820Sjeff		if (dev_ctx->intf == intf) {
74219820Sjeff			spin_lock_irq(&priv->ctx_lock);
75219820Sjeff			list_del(&dev_ctx->list);
76219820Sjeff			spin_unlock_irq(&priv->ctx_lock);
77219820Sjeff
78219820Sjeff			intf->remove(&priv->dev, dev_ctx->context);
79219820Sjeff			kfree(dev_ctx);
80219820Sjeff			return;
81219820Sjeff		}
82219820Sjeff}
83219820Sjeff
84219820Sjeffint mlx4_register_interface(struct mlx4_interface *intf)
85219820Sjeff{
86219820Sjeff	struct mlx4_priv *priv;
87219820Sjeff
88219820Sjeff	if (!intf->add || !intf->remove)
89219820Sjeff		return -EINVAL;
90219820Sjeff
91219820Sjeff	mutex_lock(&intf_mutex);
92219820Sjeff
93219820Sjeff	list_add_tail(&intf->list, &intf_list);
94219820Sjeff	list_for_each_entry(priv, &dev_list, dev_list)
95219820Sjeff		mlx4_add_device(intf, priv);
96219820Sjeff
97219820Sjeff	mutex_unlock(&intf_mutex);
98219820Sjeff
99219820Sjeff	return 0;
100219820Sjeff}
101219820SjeffEXPORT_SYMBOL_GPL(mlx4_register_interface);
102219820Sjeff
103219820Sjeffvoid mlx4_unregister_interface(struct mlx4_interface *intf)
104219820Sjeff{
105219820Sjeff	struct mlx4_priv *priv;
106219820Sjeff
107219820Sjeff	mutex_lock(&intf_mutex);
108219820Sjeff
109219820Sjeff	list_for_each_entry(priv, &dev_list, dev_list)
110219820Sjeff		mlx4_remove_device(intf, priv);
111219820Sjeff
112219820Sjeff	list_del(&intf->list);
113219820Sjeff
114219820Sjeff	mutex_unlock(&intf_mutex);
115219820Sjeff}
116219820SjeffEXPORT_SYMBOL_GPL(mlx4_unregister_interface);
117219820Sjeff
118255932Salfredvoid mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type,
119255932Salfred			 unsigned long param)
120219820Sjeff{
121219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
122219820Sjeff	struct mlx4_device_context *dev_ctx;
123219820Sjeff	unsigned long flags;
124219820Sjeff
125219820Sjeff	spin_lock_irqsave(&priv->ctx_lock, flags);
126219820Sjeff
127219820Sjeff	list_for_each_entry(dev_ctx, &priv->ctx_list, list)
128219820Sjeff		if (dev_ctx->intf->event)
129255932Salfred			dev_ctx->intf->event(dev, dev_ctx->context, type, param);
130219820Sjeff
131219820Sjeff	spin_unlock_irqrestore(&priv->ctx_lock, flags);
132219820Sjeff}
133219820Sjeff
134219820Sjeffint mlx4_register_device(struct mlx4_dev *dev)
135219820Sjeff{
136219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
137219820Sjeff	struct mlx4_interface *intf;
138219820Sjeff
139219820Sjeff	mutex_lock(&intf_mutex);
140219820Sjeff
141219820Sjeff	list_add_tail(&priv->dev_list, &dev_list);
142219820Sjeff	list_for_each_entry(intf, &intf_list, list)
143219820Sjeff		mlx4_add_device(intf, priv);
144219820Sjeff
145219820Sjeff	mutex_unlock(&intf_mutex);
146255932Salfred	if (!mlx4_is_slave(dev))
147255932Salfred		mlx4_start_catas_poll(dev);
148219820Sjeff
149219820Sjeff	return 0;
150219820Sjeff}
151219820Sjeff
152219820Sjeffvoid mlx4_unregister_device(struct mlx4_dev *dev)
153219820Sjeff{
154219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
155219820Sjeff	struct mlx4_interface *intf;
156219820Sjeff
157255932Salfred	if (!mlx4_is_slave(dev))
158255932Salfred		mlx4_stop_catas_poll(dev);
159219820Sjeff	mutex_lock(&intf_mutex);
160219820Sjeff
161219820Sjeff	list_for_each_entry(intf, &intf_list, list)
162219820Sjeff		mlx4_remove_device(intf, priv);
163219820Sjeff
164272027Shselasky	list_del_init(&priv->dev_list);
165219820Sjeff
166219820Sjeff	mutex_unlock(&intf_mutex);
167219820Sjeff}
168219820Sjeff
169255932Salfredvoid *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port)
170219820Sjeff{
171219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
172219820Sjeff	struct mlx4_device_context *dev_ctx;
173219820Sjeff	unsigned long flags;
174219820Sjeff	void *result = NULL;
175219820Sjeff
176219820Sjeff	spin_lock_irqsave(&priv->ctx_lock, flags);
177219820Sjeff
178219820Sjeff	list_for_each_entry(dev_ctx, &priv->ctx_list, list)
179255932Salfred		if (dev_ctx->intf->protocol == proto && dev_ctx->intf->get_dev) {
180255932Salfred			result = dev_ctx->intf->get_dev(dev, dev_ctx->context, port);
181219820Sjeff			break;
182255932Salfred		}
183219820Sjeff
184219820Sjeff	spin_unlock_irqrestore(&priv->ctx_lock, flags);
185219820Sjeff
186219820Sjeff	return result;
187219820Sjeff}
188255932SalfredEXPORT_SYMBOL_GPL(mlx4_get_protocol_dev);
189