/*
* Copyright (c) 2012 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <rdma/ib_mad.h>
#include <rdma/ib_smi.h>
#include <rdma/ib_cache.h>
#include <rdma/ib_sa.h>
#include <linux/mlx4/cmd.h>
#include <linux/rbtree.h>
#include <linux/delay.h>
#include "mlx4_ib.h"
#define MAX_VFS 80
#define MAX_PEND_REQS_PER_FUNC 4
#define MAD_TIMEOUT_MS 2000
#define mcg_warn(fmt, arg...) pr_warn("MCG WARNING: " fmt, ##arg)
#define mcg_error(fmt, arg...) pr_err(fmt, ##arg)
#define mcg_warn_group(group, format, arg...) \
pr_warn("%s-%d: %16s (port %d): WARNING: " format, __func__, __LINE__,\
(group)->name, group->demux->port, ## arg)
#define mcg_error_group(group, format, arg...) \
pr_err(" %16s: " format, (group)->name, ## arg)
static union ib_gid mgid0;
static struct workqueue_struct *clean_wq;
enum mcast_state {
MCAST_NOT_MEMBER = 0,
MCAST_MEMBER,
};
enum mcast_group_state {
MCAST_IDLE,
MCAST_JOIN_SENT,
MCAST_LEAVE_SENT,
MCAST_RESP_READY
};
struct mcast_member {
enum mcast_state state;
uint8_t join_state;
int num_pend_reqs;
struct list_head pending;
};
struct ib_sa_mcmember_data {
union ib_gid mgid;
union ib_gid port_gid;
__be32 qkey;
__be16 mlid;
u8 mtusel_mtu;
u8 tclass;
__be16 pkey;
u8 ratesel_rate;
u8 lifetmsel_lifetm;
__be32 sl_flowlabel_hoplimit;
u8 scope_join_state;
u8 proxy_join;
u8 reserved[2];
};
struct mcast_group {
struct ib_sa_mcmember_data rec;
struct rb_node node;
struct list_head mgid0_list;
struct mlx4_ib_demux_ctx *demux;
struct mcast_member func[MAX_VFS];
struct mutex lock;
struct work_struct work;
struct list_head pending_list;
int members[3];
enum mcast_group_state state;
enum mcast_group_state prev_state;
struct ib_sa_mad response_sa_mad;
__be64 last_req_tid;
char name[33]; /* MGID string */
struct device_attribute dentry;
/* refcount is the reference count for the following:
1. Each queued request
2. Each invocation of the worker thread
3. Membership of the port at the SA
*/
atomic_t refcount;
/* delayed work to clean pending SM request */
struct delayed_work timeout_work;
struct list_head cleanup_list;
};
struct mcast_req {
int func;
struct ib_sa_mad sa_mad;
struct list_head group_list;
struct list_head func_list;
struct mcast_group *group;
int clean;
};
#define safe_atomic_dec(ref) \
do {\
if (atomic_dec_and_test(ref)) \
mcg_warn_group(group, "did not expect to reach zero\n"); \
} while (0)
static const char *get_state_string(enum mcast_group_state state)
{
switch (state)