/*
* Copyright (c) 2005 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. 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
DEFINE_IDR(ib_uverbs_ah_idr);
DEFINE_IDR(ib_uverbs_cq_idr);
DEFINE_IDR(ib_uverbs_qp_idr);
+DEFINE_IDR(ib_uverbs_srq_idr);
static spinlock_t map_lock;
static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
[IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp,
[IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast,
[IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast,
+ [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq,
+ [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq,
+ [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq,
};
static struct vfsmount *uverbs_event_mnt;
idr_remove(&ib_uverbs_qp_idr, uobj->id);
ib_destroy_qp(qp);
list_del(&uobj->list);
- kfree(uobj);
+ kfree(container_of(uobj, struct ib_uevent_object, uobject));
}
list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) {
idr_remove(&ib_uverbs_cq_idr, uobj->id);
ib_destroy_cq(cq);
list_del(&uobj->list);
- kfree(uobj);
+ kfree(container_of(uobj, struct ib_ucq_object, uobject));
+ }
+
+ list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) {
+ struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id);
+ idr_remove(&ib_uverbs_srq_idr, uobj->id);
+ ib_destroy_srq(srq);
+ list_del(&uobj->list);
+ kfree(container_of(uobj, struct ib_uevent_object, uobject));
}
- /* XXX Free SRQs */
/* XXX Free MWs */
list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
size_t count, loff_t *pos)
{
struct ib_uverbs_event_file *file = filp->private_data;
- void *event;
+ struct ib_uverbs_event *event;
int eventsz;
int ret = 0;
return -ENODEV;
}
- if (file->is_async) {
- event = list_entry(file->event_list.next,
- struct ib_uverbs_async_event, list);
+ event = list_entry(file->event_list.next, struct ib_uverbs_event, list);
+
+ if (file->is_async)
eventsz = sizeof (struct ib_uverbs_async_event_desc);
- } else {
- event = list_entry(file->event_list.next,
- struct ib_uverbs_comp_event, list);
+ else
eventsz = sizeof (struct ib_uverbs_comp_event_desc);
- }
if (eventsz > count) {
ret = -EINVAL;
event = NULL;
- } else
+ } else {
list_del(file->event_list.next);
+ if (event->counter) {
+ ++(*event->counter);
+ list_del(&event->obj_list);
+ }
+ }
spin_unlock_irq(&file->lock);
static void ib_uverbs_event_release(struct ib_uverbs_event_file *file)
{
- struct list_head *entry, *tmp;
+ struct ib_uverbs_event *entry, *tmp;
spin_lock_irq(&file->lock);
if (file->fd != -1) {
file->fd = -1;
- list_for_each_safe(entry, tmp, &file->event_list)
- if (file->is_async)
- kfree(list_entry(entry, struct ib_uverbs_async_event, list));
- else
- kfree(list_entry(entry, struct ib_uverbs_comp_event, list));
+ list_for_each_entry_safe(entry, tmp, &file->event_list, list)
+ kfree(entry);
}
spin_unlock_irq(&file->lock);
}
void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context)
{
- struct ib_uverbs_file *file = cq_context;
- struct ib_uverbs_comp_event *entry;
- unsigned long flags;
+ struct ib_uverbs_file *file = cq_context;
+ struct ib_ucq_object *uobj;
+ struct ib_uverbs_event *entry;
+ unsigned long flags;
entry = kmalloc(sizeof *entry, GFP_ATOMIC);
if (!entry)
return;
- entry->desc.cq_handle = cq->uobject->user_handle;
+ uobj = container_of(cq->uobject, struct ib_ucq_object, uobject);
+
+ entry->desc.comp.cq_handle = cq->uobject->user_handle;
+ entry->counter = &uobj->comp_events_reported;
spin_lock_irqsave(&file->comp_file[0].lock, flags);
list_add_tail(&entry->list, &file->comp_file[0].event_list);
+ list_add_tail(&entry->obj_list, &uobj->comp_list);
spin_unlock_irqrestore(&file->comp_file[0].lock, flags);
wake_up_interruptible(&file->comp_file[0].poll_wait);
}
static void ib_uverbs_async_handler(struct ib_uverbs_file *file,
- __u64 element, __u64 event)
+ __u64 element, __u64 event,
+ struct list_head *obj_list,
+ u32 *counter)
{
- struct ib_uverbs_async_event *entry;
+ struct ib_uverbs_event *entry;
unsigned long flags;
entry = kmalloc(sizeof *entry, GFP_ATOMIC);
if (!entry)
return;
- entry->desc.element = element;
- entry->desc.event_type = event;
+ entry->desc.async.element = element;
+ entry->desc.async.event_type = event;
+ entry->counter = counter;
spin_lock_irqsave(&file->async_file.lock, flags);
list_add_tail(&entry->list, &file->async_file.event_list);
+ if (obj_list)
+ list_add_tail(&entry->obj_list, obj_list);
spin_unlock_irqrestore(&file->async_file.lock, flags);
wake_up_interruptible(&file->async_file.poll_wait);
void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr)
{
- ib_uverbs_async_handler(context_ptr,
- event->element.cq->uobject->user_handle,
- event->event);
+ struct ib_ucq_object *uobj;
+
+ uobj = container_of(event->element.cq->uobject,
+ struct ib_ucq_object, uobject);
+
+ ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle,
+ event->event, &uobj->async_list,
+ &uobj->async_events_reported);
+
}
void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
{
- ib_uverbs_async_handler(context_ptr,
- event->element.qp->uobject->user_handle,
- event->event);
+ struct ib_uevent_object *uobj;
+
+ uobj = container_of(event->element.qp->uobject,
+ struct ib_uevent_object, uobject);
+
+ ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle,
+ event->event, &uobj->event_list,
+ &uobj->events_reported);
+}
+
+void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr)
+{
+ struct ib_uevent_object *uobj;
+
+ uobj = container_of(event->element.srq->uobject,
+ struct ib_uevent_object, uobject);
+
+ ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle,
+ event->event, &uobj->event_list,
+ &uobj->events_reported);
}
static void ib_uverbs_event_handler(struct ib_event_handler *handler,
struct ib_uverbs_file *file =
container_of(handler, struct ib_uverbs_file, event_handler);
- ib_uverbs_async_handler(file, event->element.port_num, event->event);
+ ib_uverbs_async_handler(file, event->element.port_num, event->event,
+ NULL, NULL);
}
static int ib_uverbs_event_init(struct ib_uverbs_event_file *file,
if (hdr.in_words * 4 != count)
return -EINVAL;
- if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table))
+ if (hdr.command < 0 ||
+ hdr.command >= ARRAY_SIZE(uverbs_cmd_table) ||
+ !uverbs_cmd_table[hdr.command])
return -EINVAL;
if (!file->ucontext &&
file = kmalloc(sizeof *file +
(dev->num_comp - 1) * sizeof (struct ib_uverbs_event_file),
GFP_KERNEL);
- if (!file)
- return -ENOMEM;
+ if (!file) {
+ ret = -ENOMEM;
+ goto err;
+ }
file->device = dev;
kref_init(&file->ref);
+ init_MUTEX(&file->mutex);
file->ucontext = NULL;
+ kref_get(&file->ref);
ret = ib_uverbs_event_init(&file->async_file, file);
if (ret)
- goto err;
+ goto err_kref;
file->async_file.is_async = 1;
- kref_get(&file->ref);
-
for (i = 0; i < dev->num_comp; ++i) {
+ kref_get(&file->ref);
ret = ib_uverbs_event_init(&file->comp_file[i], file);
if (ret)
goto err_async;
- kref_get(&file->ref);
file->comp_file[i].is_async = 0;
}
ib_uverbs_event_release(&file->async_file);
-err:
+err_kref:
+ /*
+ * One extra kref_put() because we took a reference before the
+ * event file creation that failed and got us here.
+ */
+ kref_put(&file->ref, ib_uverbs_release_file);
kref_put(&file->ref, ib_uverbs_release_file);
+err:
+ module_put(dev->ib_dev->owner);
return ret;
}