aboutsummaryrefslogtreecommitdiff
path: root/drivers/infiniband/core/user_mad.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/core/user_mad.c')
-rw-r--r--drivers/infiniband/core/user_mad.c448
1 files changed, 240 insertions, 208 deletions
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index b53eac4611d..1acb9910055 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -2,6 +2,7 @@
* Copyright (c) 2004 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2008 Cisco. 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
@@ -30,8 +31,6 @@
* 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.
- *
- * $Id: user_mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
*/
#include <linux/module.h>
@@ -42,12 +41,14 @@
#include <linux/cdev.h>
#include <linux/dma-mapping.h>
#include <linux/poll.h>
-#include <linux/rwsem.h>
+#include <linux/mutex.h>
#include <linux/kref.h>
#include <linux/compat.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
#include <asm/uaccess.h>
-#include <asm/semaphore.h>
#include <rdma/ib_mad.h>
#include <rdma/ib_user_mad.h>
@@ -65,12 +66,9 @@ enum {
};
/*
- * Our lifetime rules for these structs are the following: each time a
- * device special file is opened, we look up the corresponding struct
- * ib_umad_port by minor in the umad_port[] table while holding the
- * port_lock. If this lookup succeeds, we take a reference on the
- * ib_umad_port's struct ib_umad_device while still holding the
- * port_lock; if the lookup fails, we fail the open(). We drop these
+ * Our lifetime rules for these structs are the following:
+ * device special file is opened, we take a reference on the
+ * ib_umad_port's struct ib_umad_device. We drop these
* references in the corresponding close().
*
* In addition to references coming from open character devices, there
@@ -78,23 +76,18 @@ enum {
* module's reference taken when allocating the ib_umad_device in
* ib_umad_add_one().
*
- * When destroying an ib_umad_device, we clear all of its
- * ib_umad_ports from umad_port[] while holding port_lock before
- * dropping the module's reference to the ib_umad_device. This is
- * always safe because any open() calls will either succeed and obtain
- * a reference before we clear the umad_port[] entries, or fail after
- * we clear the umad_port[] entries.
+ * When destroying an ib_umad_device, we drop the module's reference.
*/
struct ib_umad_port {
- struct cdev *dev;
- struct class_device *class_dev;
+ struct cdev cdev;
+ struct device *dev;
- struct cdev *sm_dev;
- struct class_device *sm_class_dev;
+ struct cdev sm_cdev;
+ struct device *sm_dev;
struct semaphore sm_sem;
- struct rw_semaphore mutex;
+ struct mutex file_mutex;
struct list_head file_list;
struct ib_device *ib_dev;
@@ -105,16 +98,16 @@ struct ib_umad_port {
struct ib_umad_device {
int start_port, end_port;
- struct kref ref;
+ struct kobject kobj;
struct ib_umad_port port[0];
};
struct ib_umad_file {
+ struct mutex mutex;
struct ib_umad_port *port;
struct list_head recv_list;
struct list_head send_list;
struct list_head port_list;
- spinlock_t recv_lock;
spinlock_t send_lock;
wait_queue_head_t recv_wait;
struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS];
@@ -136,27 +129,30 @@ static struct class *umad_class;
static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE);
static DEFINE_SPINLOCK(port_lock);
-static struct ib_umad_port *umad_port[IB_UMAD_MAX_PORTS];
static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS);
static void ib_umad_add_one(struct ib_device *device);
static void ib_umad_remove_one(struct ib_device *device);
-static void ib_umad_release_dev(struct kref *ref)
+static void ib_umad_release_dev(struct kobject *kobj)
{
struct ib_umad_device *dev =
- container_of(ref, struct ib_umad_device, ref);
+ container_of(kobj, struct ib_umad_device, kobj);
kfree(dev);
}
+static struct kobj_type ib_umad_dev_ktype = {
+ .release = ib_umad_release_dev,
+};
+
static int hdr_size(struct ib_umad_file *file)
{
return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) :
sizeof (struct ib_user_mad_hdr_old);
}
-/* caller must hold port->mutex at least for reading */
+/* caller must hold file->mutex */
static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
{
return file->agents_dead ? NULL : file->agent[id];
@@ -168,32 +164,30 @@ static int queue_packet(struct ib_umad_file *file,
{
int ret = 1;
- down_read(&file->port->mutex);
+ mutex_lock(&file->mutex);
for (packet->mad.hdr.id = 0;
packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
packet->mad.hdr.id++)
if (agent == __get_agent(file, packet->mad.hdr.id)) {
- spin_lock_irq(&file->recv_lock);
list_add_tail(&packet->list, &file->recv_list);
- spin_unlock_irq(&file->recv_lock);
wake_up_interruptible(&file->recv_wait);
ret = 0;
break;
}
- up_read(&file->port->mutex);
+ mutex_unlock(&file->mutex);
return ret;
}
static void dequeue_send(struct ib_umad_file *file,
struct ib_umad_packet *packet)
- {
+{
spin_lock_irq(&file->send_lock);
list_del(&packet->list);
spin_unlock_irq(&file->send_lock);
- }
+}
static void send_handler(struct ib_mad_agent *agent,
struct ib_mad_send_wc *send_wc)
@@ -341,10 +335,10 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
if (count < hdr_size(file))
return -EINVAL;
- spin_lock_irq(&file->recv_lock);
+ mutex_lock(&file->mutex);
while (list_empty(&file->recv_list)) {
- spin_unlock_irq(&file->recv_lock);
+ mutex_unlock(&file->mutex);
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
@@ -353,13 +347,13 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
!list_empty(&file->recv_list)))
return -ERESTARTSYS;
- spin_lock_irq(&file->recv_lock);
+ mutex_lock(&file->mutex);
}
packet = list_entry(file->recv_list.next, struct ib_umad_packet, list);
list_del(&packet->list);
- spin_unlock_irq(&file->recv_lock);
+ mutex_unlock(&file->mutex);
if (packet->recv_wc)
ret = copy_recv_mad(file, buf, packet, count);
@@ -368,9 +362,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
if (ret < 0) {
/* Requeue packet */
- spin_lock_irq(&file->recv_lock);
+ mutex_lock(&file->mutex);
list_add(&packet->list, &file->recv_list);
- spin_unlock_irq(&file->recv_lock);
+ mutex_unlock(&file->mutex);
} else {
if (packet->recv_wc)
ib_free_recv_mad(packet->recv_wc);
@@ -468,8 +462,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
goto err;
}
- if (packet->mad.hdr.id < 0 ||
- packet->mad.hdr.id >= IB_UMAD_MAX_AGENTS) {
+ if (packet->mad.hdr.id >= IB_UMAD_MAX_AGENTS) {
ret = -EINVAL;
goto err;
}
@@ -481,7 +474,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
goto err;
}
- down_read(&file->port->mutex);
+ mutex_lock(&file->mutex);
agent = __get_agent(file, packet->mad.hdr.id);
if (!agent) {
@@ -498,8 +491,8 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
ah_attr.ah_flags = IB_AH_GRH;
memcpy(ah_attr.grh.dgid.raw, packet->mad.hdr.gid, 16);
ah_attr.grh.sgid_index = packet->mad.hdr.gid_index;
- ah_attr.grh.flow_label = be32_to_cpu(packet->mad.hdr.flow_label);
- ah_attr.grh.hop_limit = packet->mad.hdr.hop_limit;
+ ah_attr.grh.flow_label = be32_to_cpu(packet->mad.hdr.flow_label);
+ ah_attr.grh.hop_limit = packet->mad.hdr.hop_limit;
ah_attr.grh.traffic_class = packet->mad.hdr.traffic_class;
}
@@ -530,9 +523,9 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
goto err_ah;
}
- packet->msg->ah = ah;
+ packet->msg->ah = ah;
packet->msg->timeout_ms = packet->mad.hdr.timeout_ms;
- packet->msg->retries = packet->mad.hdr.retries;
+ packet->msg->retries = packet->mad.hdr.retries;
packet->msg->context[0] = packet;
/* Copy MAD header. Any RMPP header is already in place. */
@@ -577,7 +570,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
if (ret)
goto err_send;
- up_read(&file->port->mutex);
+ mutex_unlock(&file->mutex);
return count;
err_send:
@@ -587,7 +580,7 @@ err_msg:
err_ah:
ib_destroy_ah(ah);
err_up:
- up_read(&file->port->mutex);
+ mutex_unlock(&file->mutex);
err:
kfree(packet);
return ret;
@@ -613,11 +606,12 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
{
struct ib_user_mad_reg_req ureq;
struct ib_mad_reg_req req;
- struct ib_mad_agent *agent;
+ struct ib_mad_agent *agent = NULL;
int agent_id;
int ret;
- down_write(&file->port->mutex);
+ mutex_lock(&file->port->file_mutex);
+ mutex_lock(&file->mutex);
if (!file->port->ib_dev) {
ret = -EPIPE;
@@ -666,13 +660,13 @@ found:
send_handler, recv_handler, file);
if (IS_ERR(agent)) {
ret = PTR_ERR(agent);
+ agent = NULL;
goto out;
}
if (put_user(agent_id,
(u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) {
ret = -EFAULT;
- ib_unregister_mad_agent(agent);
goto out;
}
@@ -690,7 +684,13 @@ found:
ret = 0;
out:
- up_write(&file->port->mutex);
+ mutex_unlock(&file->mutex);
+
+ if (ret && agent)
+ ib_unregister_mad_agent(agent);
+
+ mutex_unlock(&file->port->file_mutex);
+
return ret;
}
@@ -703,9 +703,10 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
if (get_user(id, arg))
return -EFAULT;
- down_write(&file->port->mutex);
+ mutex_lock(&file->port->file_mutex);
+ mutex_lock(&file->mutex);
- if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
+ if (id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
ret = -EINVAL;
goto out;
}
@@ -714,11 +715,13 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
file->agent[id] = NULL;
out:
- up_write(&file->port->mutex);
+ mutex_unlock(&file->mutex);
if (agent)
ib_unregister_mad_agent(agent);
+ mutex_unlock(&file->port->file_mutex);
+
return ret;
}
@@ -726,12 +729,12 @@ static long ib_umad_enable_pkey(struct ib_umad_file *file)
{
int ret = 0;
- down_write(&file->port->mutex);
+ mutex_lock(&file->mutex);
if (file->already_used)
ret = -EINVAL;
else
file->use_pkey_index = 1;
- up_write(&file->port->mutex);
+ mutex_unlock(&file->mutex);
return ret;
}
@@ -768,36 +771,34 @@ static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd,
}
#endif
+/*
+ * ib_umad_open() does not need the BKL:
+ *
+ * - the ib_umad_port structures are properly reference counted, and
+ * everything else is purely local to the file being created, so
+ * races against other open calls are not a problem;
+ * - the ioctl method does not affect any global state outside of the
+ * file structure being operated on;
+ */
static int ib_umad_open(struct inode *inode, struct file *filp)
{
struct ib_umad_port *port;
struct ib_umad_file *file;
- int ret = 0;
+ int ret = -ENXIO;
- spin_lock(&port_lock);
- port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE];
- if (port)
- kref_get(&port->umad_dev->ref);
- spin_unlock(&port_lock);
+ port = container_of(inode->i_cdev, struct ib_umad_port, cdev);
- if (!port)
- return -ENXIO;
-
- down_write(&port->mutex);
+ mutex_lock(&port->file_mutex);
- if (!port->ib_dev) {
- ret = -ENXIO;
+ if (!port->ib_dev)
goto out;
- }
+ ret = -ENOMEM;
file = kzalloc(sizeof *file, GFP_KERNEL);
- if (!file) {
- kref_put(&port->umad_dev->ref, ib_umad_release_dev);
- ret = -ENOMEM;
+ if (!file)
goto out;
- }
- spin_lock_init(&file->recv_lock);
+ mutex_init(&file->mutex);
spin_lock_init(&file->send_lock);
INIT_LIST_HEAD(&file->recv_list);
INIT_LIST_HEAD(&file->send_list);
@@ -808,8 +809,17 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
list_add_tail(&file->port_list, &port->file_list);
+ ret = nonseekable_open(inode, filp);
+ if (ret) {
+ list_del(&file->port_list);
+ kfree(file);
+ goto out;
+ }
+
+ kobject_get(&port->umad_dev->kobj);
+
out:
- up_write(&port->mutex);
+ mutex_unlock(&port->file_mutex);
return ret;
}
@@ -821,7 +831,8 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
int already_dead;
int i;
- down_write(&file->port->mutex);
+ mutex_lock(&file->port->file_mutex);
+ mutex_lock(&file->mutex);
already_dead = file->agents_dead;
file->agents_dead = 1;
@@ -834,32 +845,33 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
list_del(&file->port_list);
- downgrade_write(&file->port->mutex);
+ mutex_unlock(&file->mutex);
if (!already_dead)
for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
if (file->agent[i])
ib_unregister_mad_agent(file->agent[i]);
- up_read(&file->port->mutex);
+ mutex_unlock(&file->port->file_mutex);
kfree(file);
- kref_put(&dev->ref, ib_umad_release_dev);
+ kobject_put(&dev->kobj);
return 0;
}
static const struct file_operations umad_fops = {
- .owner = THIS_MODULE,
- .read = ib_umad_read,
- .write = ib_umad_write,
- .poll = ib_umad_poll,
+ .owner = THIS_MODULE,
+ .read = ib_umad_read,
+ .write = ib_umad_write,
+ .poll = ib_umad_poll,
.unlocked_ioctl = ib_umad_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = ib_umad_compat_ioctl,
+ .compat_ioctl = ib_umad_compat_ioctl,
#endif
- .open = ib_umad_open,
- .release = ib_umad_close
+ .open = ib_umad_open,
+ .release = ib_umad_close,
+ .llseek = no_llseek,
};
static int ib_umad_sm_open(struct inode *inode, struct file *filp)
@@ -870,14 +882,7 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp)
};
int ret;
- spin_lock(&port_lock);
- port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE - IB_UMAD_MAX_PORTS];
- if (port)
- kref_get(&port->umad_dev->ref);
- spin_unlock(&port_lock);
-
- if (!port)
- return -ENXIO;
+ port = container_of(inode->i_cdev, struct ib_umad_port, sm_cdev);
if (filp->f_flags & O_NONBLOCK) {
if (down_trylock(&port->sm_sem)) {
@@ -892,17 +897,27 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp)
}
ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
- if (ret) {
- up(&port->sm_sem);
- goto fail;
- }
+ if (ret)
+ goto err_up_sem;
filp->private_data = port;
+ ret = nonseekable_open(inode, filp);
+ if (ret)
+ goto err_clr_sm_cap;
+
+ kobject_get(&port->umad_dev->kobj);
+
return 0;
+err_clr_sm_cap:
+ swap(props.set_port_cap_mask, props.clr_port_cap_mask);
+ ib_modify_port(port->ib_dev, port->port_num, 0, &props);
+
+err_up_sem:
+ up(&port->sm_sem);
+
fail:
- kref_put(&port->umad_dev->ref, ib_umad_release_dev);
return ret;
}
@@ -914,22 +929,23 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp)
};
int ret = 0;
- down_write(&port->mutex);
+ mutex_lock(&port->file_mutex);
if (port->ib_dev)
ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
- up_write(&port->mutex);
+ mutex_unlock(&port->file_mutex);
up(&port->sm_sem);
- kref_put(&port->umad_dev->ref, ib_umad_release_dev);
+ kobject_put(&port->umad_dev->kobj);
return ret;
}
static const struct file_operations umad_sm_fops = {
- .owner = THIS_MODULE,
- .open = ib_umad_sm_open,
- .release = ib_umad_sm_close
+ .owner = THIS_MODULE,
+ .open = ib_umad_sm_open,
+ .release = ib_umad_sm_close,
+ .llseek = no_llseek,
};
static struct ib_client umad_client = {
@@ -938,113 +954,141 @@ static struct ib_client umad_client = {
.remove = ib_umad_remove_one
};
-static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
+static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct ib_umad_port *port = class_get_devdata(class_dev);
+ struct ib_umad_port *port = dev_get_drvdata(dev);
if (!port)
return -ENODEV;
return sprintf(buf, "%s\n", port->ib_dev->name);
}
-static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
+static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
-static ssize_t show_port(struct class_device *class_dev, char *buf)
+static ssize_t show_port(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct ib_umad_port *port = class_get_devdata(class_dev);
+ struct ib_umad_port *port = dev_get_drvdata(dev);
if (!port)
return -ENODEV;
return sprintf(buf, "%d\n", port->port_num);
}
-static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
+static DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
-static ssize_t show_abi_version(struct class *class, char *buf)
+static CLASS_ATTR_STRING(abi_version, S_IRUGO,
+ __stringify(IB_USER_MAD_ABI_VERSION));
+
+static dev_t overflow_maj;
+static DECLARE_BITMAP(overflow_map, IB_UMAD_MAX_PORTS);
+static int find_overflow_devnum(void)
{
- return sprintf(buf, "%d\n", IB_USER_MAD_ABI_VERSION);
+ int ret;
+
+ if (!overflow_maj) {
+ ret = alloc_chrdev_region(&overflow_maj, 0, IB_UMAD_MAX_PORTS * 2,
+ "infiniband_mad");
+ if (ret) {
+ printk(KERN_ERR "user_mad: couldn't register dynamic device number\n");
+ return ret;
+ }
+ }
+
+ ret = find_first_zero_bit(overflow_map, IB_UMAD_MAX_PORTS);
+ if (ret >= IB_UMAD_MAX_PORTS)
+ return -1;
+
+ return ret;
}
-static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
static int ib_umad_init_port(struct ib_device *device, int port_num,
+ struct ib_umad_device *umad_dev,
struct ib_umad_port *port)
{
+ int devnum;
+ dev_t base;
+
spin_lock(&port_lock);
- port->dev_num = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS);
- if (port->dev_num >= IB_UMAD_MAX_PORTS) {
+ devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS);
+ if (devnum >= IB_UMAD_MAX_PORTS) {
spin_unlock(&port_lock);
- return -1;
+ devnum = find_overflow_devnum();
+ if (devnum < 0)
+ return -1;
+
+ spin_lock(&port_lock);
+ port->dev_num = devnum + IB_UMAD_MAX_PORTS;
+ base = devnum + overflow_maj;
+ set_bit(devnum, overflow_map);
+ } else {
+ port->dev_num = devnum;
+ base = devnum + base_dev;
+ set_bit(devnum, dev_map);
}
- set_bit(port->dev_num, dev_map);
spin_unlock(&port_lock);
port->ib_dev = device;
port->port_num = port_num;
- init_MUTEX(&port->sm_sem);
- init_rwsem(&port->mutex);
+ sema_init(&port->sm_sem, 1);
+ mutex_init(&port->file_mutex);
INIT_LIST_HEAD(&port->file_list);
- port->dev = cdev_alloc();
- if (!port->dev)
- return -1;
- port->dev->owner = THIS_MODULE;
- port->dev->ops = &umad_fops;
- kobject_set_name(&port->dev->kobj, "umad%d", port->dev_num);
- if (cdev_add(port->dev, base_dev + port->dev_num, 1))
+ cdev_init(&port->cdev, &umad_fops);
+ port->cdev.owner = THIS_MODULE;
+ port->cdev.kobj.parent = &umad_dev->kobj;
+ kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num);
+ if (cdev_add(&port->cdev, base, 1))
goto err_cdev;
- port->class_dev = class_device_create(umad_class, NULL, port->dev->dev,
- device->dma_device,
- "umad%d", port->dev_num);
- if (IS_ERR(port->class_dev))
+ port->dev = device_create(umad_class, device->dma_device,
+ port->cdev.dev, port,
+ "umad%d", port->dev_num);
+ if (IS_ERR(port->dev))
goto err_cdev;
- if (class_device_create_file(port->class_dev, &class_device_attr_ibdev))
- goto err_class;
- if (class_device_create_file(port->class_dev, &class_device_attr_port))
- goto err_class;
-
- port->sm_dev = cdev_alloc();
- if (!port->sm_dev)
- goto err_class;
- port->sm_dev->owner = THIS_MODULE;
- port->sm_dev->ops = &umad_sm_fops;
- kobject_set_name(&port->sm_dev->kobj, "issm%d", port->dev_num);
- if (cdev_add(port->sm_dev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1))
+ if (device_create_file(port->dev, &dev_attr_ibdev))
+ goto err_dev;
+ if (device_create_file(port->dev, &dev_attr_port))
+ goto err_dev;
+
+ base += IB_UMAD_MAX_PORTS;
+ cdev_init(&port->sm_cdev, &umad_sm_fops);
+ port->sm_cdev.owner = THIS_MODULE;
+ port->sm_cdev.kobj.parent = &umad_dev->kobj;
+ kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num);
+ if (cdev_add(&port->sm_cdev, base, 1))
goto err_sm_cdev;
- port->sm_class_dev = class_device_create(umad_class, NULL, port->sm_dev->dev,
- device->dma_device,
- "issm%d", port->dev_num);
- if (IS_ERR(port->sm_class_dev))
+ port->sm_dev = device_create(umad_class, device->dma_device,
+ port->sm_cdev.dev, port,
+ "issm%d", port->dev_num);
+ if (IS_ERR(port->sm_dev))
goto err_sm_cdev;
- class_set_devdata(port->class_dev, port);
- class_set_devdata(port->sm_class_dev, port);
-
- if (class_device_create_file(port->sm_class_dev, &class_device_attr_ibdev))
- goto err_sm_class;
- if (class_device_create_file(port->sm_class_dev, &class_device_attr_port))
- goto err_sm_class;
-
- spin_lock(&port_lock);
- umad_port[port->dev_num] = port;
- spin_unlock(&port_lock);
+ if (device_create_file(port->sm_dev, &dev_attr_ibdev))
+ goto err_sm_dev;
+ if (device_create_file(port->sm_dev, &dev_attr_port))
+ goto err_sm_dev;
return 0;
-err_sm_class:
- class_device_destroy(umad_class, port->sm_dev->dev);
+err_sm_dev:
+ device_destroy(umad_class, port->sm_cdev.dev);
err_sm_cdev:
- cdev_del(port->sm_dev);
+ cdev_del(&port->sm_cdev);
-err_class:
- class_device_destroy(umad_class, port->dev->dev);
+err_dev:
+ device_destroy(umad_class, port->cdev.dev);
err_cdev:
- cdev_del(port->dev);
- clear_bit(port->dev_num, dev_map);
+ cdev_del(&port->cdev);
+ if (port->dev_num < IB_UMAD_MAX_PORTS)
+ clear_bit(devnum, dev_map);
+ else
+ clear_bit(devnum, overflow_map);
return -1;
}
@@ -1054,57 +1098,35 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
struct ib_umad_file *file;
int id;
- class_set_devdata(port->class_dev, NULL);
- class_set_devdata(port->sm_class_dev, NULL);
+ dev_set_drvdata(port->dev, NULL);
+ dev_set_drvdata(port->sm_dev, NULL);
- class_device_destroy(umad_class, port->dev->dev);
- class_device_destroy(umad_class, port->sm_dev->dev);
+ device_destroy(umad_class, port->cdev.dev);
+ device_destroy(umad_class, port->sm_cdev.dev);
- cdev_del(port->dev);
- cdev_del(port->sm_dev);
+ cdev_del(&port->cdev);
+ cdev_del(&port->sm_cdev);
- spin_lock(&port_lock);
- umad_port[port->dev_num] = NULL;
- spin_unlock(&port_lock);
-
- down_write(&port->mutex);
+ mutex_lock(&port->file_mutex);
port->ib_dev = NULL;
- /*
- * Now go through the list of files attached to this port and
- * unregister all of their MAD agents. We need to hold
- * port->mutex while doing this to avoid racing with
- * ib_umad_close(), but we can't hold the mutex for writing
- * while calling ib_unregister_mad_agent(), since that might
- * deadlock by calling back into queue_packet(). So we
- * downgrade our lock to a read lock, and then drop and
- * reacquire the write lock for the next iteration.
- *
- * We do list_del_init() on the file's list_head so that the
- * list_del in ib_umad_close() is still OK, even after the
- * file is removed from the list.
- */
- while (!list_empty(&port->file_list)) {
- file = list_entry(port->file_list.next, struct ib_umad_file,
- port_list);
-
+ list_for_each_entry(file, &port->file_list, port_list) {
+ mutex_lock(&file->mutex);
file->agents_dead = 1;
- list_del_init(&file->port_list);
-
- downgrade_write(&port->mutex);
+ mutex_unlock(&file->mutex);
for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
if (file->agent[id])
ib_unregister_mad_agent(file->agent[id]);
-
- up_read(&port->mutex);
- down_write(&port->mutex);
}
- up_write(&port->mutex);
+ mutex_unlock(&port->file_mutex);
- clear_bit(port->dev_num, dev_map);
+ if (port->dev_num < IB_UMAD_MAX_PORTS)
+ clear_bit(port->dev_num, dev_map);
+ else
+ clear_bit(port->dev_num - IB_UMAD_MAX_PORTS, overflow_map);
}
static void ib_umad_add_one(struct ib_device *device)
@@ -1128,7 +1150,7 @@ static void ib_umad_add_one(struct ib_device *device)
if (!umad_dev)
return;
- kref_init(&umad_dev->ref);
+ kobject_init(&umad_dev->kobj, &ib_umad_dev_ktype);
umad_dev->start_port = s;
umad_dev->end_port = e;
@@ -1136,7 +1158,8 @@ static void ib_umad_add_one(struct ib_device *device)
for (i = s; i <= e; ++i) {
umad_dev->port[i - s].umad_dev = umad_dev;
- if (ib_umad_init_port(device, i, &umad_dev->port[i - s]))
+ if (ib_umad_init_port(device, i, umad_dev,
+ &umad_dev->port[i - s]))
goto err;
}
@@ -1148,7 +1171,7 @@ err:
while (--i >= s)
ib_umad_kill_port(&umad_dev->port[i - s]);
- kref_put(&umad_dev->ref, ib_umad_release_dev);
+ kobject_put(&umad_dev->kobj);
}
static void ib_umad_remove_one(struct ib_device *device)
@@ -1162,7 +1185,12 @@ static void ib_umad_remove_one(struct ib_device *device)
for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i)
ib_umad_kill_port(&umad_dev->port[i]);
- kref_put(&umad_dev->ref, ib_umad_release_dev);
+ kobject_put(&umad_dev->kobj);
+}
+
+static char *umad_devnode(struct device *dev, umode_t *mode)
+{
+ return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
}
static int __init ib_umad_init(void)
@@ -1183,7 +1211,9 @@ static int __init ib_umad_init(void)
goto out_chrdev;
}
- ret = class_create_file(umad_class, &class_attr_abi_version);
+ umad_class->devnode = umad_devnode;
+
+ ret = class_create_file(umad_class, &class_attr_abi_version.attr);
if (ret) {
printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n");
goto out_class;
@@ -1212,6 +1242,8 @@ static void __exit ib_umad_cleanup(void)
ib_unregister_client(&umad_client);
class_destroy(umad_class);
unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2);
+ if (overflow_maj)
+ unregister_chrdev_region(overflow_maj, IB_UMAD_MAX_PORTS * 2);
}
module_init(ib_umad_init);