Commit 976fd0e2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband

* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband:
  IB/core: Set static rate in ib_init_ah_from_path()
  IB/ipath: Make ipath_map_sg() static
  IB/core: Fix sparse warnings about shadowed declarations
  RDMA/cma: Add multicast communication support
  IB/sa: Track multicast join/leave requests
  IPoIB: CM error handling thinko fix
  RDMA/cxgb3: Remove Open Grid Computing copyrights in iw_cxgb3 driver
  RDMA/cxgb3: Fail posts synchronously when in TERMINATE state
  RDMA/iwcm: iw_cm_id destruction race fixes
  IB/ehca: Change query_port() to return LINK_UP instead UNKNOWN
  IB/ehca: Allow en/disabling scaling code via module parameter
  IB/ehca: Fix race condition/locking issues in scaling code
  IB/ehca: Rework irq handler
  IPoIB: Only allow root to change between datagram and connected mode
  IB/mthca: Fix allocation of ICM chunks in coherent memory
  IB/mthca: Allow the QP state transition RESET->RESET
parents 733abe4f 7084f842
...@@ -12,7 +12,7 @@ ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ ...@@ -12,7 +12,7 @@ ib_core-y := packer.o ud_header.o verbs.o sysfs.o \
ib_mad-y := mad.o smi.o agent.o mad_rmpp.o ib_mad-y := mad.o smi.o agent.o mad_rmpp.o
ib_sa-y := sa_query.o ib_sa-y := sa_query.o multicast.o
ib_cm-y := cm.o ib_cm-y := cm.o
......
This diff is collapsed.
...@@ -301,7 +301,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, ...@@ -301,7 +301,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
{ {
struct ib_pool_fmr *fmr; struct ib_pool_fmr *fmr;
struct ib_fmr_attr attr = { struct ib_fmr_attr fmr_attr = {
.max_pages = params->max_pages_per_fmr, .max_pages = params->max_pages_per_fmr,
.max_maps = pool->max_remaps, .max_maps = pool->max_remaps,
.page_shift = params->page_shift .page_shift = params->page_shift
...@@ -321,7 +321,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, ...@@ -321,7 +321,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
fmr->ref_count = 0; fmr->ref_count = 0;
INIT_HLIST_NODE(&fmr->cache_node); INIT_HLIST_NODE(&fmr->cache_node);
fmr->fmr = ib_alloc_fmr(pd, params->access, &attr); fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr);
if (IS_ERR(fmr->fmr)) { if (IS_ERR(fmr->fmr)) {
printk(KERN_WARNING "fmr_create failed for FMR %d", i); printk(KERN_WARNING "fmr_create failed for FMR %d", i);
kfree(fmr); kfree(fmr);
......
...@@ -146,6 +146,12 @@ static int copy_private_data(struct iw_cm_event *event) ...@@ -146,6 +146,12 @@ static int copy_private_data(struct iw_cm_event *event)
return 0; return 0;
} }
static void free_cm_id(struct iwcm_id_private *cm_id_priv)
{
dealloc_work_entries(cm_id_priv);
kfree(cm_id_priv);
}
/* /*
* Release a reference on cm_id. If the last reference is being * Release a reference on cm_id. If the last reference is being
* released, enable the waiting thread (in iw_destroy_cm_id) to * released, enable the waiting thread (in iw_destroy_cm_id) to
...@@ -153,21 +159,14 @@ static int copy_private_data(struct iw_cm_event *event) ...@@ -153,21 +159,14 @@ static int copy_private_data(struct iw_cm_event *event)
*/ */
static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv) static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
{ {
int ret = 0;
BUG_ON(atomic_read(&cm_id_priv->refcount)==0); BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
if (atomic_dec_and_test(&cm_id_priv->refcount)) { if (atomic_dec_and_test(&cm_id_priv->refcount)) {
BUG_ON(!list_empty(&cm_id_priv->work_list)); BUG_ON(!list_empty(&cm_id_priv->work_list));
if (waitqueue_active(&cm_id_priv->destroy_comp.wait)) {
BUG_ON(cm_id_priv->state != IW_CM_STATE_DESTROYING);
BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY,
&cm_id_priv->flags));
ret = 1;
}
complete(&cm_id_priv->destroy_comp); complete(&cm_id_priv->destroy_comp);
return 1;
} }
return ret; return 0;
} }
static void add_ref(struct iw_cm_id *cm_id) static void add_ref(struct iw_cm_id *cm_id)
...@@ -181,7 +180,11 @@ static void rem_ref(struct iw_cm_id *cm_id) ...@@ -181,7 +180,11 @@ static void rem_ref(struct iw_cm_id *cm_id)
{ {
struct iwcm_id_private *cm_id_priv; struct iwcm_id_private *cm_id_priv;
cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
iwcm_deref_id(cm_id_priv); if (iwcm_deref_id(cm_id_priv) &&
test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) {
BUG_ON(!list_empty(&cm_id_priv->work_list));
free_cm_id(cm_id_priv);
}
} }
static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event); static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event);
...@@ -355,7 +358,9 @@ static void destroy_cm_id(struct iw_cm_id *cm_id) ...@@ -355,7 +358,9 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
case IW_CM_STATE_CONN_RECV: case IW_CM_STATE_CONN_RECV:
/* /*
* App called destroy before/without calling accept after * App called destroy before/without calling accept after
* receiving connection request event notification. * receiving connection request event notification or
* returned non zero from the event callback function.
* In either case, must tell the provider to reject.
*/ */
cm_id_priv->state = IW_CM_STATE_DESTROYING; cm_id_priv->state = IW_CM_STATE_DESTROYING;
break; break;
...@@ -391,9 +396,7 @@ void iw_destroy_cm_id(struct iw_cm_id *cm_id) ...@@ -391,9 +396,7 @@ void iw_destroy_cm_id(struct iw_cm_id *cm_id)
wait_for_completion(&cm_id_priv->destroy_comp); wait_for_completion(&cm_id_priv->destroy_comp);
dealloc_work_entries(cm_id_priv); free_cm_id(cm_id_priv);
kfree(cm_id_priv);
} }
EXPORT_SYMBOL(iw_destroy_cm_id); EXPORT_SYMBOL(iw_destroy_cm_id);
...@@ -647,10 +650,11 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv, ...@@ -647,10 +650,11 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv,
/* Call the client CM handler */ /* Call the client CM handler */
ret = cm_id->cm_handler(cm_id, iw_event); ret = cm_id->cm_handler(cm_id, iw_event);
if (ret) { if (ret) {
iw_cm_reject(cm_id, NULL, 0);
set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags); set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
destroy_cm_id(cm_id); destroy_cm_id(cm_id);
if (atomic_read(&cm_id_priv->refcount)==0) if (atomic_read(&cm_id_priv->refcount)==0)
kfree(cm_id); free_cm_id(cm_id_priv);
} }
out: out:
...@@ -854,13 +858,12 @@ static void cm_work_handler(struct work_struct *_work) ...@@ -854,13 +858,12 @@ static void cm_work_handler(struct work_struct *_work)
destroy_cm_id(&cm_id_priv->id); destroy_cm_id(&cm_id_priv->id);
} }
BUG_ON(atomic_read(&cm_id_priv->refcount)==0); BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
if (iwcm_deref_id(cm_id_priv)) if (iwcm_deref_id(cm_id_priv)) {
return; if (test_bit(IWCM_F_CALLBACK_DESTROY,
&cm_id_priv->flags)) {
if (atomic_read(&cm_id_priv->refcount)==0 && BUG_ON(!list_empty(&cm_id_priv->work_list));
test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) { free_cm_id(cm_id_priv);
dealloc_work_entries(cm_id_priv); }
kfree(cm_id_priv);
return; return;
} }
spin_lock_irqsave(&cm_id_priv->lock, flags); spin_lock_irqsave(&cm_id_priv->lock, flags);
......
This diff is collapsed.
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Voltaire, Inc.  All rights reserved.
* Copyright (c) 2006 Intel Corporation. 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.
*/
#ifndef SA_H
#define SA_H
#include <rdma/ib_sa.h>
static inline void ib_sa_client_get(struct ib_sa_client *client)
{
atomic_inc(&client->users);
}
static inline void ib_sa_client_put(struct ib_sa_client *client)
{
if (atomic_dec_and_test(&client->users))
complete(&client->comp);
}
int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
struct ib_device *device, u8 port_num,
u8 method,
struct ib_sa_mcmember_rec *rec,
ib_sa_comp_mask comp_mask,
int timeout_ms, gfp_t gfp_mask,
void (*callback)(int status,
struct ib_sa_mcmember_rec *resp,
void *context),
void *context,
struct ib_sa_query **sa_query);
int mcast_init(void);
void mcast_cleanup(void);
#endif /* SA_H */
...@@ -47,8 +47,8 @@ ...@@ -47,8 +47,8 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <rdma/ib_pack.h> #include <rdma/ib_pack.h>
#include <rdma/ib_sa.h>
#include <rdma/ib_cache.h> #include <rdma/ib_cache.h>
#include "sa.h"
MODULE_AUTHOR("Roland Dreier"); MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("InfiniBand subnet administration query support"); MODULE_DESCRIPTION("InfiniBand subnet administration query support");
...@@ -425,17 +425,6 @@ void ib_sa_register_client(struct ib_sa_client *client) ...@@ -425,17 +425,6 @@ void ib_sa_register_client(struct ib_sa_client *client)
} }
EXPORT_SYMBOL(ib_sa_register_client); EXPORT_SYMBOL(ib_sa_register_client);
static inline void ib_sa_client_get(struct ib_sa_client *client)
{
atomic_inc(&client->users);
}
static inline void ib_sa_client_put(struct ib_sa_client *client)
{
if (atomic_dec_and_test(&client->users))
complete(&client->comp);
}
void ib_sa_unregister_client(struct ib_sa_client *client) void ib_sa_unregister_client(struct ib_sa_client *client)
{ {
ib_sa_client_put(client); ib_sa_client_put(client);
...@@ -482,6 +471,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num, ...@@ -482,6 +471,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
ah_attr->sl = rec->sl; ah_attr->sl = rec->sl;
ah_attr->src_path_bits = be16_to_cpu(rec->slid) & 0x7f; ah_attr->src_path_bits = be16_to_cpu(rec->slid) & 0x7f;
ah_attr->port_num = port_num; ah_attr->port_num = port_num;
ah_attr->static_rate = rec->rate;
if (rec->hop_limit > 1) { if (rec->hop_limit > 1) {
ah_attr->ah_flags = IB_AH_GRH; ah_attr->ah_flags = IB_AH_GRH;
...@@ -901,7 +891,6 @@ int ib_sa_mcmember_rec_query(struct ib_sa_client *client, ...@@ -901,7 +891,6 @@ int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
kfree(query); kfree(query);
return ret; return ret;
} }
EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
static void send_handler(struct ib_mad_agent *agent, static void send_handler(struct ib_mad_agent *agent,
struct ib_mad_send_wc *mad_send_wc) struct ib_mad_send_wc *mad_send_wc)
...@@ -1053,14 +1042,27 @@ static int __init ib_sa_init(void) ...@@ -1053,14 +1042,27 @@ static int __init ib_sa_init(void)
get_random_bytes(&tid, sizeof tid); get_random_bytes(&tid, sizeof tid);
ret = ib_register_client(&sa_client); ret = ib_register_client(&sa_client);
if (ret) if (ret) {
printk(KERN_ERR "Couldn't register ib_sa client\n"); printk(KERN_ERR "Couldn't register ib_sa client\n");
goto err1;
}
ret = mcast_init();
if (ret) {
printk(KERN_ERR "Couldn't initialize multicast handling\n");
goto err2;
}
return 0;
err2:
ib_unregister_client(&sa_client);
err1:
return ret; return ret;
} }
static void __exit ib_sa_cleanup(void) static void __exit ib_sa_cleanup(void)
{ {
mcast_cleanup();
ib_unregister_client(&sa_client); ib_unregister_client(&sa_client);
idr_destroy(&query_idr); idr_destroy(&query_idr);
} }
......
...@@ -714,8 +714,6 @@ int ib_device_register_sysfs(struct ib_device *device) ...@@ -714,8 +714,6 @@ int ib_device_register_sysfs(struct ib_device *device)
if (ret) if (ret)
goto err_put; goto err_put;
} else { } else {
int i;
for (i = 1; i <= device->phys_port_cnt; ++i) { for (i = 1; i <= device->phys_port_cnt; ++i) {
ret = add_port(device, i); ret = add_port(device, i);
if (ret) if (ret)
......
...@@ -70,10 +70,24 @@ struct ucma_context { ...@@ -70,10 +70,24 @@ struct ucma_context {
u64 uid; u64 uid;
struct list_head list; struct list_head list;
struct list_head mc_list;
};
struct ucma_multicast {
struct ucma_context *ctx;
int id;
int events_reported;
u64 uid;
struct list_head list;
struct sockaddr addr;
u8 pad[sizeof(struct sockaddr_in6) -
sizeof(struct sockaddr)];
}; };
struct ucma_event { struct ucma_event {
struct ucma_context *ctx; struct ucma_context *ctx;
struct ucma_multicast *mc;
struct list_head list; struct list_head list;
struct rdma_cm_id *cm_id; struct rdma_cm_id *cm_id;
struct rdma_ucm_event_resp resp; struct rdma_ucm_event_resp resp;
...@@ -81,6 +95,7 @@ struct ucma_event { ...@@ -81,6 +95,7 @@ struct ucma_event {
static DEFINE_MUTEX(mut); static DEFINE_MUTEX(mut);
static DEFINE_IDR(ctx_idr); static DEFINE_IDR(ctx_idr);
static DEFINE_IDR(multicast_idr);
static inline struct ucma_context *_ucma_find_context(int id, static inline struct ucma_context *_ucma_find_context(int id,
struct ucma_file *file) struct ucma_file *file)
...@@ -124,6 +139,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file) ...@@ -124,6 +139,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
atomic_set(&ctx->ref, 1); atomic_set(&ctx->ref, 1);
init_completion(&ctx->comp); init_completion(&ctx->comp);
INIT_LIST_HEAD(&ctx->mc_list);
ctx->file = file; ctx->file = file;
do { do {
...@@ -147,6 +163,37 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file) ...@@ -147,6 +163,37 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
return NULL; return NULL;
} }
static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx)
{
struct ucma_multicast *mc;
int ret;
mc = kzalloc(sizeof(*mc), GFP_KERNEL);
if (!mc)
return NULL;
do {
ret = idr_pre_get(&multicast_idr, GFP_KERNEL);
if (!ret)
goto error;
mutex_lock(&mut);
ret = idr_get_new(&multicast_idr, mc, &mc->id);
mutex_unlock(&mut);
} while (ret == -EAGAIN);
if (ret)
goto error;
mc->ctx = ctx;
list_add_tail(&mc->list, &ctx->mc_list);
return mc;
error:
kfree(mc);
return NULL;
}
static void ucma_copy_conn_event(struct rdma_ucm_conn_param *dst, static void ucma_copy_conn_event(struct rdma_ucm_conn_param *dst,
struct rdma_conn_param *src) struct rdma_conn_param *src)
{ {
...@@ -180,8 +227,19 @@ static void ucma_set_event_context(struct ucma_context *ctx, ...@@ -180,8 +227,19 @@ static void ucma_set_event_context(struct ucma_context *ctx,
struct ucma_event *uevent) struct ucma_event *uevent)
{ {
uevent->ctx = ctx; uevent->ctx = ctx;
switch (event->event) {
case RDMA_CM_EVENT_MULTICAST_JOIN:
case RDMA_CM_EVENT_MULTICAST_ERROR:
uevent->mc = (struct ucma_multicast *)
event->param.ud.private_data;
uevent->resp.uid = uevent->mc->uid;
uevent->resp.id = uevent->mc->id;
break;
default:
uevent->resp.uid = ctx->uid; uevent->resp.uid = ctx->uid;
uevent->resp.id = ctx->id; uevent->resp.id = ctx->id;
break;
}
} }
static int ucma_event_handler(struct rdma_cm_id *cm_id, static int ucma_event_handler(struct rdma_cm_id *cm_id,
...@@ -199,7 +257,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id, ...@@ -199,7 +257,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
ucma_set_event_context(ctx, event, uevent); ucma_set_event_context(ctx, event, uevent);
uevent->resp.event = event->event; uevent->resp.event = event->event;
uevent->resp.status = event->status; uevent->resp.status = event->status;
if (cm_id->ps == RDMA_PS_UDP) if (cm_id->ps == RDMA_PS_UDP || cm_id->ps == RDMA_PS_IPOIB)
ucma_copy_ud_event(&uevent->resp.param.ud, &event->param.ud); ucma_copy_ud_event(&uevent->resp.param.ud, &event->param.ud);
else else
ucma_copy_conn_event(&uevent->resp.param.conn, ucma_copy_conn_event(&uevent->resp.param.conn,
...@@ -290,6 +348,8 @@ static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf, ...@@ -290,6 +348,8 @@ static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf,
list_del(&uevent->list); list_del(&uevent->list);
uevent->ctx->events_reported++; uevent->ctx->events_reported++;
if (uevent->mc)
uevent->mc->events_reported++;
kfree(uevent); kfree(uevent);
done: done:
mutex_unlock(&file->mut); mutex_unlock(&file->mut);
...@@ -342,6 +402,19 @@ static ssize_t ucma_create_id(struct ucma_file *file, ...@@ -342,6 +402,19 @@ static ssize_t ucma_create_id(struct ucma_file *file,
return ret; return ret;
} }
static void ucma_cleanup_multicast(struct ucma_context *ctx)
{
struct ucma_multicast *mc, *tmp;
mutex_lock(&mut);
list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) {
list_del(&mc->list);
idr_remove(&multicast_idr, mc->id);
kfree(mc);
}
mutex_unlock(&mut);
}
static void ucma_cleanup_events(struct ucma_context *ctx) static void ucma_cleanup_events(struct ucma_context *ctx)
{ {
struct ucma_event *uevent, *tmp; struct ucma_event *uevent, *tmp;
...@@ -360,6 +433,19 @@ static void ucma_cleanup_events(struct ucma_context *ctx) ...@@ -360,6 +433,19 @@ static void ucma_cleanup_events(struct ucma_context *ctx)
} }
} }
static void ucma_cleanup_mc_events(struct ucma_multicast *mc)
{
struct ucma_event *uevent, *tmp;
list_for_each_entry_safe(uevent, tmp, &mc->ctx->file->event_list, list) {
if (uevent->mc != mc)
continue;
list_del(&uevent->list);
kfree(uevent);
}
}
static int ucma_free_ctx(struct ucma_context *ctx) static int ucma_free_ctx(struct ucma_context *ctx)
{ {
int events_reported; int events_reported;
...@@ -367,6 +453,8 @@ static int ucma_free_ctx(struct ucma_context *ctx) ...@@ -367,6 +453,8 @@ static int ucma_free_ctx(struct ucma_context *ctx)
/* No new events will be generated after destroying the id. */ /* No new events will be generated after destroying the id. */
rdma_destroy_id(ctx->cm_id); rdma_destroy_id(ctx->cm_id);
ucma_cleanup_multicast(ctx);
/* Cleanup events not yet reported to the user. */ /* Cleanup events not yet reported to the user. */
mutex_lock(&ctx->file->mut); mutex_lock(&ctx->file->mut);
ucma_cleanup_events(ctx); ucma_cleanup_events(ctx);
...@@ -731,6 +819,114 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, ...@@ -731,6 +819,114 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
return ret; return ret;
} }
static ssize_t ucma_join_multicast(struct ucma_file *file,
const char __user *inbuf,
int in_len, int out_len)
{
struct rdma_ucm_join_mcast cmd;
struct rdma_ucm_create_id_resp resp;
struct ucma_context *ctx;
struct ucma_multicast *mc;
int ret;
if (out_len < sizeof(resp))
return -ENOSPC;
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
ctx = ucma_get_ctx(file, cmd.id);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
mutex_lock(&file->mut);
mc = ucma_alloc_multicast(ctx);
if (IS_ERR(mc)) {
ret = PTR_ERR(mc);
goto err1;
}
mc->uid = cmd.uid;
memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr);
ret = rdma_join_multicast(ctx->cm_id, &mc->addr, mc);
if (ret)
goto err2;
resp.id = mc->id;
if (copy_to_user((void __user *)(unsigned long)cmd.response,
&resp, sizeof(resp))) {
ret = -EFAULT;
goto err3;
}
mutex_unlock(&file->mut);
ucma_put_ctx(ctx);
return 0;
err3:
rdma_leave_multicast(ctx->cm_id, &mc->addr);
ucma_cleanup_mc_events(mc);
err2:
mutex_lock(&mut);
idr_remove(&multicast_idr, mc->id);
mutex_unlock(&mut);
list_del(&mc->list);
kfree(mc);
err1:
mutex_unlock(&file->mut);
ucma_put_ctx(ctx);
return ret;
}
static ssize_t ucma_leave_multicast(struct ucma_file *file,
const char __user *inbuf,
int in_len, int out_len)
{
struct rdma_ucm_destroy_id cmd;
struct rdma_ucm_destroy_id_resp resp;
struct ucma_multicast *mc;
int ret = 0;
if (out_len < sizeof(resp))
return -ENOSPC;
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
mutex_lock(&mut);
mc = idr_find(&multicast_idr, cmd.id);
if (!mc)
mc = ERR_PTR(-ENOENT);
else if (mc->ctx->file != file)
mc = ERR_PTR(-EINVAL);
else {
idr_remove(&multicast_idr, mc->id);
atomic_inc(&mc->ctx->ref);
}
mutex_unlock(&mut);
if (IS_ERR(mc)) {
ret = PTR_ERR(mc);
goto out;
}
rdma_leave_multicast(mc->ctx->cm_id, &mc->addr);
mutex_lock(&mc->ctx->file->mut);
ucma_cleanup_mc_events(mc);
list_del(&mc->list);
mutex_unlock(&mc->ctx->file->mut);
ucma_put_ctx(mc->ctx);
resp.events_reported = mc->events_reported;
kfree(mc);
if (copy_to_user((void __user *)(unsigned long)cmd.response,
&resp, sizeof(resp)))
ret = -EFAULT;
out:
return ret;
}
static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
const char __user *inbuf, const char __user *inbuf,
int in_len, int out_len) = { int in_len, int out_len) = {
...@@ -750,6 +946,8 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, ...@@ -750,6 +946,8 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
[RDMA_USER_CM_CMD_GET_OPTION] = NULL, [RDMA_USER_CM_CMD_GET_OPTION] = NULL,
[RDMA_USER_CM_CMD_SET_OPTION] = NULL, [RDMA_USER_CM_CMD_SET_OPTION] = NULL,
[RDMA_USER_CM_CMD_NOTIFY] = ucma_notify, [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify,
[RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast,
[RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast,
}; };
static ssize_t ucma_write(struct file *filp, const char __user *buf, static ssize_t ucma_write(struct file *filp, const char __user *buf,
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
...@@ -846,6 +845,8 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, ...@@ -846,6 +845,8 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
break; break;
case IWCH_QP_STATE_TERMINATE: case IWCH_QP_STATE_TERMINATE:
qhp->attr.state = IWCH_QP_STATE_TERMINATE; qhp->attr.state = IWCH_QP_STATE_TERMINATE;
if (t3b_device(qhp->rhp))
cxio_set_wq_in_error(&qhp->wq);
if (!internal) if (!internal)
terminate = 1; terminate = 1;
break; break;
......
/* /*
* Copyright (c) 2006 Chelsio, Inc. All rights reserved. * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
* Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved.
* *
* This software is available to you under a choice of one of two * 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 * licenses. You may choose to be licensed under the terms of the GNU
......
...@@ -7,11 +7,3 @@ config INFINIBAND_EHCA ...@@ -7,11 +7,3 @@ config INFINIBAND_EHCA
To compile the driver as a module, choose M here. The module To compile the driver as a module, choose M here. The module
will be called ib_ehca. will be called ib_ehca.
config INFINIBAND_EHCA_SCALING
bool "Scaling support (EXPERIMENTAL)"
depends on IBMEBUS && INFINIBAND_EHCA && HOTPLUG_CPU && EXPERIMENTAL
default y
---help---
eHCA scaling support schedules the CQ callbacks to different CPUs.
To enable this feature choose Y here.
...@@ -42,8 +42,6 @@ ...@@ -42,8 +42,6 @@
#ifndef __EHCA_CLASSES_H__ #ifndef __EHCA_CLASSES_H__
#define __EHCA_CLASSES_H__ #define __EHCA_CLASSES_H__
#include "ehca_classes.h"
#include "ipz_pt_fn.h"
struct ehca_module; struct ehca_module;
struct ehca_qp; struct ehca_qp;
...@@ -54,14 +52,22 @@ struct ehca_mw; ...@@ -54,14 +52,22 @@ struct ehca_mw;
struct ehca_pd; struct ehca_pd;
struct ehca_av; struct ehca_av;
#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
#include "ehca_classes_pSeries.h" #include "ehca_classes_pSeries.h"
#endif #endif
#include "ipz_pt_fn.h"
#include "ehca_qes.h"
#include "ehca_irq.h"
#include <rdma/ib_verbs.h> #define EHCA_EQE_CACHE_SIZE 20
#include <rdma/ib_user_verbs.h>
#include "ehca_irq.h" struct ehca_eqe_cache_entry {
struct ehca_eqe *eqe;
struct ehca_cq *cq;
};
struct ehca_eq { struct ehca_eq {
u32 length; u32 length;
...@@ -74,6 +80,8 @@ struct ehca_eq { ...@@ -74,6 +80,8 @@ struct ehca_eq {
spinlock_t spinlock; spinlock_t spinlock;
struct tasklet_struct interrupt_task; struct tasklet_struct interrupt_task;
u32 ist; u32 ist;
spinlock_t irq_spinlock;
struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE];
}; };
struct ehca_sport { struct ehca_sport {
...@@ -269,6 +277,7 @@ extern struct idr ehca_cq_idr; ...@@ -269,6 +277,7 @@ extern struct idr ehca_cq_idr;
extern int ehca_static_rate; extern int ehca_static_rate;
extern int ehca_port_act_time; extern int ehca_port_act_time;
extern int ehca_use_hp_mr; extern int ehca_use_hp_mr;
extern int ehca_scaling_code;
struct ipzu_queue_resp { struct ipzu_queue_resp {
u32 qe_size; /* queue entry size */ u32 qe_size; /* queue entry size */
......
...@@ -61,6 +61,7 @@ int ehca_create_eq(struct ehca_shca *shca, ...@@ -61,6 +61,7 @@ int ehca_create_eq(struct ehca_shca *shca,
struct ib_device *ib_dev = &shca->ib_device; struct ib_device *ib_dev = &shca->ib_device;
spin_lock_init(&eq->spinlock); spin_lock_init(&eq->spinlock);
spin_lock_init(&eq->irq_spinlock);
eq->is_initialized = 0; eq->is_initialized = 0;
if (type != EHCA_EQ && type != EHCA_NEQ) { if (type != EHCA_EQ && type != EHCA_NEQ) {
......
...@@ -162,6 +162,9 @@ int ehca_query_port(struct ib_device *ibdev, ...@@ -162,6 +162,9 @@ int ehca_query_port(struct ib_device *ibdev,
props->active_width = IB_WIDTH_12X; props->active_width = IB_WIDTH_12X;
props->active_speed = 0x1; props->active_speed = 0x1;
/* at the moment (logical) link state is always LINK_UP */
props->phys_state = 0x5;
query_port1: query_port1:
ehca_free_fw_ctrlblock(rblock); ehca_free_fw_ctrlblock(rblock);
......
This diff is collapsed.
...@@ -56,6 +56,7 @@ void ehca_tasklet_neq(unsigned long data); ...@@ -56,6 +56,7 @@ void ehca_tasklet_neq(unsigned long data);
irqreturn_t ehca_interrupt_eq(int irq, void *dev_id); irqreturn_t ehca_interrupt_eq(int irq, void *dev_id);
void ehca_tasklet_eq(unsigned long data); void ehca_tasklet_eq(unsigned long data);
void ehca_process_eq(struct ehca_shca *shca, int is_irq);
struct ehca_cpu_comp_task { struct ehca_cpu_comp_task {
wait_queue_head_t wait_queue; wait_queue_head_t wait_queue;
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>"); MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
MODULE_VERSION("SVNEHCA_0020"); MODULE_VERSION("SVNEHCA_0021");
int ehca_open_aqp1 = 0; int ehca_open_aqp1 = 0;
int ehca_debug_level = 0; int ehca_debug_level = 0;
...@@ -62,6 +62,7 @@ int ehca_use_hp_mr = 0; ...@@ -62,6 +62,7 @@ int ehca_use_hp_mr = 0;
int ehca_port_act_time = 30; int ehca_port_act_time = 30;
int ehca_poll_all_eqs = 1; int ehca_poll_all_eqs = 1;
int ehca_static_rate = -1; int ehca_static_rate = -1;
int ehca_scaling_code = 1;
module_param_named(open_aqp1, ehca_open_aqp1, int, 0); module_param_named(open_aqp1, ehca_open_aqp1, int, 0);
module_param_named(debug_level, ehca_debug_level, int, 0); module_param_named(debug_level, ehca_debug_level, int, 0);
...@@ -71,6 +72,7 @@ module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0); ...@@ -71,6 +72,7 @@ module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0);
module_param_named(port_act_time, ehca_port_act_time, int, 0); module_param_named(port_act_time, ehca_port_act_time, int, 0);
module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0); module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0);
module_param_named(static_rate, ehca_static_rate, int, 0); module_param_named(static_rate, ehca_static_rate, int, 0);
module_param_named(scaling_code, ehca_scaling_code, int, 0);
MODULE_PARM_DESC(open_aqp1, MODULE_PARM_DESC(open_aqp1,
"AQP1 on startup (0: no (default), 1: yes)"); "AQP1 on startup (0: no (default), 1: yes)");
...@@ -91,6 +93,8 @@ MODULE_PARM_DESC(poll_all_eqs, ...@@ -91,6 +93,8 @@ MODULE_PARM_DESC(poll_all_eqs,
" (0: no, 1: yes (default))"); " (0: no, 1: yes (default))");
MODULE_PARM_DESC(static_rate, MODULE_PARM_DESC(static_rate,
"set permanent static rate (default: disabled)"); "set permanent static rate (default: disabled)");
MODULE_PARM_DESC(scaling_code,
"set scaling code (0: disabled, 1: enabled/default)");
spinlock_t ehca_qp_idr_lock; spinlock_t ehca_qp_idr_lock;
spinlock_t ehca_cq_idr_lock; spinlock_t ehca_cq_idr_lock;
...@@ -778,8 +782,24 @@ void ehca_poll_eqs(unsigned long data) ...@@ -778,8 +782,24 @@ void ehca_poll_eqs(unsigned long data)
spin_lock(&shca_list_lock); spin_lock(&shca_list_lock);
list_for_each_entry(shca, &shca_list, shca_list) { list_for_each_entry(shca, &shca_list, shca_list) {
if (shca->eq.is_initialized) if (shca->eq.is_initialized) {
ehca_tasklet_eq((unsigned long)(void*)shca); /* call deadman proc only if eq ptr does not change */
struct ehca_eq *eq = &shca->eq;
int max = 3;
volatile u64 q_ofs, q_ofs2;
u64 flags;
spin_lock_irqsave(&eq->spinlock, flags);
q_ofs = eq->ipz_queue.current_q_offset;
spin_unlock_irqrestore(&eq->spinlock, flags);
do {
spin_lock_irqsave(&eq->spinlock, flags);
q_ofs2 = eq->ipz_queue.current_q_offset;
spin_unlock_irqrestore(&eq->spinlock, flags);
max--;
} while (q_ofs == q_ofs2 && max > 0);
if (q_ofs == q_ofs2)
ehca_process_eq(shca, 0);
}
} }
mod_timer(&poll_eqs_timer, jiffies + HZ); mod_timer(&poll_eqs_timer, jiffies + HZ);
spin_unlock(&shca_list_lock); spin_unlock(&shca_list_lock);
...@@ -790,7 +810,7 @@ int __init ehca_module_init(void) ...@@ -790,7 +810,7 @@ int __init ehca_module_init(void)
int ret; int ret;
printk(KERN_INFO "eHCA Infiniband Device Driver " printk(KERN_INFO "eHCA Infiniband Device Driver "
"(Rel.: SVNEHCA_0020)\n"); "(Rel.: SVNEHCA_0021)\n");
idr_init(&ehca_qp_idr); idr_init(&ehca_qp_idr);
idr_init(&ehca_cq_idr); idr_init(&ehca_cq_idr);
spin_lock_init(&ehca_qp_idr_lock); spin_lock_init(&ehca_qp_idr_lock);
......
...@@ -247,6 +247,15 @@ static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue) ...@@ -247,6 +247,15 @@ static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
return ret; return ret;
} }
static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue)
{
void *ret = ipz_qeit_get(queue);
u32 qe = *(u8 *) ret;
if ((qe >> 7) != (queue->toggle_state & 1))
return NULL;
return ret;
}
/* returns address (GX) of first queue entry */ /* returns address (GX) of first queue entry */
static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt) static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt)
{ {
......
...@@ -96,7 +96,7 @@ static void ipath_dma_unmap_page(struct ib_device *dev, ...@@ -96,7 +96,7 @@ static void ipath_dma_unmap_page(struct ib_device *dev,
BUG_ON(!valid_dma_direction(direction)); BUG_ON(!valid_dma_direction(direction));
} }
int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents, static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction direction) enum dma_data_direction direction)
{ {
u64 addr; u64 addr;
......
...@@ -175,7 +175,9 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, ...@@ -175,7 +175,9 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
if (!ret) { if (!ret) {
++chunk->npages; ++chunk->npages;
if (!coherent && chunk->npages == MTHCA_ICM_CHUNK_LEN) { if (coherent)
++chunk->nsg;
else if (chunk->npages == MTHCA_ICM_CHUNK_LEN) {
chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
chunk->npages, chunk->npages,
PCI_DMA_BIDIRECTIONAL); PCI_DMA_BIDIRECTIONAL);
......
...@@ -573,6 +573,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, ...@@ -573,6 +573,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
goto out; goto out;
} }
if (cur_state == new_state && cur_state == IB_QPS_RESET) {
err = 0;
goto out;
}
if ((attr_mask & IB_QP_PKEY_INDEX) && if ((attr_mask & IB_QP_PKEY_INDEX) &&
attr->pkey_index >= dev->limits.pkey_table_len) { attr->pkey_index >= dev->limits.pkey_table_len) {
mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n", mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n",
......
...@@ -145,7 +145,7 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, ...@@ -145,7 +145,7 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id,
for (; i >= 0; --i) for (; i >= 0; --i)
ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE); ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
kfree_skb(skb); dev_kfree_skb_any(skb);
return -ENOMEM; return -ENOMEM;
} }
...@@ -1138,7 +1138,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, ...@@ -1138,7 +1138,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr,
return -EINVAL; return -EINVAL;
} }
static DEVICE_ATTR(mode, S_IWUGO | S_IRUGO, show_mode, set_mode); static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode);
int ipoib_cm_add_mode_attr(struct net_device *dev) int ipoib_cm_add_mode_attr(struct net_device *dev)
{ {
......
...@@ -60,14 +60,11 @@ static DEFINE_MUTEX(mcast_mutex); ...@@ -60,14 +60,11 @@ static DEFINE_MUTEX(mcast_mutex);
/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
struct ipoib_mcast { struct ipoib_mcast {
struct ib_sa_mcmember_rec mcmember; struct ib_sa_mcmember_rec mcmember;
struct ib_sa_multicast *mc;
struct ipoib_ah *ah; struct ipoib_ah *ah;
struct rb_node rb_node; struct rb_node rb_node;
struct list_head list; struct list_head list;
struct completion done;
int query_id;
struct ib_sa_query *query;
unsigned long created; unsigned long created;
unsigned long backoff; unsigned long backoff;
...@@ -299,18 +296,22 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, ...@@ -299,18 +296,22 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
return 0; return 0;
} }
static void static int
ipoib_mcast_sendonly_join_complete(int status, ipoib_mcast_sendonly_join_complete(int status,
struct ib_sa_mcmember_rec *mcmember, struct ib_sa_multicast *multicast)
void *mcast_ptr)
{ {
struct ipoib_mcast *mcast = mcast_ptr; struct ipoib_mcast *mcast = multicast->context;
struct net_device *dev = mcast->dev; struct net_device *dev = mcast->dev;
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
/* We trap for port events ourselves. */
if (status == -ENETRESET)
return 0;
if (!status) if (!status)
ipoib_mcast_join_finish(mcast, mcmember); status = ipoib_mcast_join_finish(mcast, &multicast->rec);
else {
if (status) {
if (mcast->logcount++ < 20) if (mcast->logcount++ < 20)
ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for " ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for "
IPOIB_GID_FMT ", status %d\n", IPOIB_GID_FMT ", status %d\n",
...@@ -325,11 +326,10 @@ ipoib_mcast_sendonly_join_complete(int status, ...@@ -325,11 +326,10 @@ ipoib_mcast_sendonly_join_complete(int status,
spin_unlock_irq(&priv->tx_lock); spin_unlock_irq(&priv->tx_lock);
/* Clear the busy flag so we try again */ /* Clear the busy flag so we try again */
clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY,
mcast->query = NULL; &mcast->flags);
} }
return status;
complete(&mcast->done);
} }
static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
...@@ -359,35 +359,33 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) ...@@ -359,35 +359,33 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
rec.port_gid = priv->local_gid; rec.port_gid = priv->local_gid;
rec.pkey = cpu_to_be16(priv->pkey); rec.pkey = cpu_to_be16(priv->pkey);
init_completion(&mcast->done); mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca,
priv->port, &rec,
ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, &rec,
IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_MGID |
IB_SA_MCMEMBER_REC_PORT_GID | IB_SA_MCMEMBER_REC_PORT_GID |
IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_PKEY |
IB_SA_MCMEMBER_REC_JOIN_STATE, IB_SA_MCMEMBER_REC_JOIN_STATE,
1000, GFP_ATOMIC, GFP_ATOMIC,
ipoib_mcast_sendonly_join_complete, ipoib_mcast_sendonly_join_complete,
mcast, &mcast->query); mcast);
if (ret < 0) { if (IS_ERR(mcast->mc)) {
ipoib_warn(priv, "ib_sa_mcmember_rec_set failed (ret = %d)\n", ret = PTR_ERR(mcast->mc);
clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n",
ret); ret);
} else { } else {
ipoib_dbg_mcast(priv, "no multicast record for " IPOIB_GID_FMT ipoib_dbg_mcast(priv, "no multicast record for " IPOIB_GID_FMT
", starting join\n", ", starting join\n",
IPOIB_GID_ARG(mcast->mcmember.mgid)); IPOIB_GID_ARG(mcast->mcmember.mgid));
mcast->query_id = ret;
} }
return ret; return ret;
} }
static void ipoib_mcast_join_complete(int status, static int ipoib_mcast_join_complete(int status,
struct ib_sa_mcmember_rec *mcmember, struct ib_sa_multicast *multicast)
void *mcast_ptr)
{ {
struct ipoib_mcast *mcast = mcast_ptr; struct ipoib_mcast *mcast = multicast->context;
struct net_device *dev = mcast->dev; struct net_device *dev = mcast->dev;
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
...@@ -395,24 +393,25 @@ static void ipoib_mcast_join_complete(int status, ...@@ -395,24 +393,25 @@ static void ipoib_mcast_join_complete(int status,
" (status %d)\n", " (status %d)\n",
IPOIB_GID_ARG(mcast->mcmember.mgid), status); IPOIB_GID_ARG(mcast->mcmember.mgid), status);
if (!status && !ipoib_mcast_join_finish(mcast, mcmember)) { /* We trap for port events ourselves. */
if (status == -ENETRESET)
return 0;
if (!status)
status = ipoib_mcast_join_finish(mcast, &multicast->rec);
if (!status) {
mcast->backoff = 1; mcast->backoff = 1;
mutex_lock(&mcast_mutex); mutex_lock(&mcast_mutex);
if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
queue_delayed_work(ipoib_workqueue, queue_delayed_work(ipoib_workqueue,
&priv->mcast_task, 0); &priv->mcast_task, 0);
mutex_unlock(&mcast_mutex); mutex_unlock(&mcast_mutex);
complete(&mcast->done); return 0;
return;
}
if (status == -EINTR) {
complete(&mcast->done);
return;
} }
if (status && mcast->logcount++ < 20) { if (mcast->logcount++ < 20) {
if (status == -ETIMEDOUT || status == -EINTR) { if (status == -ETIMEDOUT) {
ipoib_dbg_mcast(priv, "multicast join failed for " IPOIB_GID_FMT ipoib_dbg_mcast(priv, "multicast join failed for " IPOIB_GID_FMT
", status %d\n", ", status %d\n",
IPOIB_GID_ARG(mcast->mcmember.mgid), IPOIB_GID_ARG(mcast->mcmember.mgid),
...@@ -429,24 +428,18 @@ static void ipoib_mcast_join_complete(int status, ...@@ -429,24 +428,18 @@ static void ipoib_mcast_join_complete(int status,
if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
mutex_lock(&mcast_mutex); /* Clear the busy flag so we try again */
status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
mutex_lock(&mcast_mutex);
spin_lock_irq(&priv->lock); spin_lock_irq(&priv->lock);
mcast->query = NULL; if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) {
if (status == -ETIMEDOUT)
queue_delayed_work(ipoib_workqueue, &priv->mcast_task,
0);
else
queue_delayed_work(ipoib_workqueue, &priv->mcast_task, queue_delayed_work(ipoib_workqueue, &priv->mcast_task,
mcast->backoff * HZ); mcast->backoff * HZ);
} else
complete(&mcast->done);
spin_unlock_irq(&priv->lock); spin_unlock_irq(&priv->lock);
mutex_unlock(&mcast_mutex); mutex_unlock(&mcast_mutex);
return; return status;
} }
static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
...@@ -495,15 +488,14 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, ...@@ -495,15 +488,14 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
rec.hop_limit = priv->broadcast->mcmember.hop_limit; rec.hop_limit = priv->broadcast->mcmember.hop_limit;
} }
init_completion(&mcast->done); set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port,
ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, &rec, comp_mask, GFP_KERNEL,
&rec, comp_mask, mcast->backoff * 1000, ipoib_mcast_join_complete, mcast);
GFP_ATOMIC, ipoib_mcast_join_complete, if (IS_ERR(mcast->mc)) {
mcast, &mcast->query); clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
ret = PTR_ERR(mcast->mc);
if (ret < 0) { ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret);
ipoib_warn(priv, "ib_sa_mcmember_rec_set failed, status %d\n", ret);
mcast->backoff *= 2; mcast->backoff *= 2;
if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
...@@ -515,8 +507,7 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, ...@@ -515,8 +507,7 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
&priv->mcast_task, &priv->mcast_task,
mcast->backoff * HZ); mcast->backoff * HZ);
mutex_unlock(&mcast_mutex); mutex_unlock(&mcast_mutex);
} else }
mcast->query_id = ret;
} }
void ipoib_mcast_join_task(struct work_struct *work) void ipoib_mcast_join_task(struct work_struct *work)
...@@ -568,6 +559,7 @@ void ipoib_mcast_join_task(struct work_struct *work) ...@@ -568,6 +559,7 @@ void ipoib_mcast_join_task(struct work_struct *work)
} }
if (!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { if (!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) {
if (!test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags))
ipoib_mcast_join(dev, priv->broadcast, 0); ipoib_mcast_join(dev, priv->broadcast, 0);
return; return;
} }
...@@ -625,26 +617,9 @@ int ipoib_mcast_start_thread(struct net_device *dev) ...@@ -625,26 +617,9 @@ int ipoib_mcast_start_thread(struct net_device *dev)
return 0; return 0;
} }
static void wait_for_mcast_join(struct ipoib_dev_priv *priv,
struct ipoib_mcast *mcast)
{
spin_lock_irq(&priv->lock);
if (mcast && mcast->query) {
ib_sa_cancel_query(mcast->query_id, mcast->query);
mcast->query = NULL;
spin_unlock_irq(&priv->lock);
ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
IPOIB_GID_ARG(mcast->mcmember.mgid));
wait_for_completion(&mcast->done);
}
else
spin_unlock_irq(&priv->lock);
}
int ipoib_mcast_stop_thread(struct net_device *dev, int flush) int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_mcast *mcast;
ipoib_dbg_mcast(priv, "stopping multicast thread\n"); ipoib_dbg_mcast(priv, "stopping multicast thread\n");
...@@ -660,52 +635,27 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush) ...@@ -660,52 +635,27 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
if (flush) if (flush)
flush_workqueue(ipoib_workqueue); flush_workqueue(ipoib_workqueue);
wait_for_mcast_join(priv, priv->broadcast);
list_for_each_entry(mcast, &priv->multicast_list, list)
wait_for_mcast_join(priv, mcast);
return 0; return 0;
} }
static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ib_sa_mcmember_rec rec = {
.join_state = 1
};
int ret = 0; int ret = 0;
if (!test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) {
return 0;
ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n", ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n",
IPOIB_GID_ARG(mcast->mcmember.mgid)); IPOIB_GID_ARG(mcast->mcmember.mgid));
rec.mgid = mcast->mcmember.mgid;
rec.port_gid = priv->local_gid;
rec.pkey = cpu_to_be16(priv->pkey);
/* Remove ourselves from the multicast group */ /* Remove ourselves from the multicast group */
ret = ipoib_mcast_detach(dev, be16_to_cpu(mcast->mcmember.mlid), ret = ipoib_mcast_detach(dev, be16_to_cpu(mcast->mcmember.mlid),
&mcast->mcmember.mgid); &mcast->mcmember.mgid);
if (ret) if (ret)
ipoib_warn(priv, "ipoib_mcast_detach failed (result = %d)\n", ret); ipoib_warn(priv, "ipoib_mcast_detach failed (result = %d)\n", ret);
}
/* if (test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
* Just make one shot at leaving and don't wait for a reply; ib_sa_free_multicast(mcast->mc);
* if we fail, too bad.
*/
ret = ib_sa_mcmember_rec_delete(&ipoib_sa_client, priv->ca, priv->port, &rec,
IB_SA_MCMEMBER_REC_MGID |
IB_SA_MCMEMBER_REC_PORT_GID |
IB_SA_MCMEMBER_REC_PKEY |
IB_SA_MCMEMBER_REC_JOIN_STATE,
0, GFP_ATOMIC, NULL,
mcast, &mcast->query);
if (ret < 0)
ipoib_warn(priv, "ib_sa_mcmember_rec_delete failed "
"for leave (result = %d)\n", ret);
return 0; return 0;
} }
...@@ -758,7 +708,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) ...@@ -758,7 +708,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
if (mcast->query) if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
ipoib_dbg_mcast(priv, "no address vector, " ipoib_dbg_mcast(priv, "no address vector, "
"but multicast join already started\n"); "but multicast join already started\n");
else if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) else if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags))
...@@ -916,7 +866,6 @@ void ipoib_mcast_restart_task(struct work_struct *work) ...@@ -916,7 +866,6 @@ void ipoib_mcast_restart_task(struct work_struct *work)
/* We have to cancel outside of the spinlock */ /* We have to cancel outside of the spinlock */
list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
wait_for_mcast_join(priv, mcast);
ipoib_mcast_leave(mcast->dev, mcast); ipoib_mcast_leave(mcast->dev, mcast);
ipoib_mcast_free(mcast); ipoib_mcast_free(mcast);
} }
......
...@@ -110,6 +110,12 @@ static inline void ib_addr_set_pkey(struct rdma_dev_addr *dev_addr, u16 pkey) ...@@ -110,6 +110,12 @@ static inline void ib_addr_set_pkey(struct rdma_dev_addr *dev_addr, u16 pkey)
dev_addr->broadcast[9] = (unsigned char) pkey; dev_addr->broadcast[9] = (unsigned char) pkey;
} }
static inline void ib_addr_get_mgid(struct rdma_dev_addr *dev_addr,
union ib_gid *gid)
{
memcpy(gid, dev_addr->broadcast + 4, sizeof *gid);
}
static inline void ib_addr_get_sgid(struct rdma_dev_addr *dev_addr, static inline void ib_addr_get_sgid(struct rdma_dev_addr *dev_addr,
union ib_gid *gid) union ib_gid *gid)
{ {
......
...@@ -285,18 +285,6 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, ...@@ -285,18 +285,6 @@ int ib_sa_path_rec_get(struct ib_sa_client *client,
void *context, void *context,
struct ib_sa_query **query); struct ib_sa_query **query);
int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
struct ib_device *device, u8 port_num,
u8 method,
struct ib_sa_mcmember_rec *rec,
ib_sa_comp_mask comp_mask,
int timeout_ms, gfp_t gfp_mask,
void (*callback)(int status,
struct ib_sa_mcmember_rec *resp,
void *context),
void *context,
struct ib_sa_query **query);
int ib_sa_service_rec_query(struct ib_sa_client *client, int ib_sa_service_rec_query(struct ib_sa_client *client,
struct ib_device *device, u8 port_num, struct ib_device *device, u8 port_num,
u8 method, u8 method,
...@@ -309,93 +297,82 @@ int ib_sa_service_rec_query(struct ib_sa_client *client, ...@@ -309,93 +297,82 @@ int ib_sa_service_rec_query(struct ib_sa_client *client,
void *context, void *context,
struct ib_sa_query **sa_query); struct ib_sa_query **sa_query);
struct ib_sa_multicast {
struct ib_sa_mcmember_rec rec;
ib_sa_comp_mask comp_mask;
int (*callback)(int status,
struct ib_sa_multicast *multicast);
void *context;
};
/** /**
* ib_sa_mcmember_rec_set - Start an MCMember set query * ib_sa_join_multicast - Initiates a join request to the specified multicast
* @client:SA client * group.
* @device:device to send query on * @client: SA client
* @port_num: port number to send query on * @device: Device associated with the multicast group.
* @rec:MCMember Record to send in query * @port_num: Port on the specified device to associate with the multicast
* @comp_mask:component mask to send in query * group.
* @timeout_ms:time to wait for response * @rec: SA multicast member record specifying group attributes.
* @gfp_mask:GFP mask to use for internal allocations * @comp_mask: Component mask indicating which group attributes of %rec are
* @callback:function called when query completes, times out or is * valid.
* canceled * @gfp_mask: GFP mask for memory allocations.
* @context:opaque user context passed to callback * @callback: User callback invoked once the join operation completes.
* @sa_query:query context, used to cancel query * @context: User specified context stored with the ib_sa_multicast structure.
* *
* Send an MCMember Set query to the SA (eg to join a multicast * This call initiates a multicast join request with the SA for the specified
* group). The callback function will be called when the query * multicast group. If the join operation is started successfully, it returns
* completes (or fails); status is 0 for a successful response, -EINTR * an ib_sa_multicast structure that is used to track the multicast operation.
* if the query is canceled, -ETIMEDOUT is the query timed out, or * Users must free this structure by calling ib_free_multicast, even if the
* -EIO if an error occurred sending the query. The resp parameter of * join operation later fails. (The callback status is non-zero.)
* the callback is only valid if status is 0.
* *
* If the return value of ib_sa_mcmember_rec_set() is negative, it is * If the join operation fails; status will be non-zero, with the following
* an error code. Otherwise it is a query ID that can be used to * failures possible:
* cancel the query. * -ETIMEDOUT: The request timed out.
* -EIO: An error occurred sending the query.
* -EINVAL: The MCMemberRecord values differed from the existing group's.
* -ENETRESET: Indicates that an fatal error has occurred on the multicast
* group, and the user must rejoin the group to continue using it.
*/ */
static inline int struct ib_sa_multicast *ib_sa_join_multicast(struct ib_sa_client *client,
ib_sa_mcmember_rec_set(struct ib_sa_client *client,
struct ib_device *device, u8 port_num, struct ib_device *device, u8 port_num,
struct ib_sa_mcmember_rec *rec, struct ib_sa_mcmember_rec *rec,
ib_sa_comp_mask comp_mask, ib_sa_comp_mask comp_mask, gfp_t gfp_mask,
int timeout_ms, gfp_t gfp_mask, int (*callback)(int status,
void (*callback)(int status, struct ib_sa_multicast
struct ib_sa_mcmember_rec *resp, *multicast),
void *context), void *context);
void *context,
struct ib_sa_query **query)
{
return ib_sa_mcmember_rec_query(client, device, port_num,
IB_MGMT_METHOD_SET,
rec, comp_mask,
timeout_ms, gfp_mask, callback,
context, query);
}
/** /**
* ib_sa_mcmember_rec_delete - Start an MCMember delete query * ib_free_multicast - Frees the multicast tracking structure, and releases
* @client:SA client * any reference on the multicast group.
* @device:device to send query on * @multicast: Multicast tracking structure allocated by ib_join_multicast.
* @port_num: port number to send query on
* @rec:MCMember Record to send in query
* @comp_mask:component mask to send in query
* @timeout_ms:time to wait for response
* @gfp_mask:GFP mask to use for internal allocations
* @callback:function called when query completes, times out or is
* canceled
* @context:opaque user context passed to callback
* @sa_query:query context, used to cancel query
*
* Send an MCMember Delete query to the SA (eg to leave a multicast
* group). The callback function will be called when the query
* completes (or fails); status is 0 for a successful response, -EINTR
* if the query is canceled, -ETIMEDOUT is the query timed out, or
* -EIO if an error occurred sending the query. The resp parameter of
* the callback is only valid if status is 0.
* *
* If the return value of ib_sa_mcmember_rec_delete() is negative, it * This call blocks until the multicast identifier is destroyed. It may
* is an error code. Otherwise it is a query ID that can be used to * not be called from within the multicast callback; however, returning a non-
* cancel the query. * zero value from the callback will result in destroying the multicast
* tracking structure.
*/ */
static inline int void ib_sa_free_multicast(struct ib_sa_multicast *multicast);
ib_sa_mcmember_rec_delete(struct ib_sa_client *client,
struct ib_device *device, u8 port_num, /**
* ib_get_mcmember_rec - Looks up a multicast member record by its MGID and
* returns it if found.
* @device: Device associated with the multicast group.
* @port_num: Port on the specified device to associate with the multicast
* group.
* @mgid: MGID of multicast group.
* @rec: Location to copy SA multicast member record.
*/
int ib_sa_get_mcmember_rec(struct ib_device *device, u8 port_num,
union ib_gid *mgid, struct ib_sa_mcmember_rec *rec);
/**
* ib_init_ah_from_mcmember - Initialize address handle attributes based on
* an SA multicast member record.
*/
int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
struct ib_sa_mcmember_rec *rec, struct ib_sa_mcmember_rec *rec,
ib_sa_comp_mask comp_mask, struct ib_ah_attr *ah_attr);
int timeout_ms, gfp_t gfp_mask,
void (*callback)(int status,
struct ib_sa_mcmember_rec *resp,
void *context),
void *context,
struct ib_sa_query **query)
{
return ib_sa_mcmember_rec_query(client, device, port_num,
IB_SA_METHOD_DELETE,
rec, comp_mask,
timeout_ms, gfp_mask, callback,
context, query);
}
/** /**
* ib_init_ah_from_path - Initialize address handle attributes based on an SA * ib_init_ah_from_path - Initialize address handle attributes based on an SA
......
...@@ -52,10 +52,13 @@ enum rdma_cm_event_type { ...@@ -52,10 +52,13 @@ enum rdma_cm_event_type {
RDMA_CM_EVENT_ESTABLISHED, RDMA_CM_EVENT_ESTABLISHED,
RDMA_CM_EVENT_DISCONNECTED, RDMA_CM_EVENT_DISCONNECTED,
RDMA_CM_EVENT_DEVICE_REMOVAL, RDMA_CM_EVENT_DEVICE_REMOVAL,
RDMA_CM_EVENT_MULTICAST_JOIN,
RDMA_CM_EVENT_MULTICAST_ERROR
}; };
enum rdma_port_space { enum rdma_port_space {
RDMA_PS_SDP = 0x0001, RDMA_PS_SDP = 0x0001,
RDMA_PS_IPOIB= 0x0002,
RDMA_PS_TCP = 0x0106, RDMA_PS_TCP = 0x0106,
RDMA_PS_UDP = 0x0111, RDMA_PS_UDP = 0x0111,
RDMA_PS_SCTP = 0x0183 RDMA_PS_SCTP = 0x0183
...@@ -294,5 +297,21 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data, ...@@ -294,5 +297,21 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
*/ */
int rdma_disconnect(struct rdma_cm_id *id); int rdma_disconnect(struct rdma_cm_id *id);
#endif /* RDMA_CM_H */ /**
* rdma_join_multicast - Join the multicast group specified by the given
* address.
* @id: Communication identifier associated with the request.
* @addr: Multicast address identifying the group to join.
* @context: User-defined context associated with the join request, returned
* to the user through the private_data pointer in multicast events.
*/
int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
void *context);
/**
* rdma_leave_multicast - Leave the multicast group specified by the given
* address.
*/
void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr);
#endif /* RDMA_CM_H */
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
int rdma_set_ib_paths(struct rdma_cm_id *id, int rdma_set_ib_paths(struct rdma_cm_id *id,
struct ib_sa_path_rec *path_rec, int num_paths); struct ib_sa_path_rec *path_rec, int num_paths);
/* Global qkey for UD QPs and multicast groups. */ /* Global qkey for UDP QPs and multicast groups. */
#define RDMA_UD_QKEY 0x01234567 #define RDMA_UDP_QKEY 0x01234567
#endif /* RDMA_CM_IB_H */ #endif /* RDMA_CM_IB_H */
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#include <rdma/ib_user_verbs.h> #include <rdma/ib_user_verbs.h>
#include <rdma/ib_user_sa.h> #include <rdma/ib_user_sa.h>
#define RDMA_USER_CM_ABI_VERSION 3 #define RDMA_USER_CM_ABI_VERSION 4
#define RDMA_MAX_PRIVATE_DATA 256 #define RDMA_MAX_PRIVATE_DATA 256
...@@ -58,7 +58,9 @@ enum { ...@@ -58,7 +58,9 @@ enum {
RDMA_USER_CM_CMD_GET_EVENT, RDMA_USER_CM_CMD_GET_EVENT,
RDMA_USER_CM_CMD_GET_OPTION, RDMA_USER_CM_CMD_GET_OPTION,
RDMA_USER_CM_CMD_SET_OPTION, RDMA_USER_CM_CMD_SET_OPTION,
RDMA_USER_CM_CMD_NOTIFY RDMA_USER_CM_CMD_NOTIFY,
RDMA_USER_CM_CMD_JOIN_MCAST,
RDMA_USER_CM_CMD_LEAVE_MCAST
}; };
/* /*
...@@ -188,6 +190,13 @@ struct rdma_ucm_notify { ...@@ -188,6 +190,13 @@ struct rdma_ucm_notify {
__u32 event; __u32 event;
}; };
struct rdma_ucm_join_mcast {
__u64 response; /* rdma_ucm_create_id_resp */
__u64 uid;
struct sockaddr_in6 addr;
__u32 id;
};
struct rdma_ucm_get_event { struct rdma_ucm_get_event {
__u64 response; __u64 response;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment