IB/hfi1: Add ioctl() interface for user commands
[deliverable/linux.git] / drivers / staging / rdma / hfi1 / file_ops.c
index 8396dc5fb6c1899bc32b775e19877b00bfd0151f..a338238bef92df7b2277cf1eb8e043b9ad1e60fe 100644 (file)
@@ -49,6 +49,8 @@
 #include <linux/vmalloc.h>
 #include <linux/io.h>
 
+#include <rdma/ib.h>
+
 #include "hfi.h"
 #include "pio.h"
 #include "device.h"
@@ -84,8 +86,7 @@ static int get_ctxt_info(struct file *, void __user *, __u32);
 static int get_base_info(struct file *, void __user *, __u32);
 static int setup_ctxt(struct file *);
 static int setup_subctxt(struct hfi1_ctxtdata *);
-static int get_user_context(struct file *, struct hfi1_user_info *,
-                           int, unsigned);
+static int get_user_context(struct file *, struct hfi1_user_info *, int);
 static int find_shared_ctxt(struct file *, const struct hfi1_user_info *);
 static int allocate_ctxt(struct file *, struct hfi1_devdata *,
                         struct hfi1_user_info *);
@@ -95,6 +96,8 @@ static int user_event_ack(struct hfi1_ctxtdata *, int, unsigned long);
 static int set_ctxt_pkey(struct hfi1_ctxtdata *, unsigned, u16);
 static int manage_rcvq(struct hfi1_ctxtdata *, unsigned, int);
 static int vma_fault(struct vm_area_struct *, struct vm_fault *);
+static long hfi1_file_ioctl(struct file *fp, unsigned int cmd,
+                           unsigned long arg);
 
 static const struct file_operations hfi1_file_ops = {
        .owner = THIS_MODULE,
@@ -102,6 +105,7 @@ static const struct file_operations hfi1_file_ops = {
        .write_iter = hfi1_write_iter,
        .open = hfi1_file_open,
        .release = hfi1_file_close,
+       .unlocked_ioctl = hfi1_file_ioctl,
        .poll = hfi1_poll,
        .mmap = hfi1_file_mmap,
        .llseek = noop_llseek,
@@ -174,6 +178,207 @@ static int hfi1_file_open(struct inode *inode, struct file *fp)
        return fp->private_data ? 0 : -ENOMEM;
 }
 
+static long hfi1_file_ioctl(struct file *fp, unsigned int cmd,
+                           unsigned long arg)
+{
+       struct hfi1_filedata *fd = fp->private_data;
+       struct hfi1_ctxtdata *uctxt = fd->uctxt;
+       struct hfi1_user_info uinfo;
+       struct hfi1_tid_info tinfo;
+       int ret = 0;
+       unsigned long addr;
+       int uval = 0;
+       unsigned long ul_uval = 0;
+       u16 uval16 = 0;
+
+       if (cmd != HFI1_IOCTL_ASSIGN_CTXT &&
+           cmd != HFI1_IOCTL_GET_VERS &&
+           !uctxt)
+               return -EINVAL;
+
+       switch (cmd) {
+       case HFI1_IOCTL_ASSIGN_CTXT:
+               if (copy_from_user(&uinfo,
+                                  (struct hfi1_user_info __user *)arg,
+                                  sizeof(uinfo)))
+                       return -EFAULT;
+
+               ret = assign_ctxt(fp, &uinfo);
+               if (ret < 0)
+                       return ret;
+               setup_ctxt(fp);
+               if (ret)
+                       return ret;
+               ret = user_init(fp);
+               break;
+       case HFI1_IOCTL_CTXT_INFO:
+               ret = get_ctxt_info(fp, (void __user *)(unsigned long)arg,
+                                   sizeof(struct hfi1_ctxt_info));
+               break;
+       case HFI1_IOCTL_USER_INFO:
+               ret = get_base_info(fp, (void __user *)(unsigned long)arg,
+                                   sizeof(struct hfi1_base_info));
+               break;
+       case HFI1_IOCTL_CREDIT_UPD:
+               if (uctxt && uctxt->sc)
+                       sc_return_credits(uctxt->sc);
+               break;
+
+       case HFI1_IOCTL_TID_UPDATE:
+               if (copy_from_user(&tinfo,
+                                  (struct hfi11_tid_info __user *)arg,
+                                  sizeof(tinfo)))
+                       return -EFAULT;
+
+               ret = hfi1_user_exp_rcv_setup(fp, &tinfo);
+               if (!ret) {
+                       /*
+                        * Copy the number of tidlist entries we used
+                        * and the length of the buffer we registered.
+                        * These fields are adjacent in the structure so
+                        * we can copy them at the same time.
+                        */
+                       addr = arg + offsetof(struct hfi1_tid_info, tidcnt);
+                       if (copy_to_user((void __user *)addr, &tinfo.tidcnt,
+                                        sizeof(tinfo.tidcnt) +
+                                        sizeof(tinfo.length)))
+                               ret = -EFAULT;
+               }
+               break;
+
+       case HFI1_IOCTL_TID_FREE:
+               if (copy_from_user(&tinfo,
+                                  (struct hfi11_tid_info __user *)arg,
+                                  sizeof(tinfo)))
+                       return -EFAULT;
+
+               ret = hfi1_user_exp_rcv_clear(fp, &tinfo);
+               if (ret)
+                       break;
+               addr = arg + offsetof(struct hfi1_tid_info, tidcnt);
+               if (copy_to_user((void __user *)addr, &tinfo.tidcnt,
+                                sizeof(tinfo.tidcnt)))
+                       ret = -EFAULT;
+               break;
+
+       case HFI1_IOCTL_TID_INVAL_READ:
+               if (copy_from_user(&tinfo,
+                                  (struct hfi11_tid_info __user *)arg,
+                                  sizeof(tinfo)))
+                       return -EFAULT;
+
+               ret = hfi1_user_exp_rcv_invalid(fp, &tinfo);
+               if (ret)
+                       break;
+               addr = arg + offsetof(struct hfi1_tid_info, tidcnt);
+               if (copy_to_user((void __user *)addr, &tinfo.tidcnt,
+                                sizeof(tinfo.tidcnt)))
+                       ret = -EFAULT;
+               break;
+
+       case HFI1_IOCTL_RECV_CTRL:
+               ret = get_user(uval, (int __user *)arg);
+               if (ret != 0)
+                       return -EFAULT;
+               ret = manage_rcvq(uctxt, fd->subctxt, uval);
+               break;
+
+       case HFI1_IOCTL_POLL_TYPE:
+               ret = get_user(uval, (int __user *)arg);
+               if (ret != 0)
+                       return -EFAULT;
+               uctxt->poll_type = (typeof(uctxt->poll_type))uval;
+               break;
+
+       case HFI1_IOCTL_ACK_EVENT:
+               ret = get_user(ul_uval, (unsigned long __user *)arg);
+               if (ret != 0)
+                       return -EFAULT;
+               ret = user_event_ack(uctxt, fd->subctxt, ul_uval);
+               break;
+
+       case HFI1_IOCTL_SET_PKEY:
+               ret = get_user(uval16, (u16 __user *)arg);
+               if (ret != 0)
+                       return -EFAULT;
+               if (HFI1_CAP_IS_USET(PKEY_CHECK))
+                       ret = set_ctxt_pkey(uctxt, fd->subctxt, uval16);
+               else
+                       return -EPERM;
+               break;
+
+       case HFI1_IOCTL_CTXT_RESET: {
+               struct send_context *sc;
+               struct hfi1_devdata *dd;
+
+               if (!uctxt || !uctxt->dd || !uctxt->sc)
+                       return -EINVAL;
+
+               /*
+                * There is no protection here. User level has to
+                * guarantee that no one will be writing to the send
+                * context while it is being re-initialized.
+                * If user level breaks that guarantee, it will break
+                * it's own context and no one else's.
+                */
+               dd = uctxt->dd;
+               sc = uctxt->sc;
+               /*
+                * Wait until the interrupt handler has marked the
+                * context as halted or frozen. Report error if we time
+                * out.
+                */
+               wait_event_interruptible_timeout(
+                       sc->halt_wait, (sc->flags & SCF_HALTED),
+                       msecs_to_jiffies(SEND_CTXT_HALT_TIMEOUT));
+               if (!(sc->flags & SCF_HALTED))
+                       return -ENOLCK;
+
+               /*
+                * If the send context was halted due to a Freeze,
+                * wait until the device has been "unfrozen" before
+                * resetting the context.
+                */
+               if (sc->flags & SCF_FROZEN) {
+                       wait_event_interruptible_timeout(
+                               dd->event_queue,
+                               !(ACCESS_ONCE(dd->flags) & HFI1_FROZEN),
+                               msecs_to_jiffies(SEND_CTXT_HALT_TIMEOUT));
+                       if (dd->flags & HFI1_FROZEN)
+                               return -ENOLCK;
+
+                       if (dd->flags & HFI1_FORCED_FREEZE)
+                               /*
+                                * Don't allow context reset if we are into
+                                * forced freeze
+                                */
+                               return -ENODEV;
+
+                       sc_disable(sc);
+                       ret = sc_enable(sc);
+                       hfi1_rcvctrl(dd, HFI1_RCVCTRL_CTXT_ENB,
+                                    uctxt->ctxt);
+               } else {
+                       ret = sc_restart(sc);
+               }
+               if (!ret)
+                       sc_return_credits(sc);
+               break;
+       }
+
+       case HFI1_IOCTL_GET_VERS:
+               uval = HFI1_USER_SWVERSION;
+               if (put_user(uval, (int __user *)arg))
+                       return -EFAULT;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
 static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
                               size_t count, loff_t *offset)
 {
@@ -188,7 +393,10 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
        void *dest = NULL;
        __u64 user_val = 0;
        int uctxt_required = 1;
-       int must_be_root = 0;
+
+       /* FIXME: This interface cannot continue out of staging */
+       if (WARN_ON_ONCE(!ib_safe_file_access(fp)))
+               return -EACCES;
 
        if (count < sizeof(cmd)) {
                ret = -EINVAL;
@@ -209,7 +417,6 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
                copy = sizeof(uinfo);
                dest = &uinfo;
                break;
-       case HFI1_CMD_SDMA_STATUS_UPD:
        case HFI1_CMD_CREDIT_UPD:
                copy = 0;
                break;
@@ -229,15 +436,6 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
                copy = 0;
                user_val = cmd.addr;
                break;
-       case HFI1_CMD_EP_INFO:
-       case HFI1_CMD_EP_ERASE_CHIP:
-       case HFI1_CMD_EP_ERASE_RANGE:
-       case HFI1_CMD_EP_READ_RANGE:
-       case HFI1_CMD_EP_WRITE_RANGE:
-               uctxt_required = 0;     /* assigned user context not required */
-               must_be_root = 1;       /* validate user */
-               copy = 0;
-               break;
        default:
                ret = -EINVAL;
                goto bail;
@@ -260,12 +458,6 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
                goto bail;
        }
 
-       /* only root can do these operations */
-       if (must_be_root && !capable(CAP_SYS_ADMIN)) {
-               ret = -EPERM;
-               goto bail;
-       }
-
        switch (cmd.type) {
        case HFI1_CMD_ASSIGN_CTXT:
                ret = assign_ctxt(fp, &uinfo);
@@ -284,8 +476,6 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
                ret = get_base_info(fp, (void __user *)(unsigned long)
                                    user_val, cmd.len);
                break;
-       case HFI1_CMD_SDMA_STATUS_UPD:
-               break;
        case HFI1_CMD_CREDIT_UPD:
                if (uctxt && uctxt->sc)
                        sc_return_credits(uctxt->sc);
@@ -404,13 +594,6 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
                        sc_return_credits(sc);
                break;
        }
-       case HFI1_CMD_EP_INFO:
-       case HFI1_CMD_EP_ERASE_CHIP:
-       case HFI1_CMD_EP_ERASE_RANGE:
-       case HFI1_CMD_EP_READ_RANGE:
-       case HFI1_CMD_EP_WRITE_RANGE:
-               ret = handle_eprom_command(fp, &cmd);
-               break;
        }
 
        if (ret >= 0)
@@ -791,15 +974,16 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
        spin_unlock_irqrestore(&dd->uctxt_lock, flags);
 
        dd->rcd[uctxt->ctxt] = NULL;
+
+       hfi1_user_exp_rcv_free(fdata);
+       hfi1_clear_ctxt_pkey(dd, uctxt->ctxt);
+
        uctxt->rcvwait_to = 0;
        uctxt->piowait_to = 0;
        uctxt->rcvnowait = 0;
        uctxt->pionowait = 0;
        uctxt->event_flags = 0;
 
-       hfi1_user_exp_rcv_free(fdata);
-       hfi1_clear_ctxt_pkey(dd, uctxt->ctxt);
-
        hfi1_stats.sps_ctxts--;
        if (++dd->freectxts == dd->num_user_contexts)
                aspm_enable_all(dd);
@@ -829,7 +1013,7 @@ static u64 kvirt_to_phys(void *addr)
 static int assign_ctxt(struct file *fp, struct hfi1_user_info *uinfo)
 {
        int i_minor, ret = 0;
-       unsigned swmajor, swminor, alg = HFI1_ALG_ACROSS;
+       unsigned int swmajor, swminor;
 
        swmajor = uinfo->userversion >> 16;
        if (swmajor != HFI1_USER_SWMAJOR) {
@@ -839,9 +1023,6 @@ static int assign_ctxt(struct file *fp, struct hfi1_user_info *uinfo)
 
        swminor = uinfo->userversion & 0xffff;
 
-       if (uinfo->hfi1_alg < HFI1_ALG_COUNT)
-               alg = uinfo->hfi1_alg;
-
        mutex_lock(&hfi1_mutex);
        /* First, lets check if we need to setup a shared context? */
        if (uinfo->subctxt_cnt) {
@@ -861,7 +1042,7 @@ static int assign_ctxt(struct file *fp, struct hfi1_user_info *uinfo)
         */
        if (!ret) {
                i_minor = iminor(file_inode(fp)) - HFI1_USER_MINOR_BASE;
-               ret = get_user_context(fp, uinfo, i_minor - 1, alg);
+               ret = get_user_context(fp, uinfo, i_minor);
        }
 done_unlock:
        mutex_unlock(&hfi1_mutex);
@@ -869,71 +1050,26 @@ done:
        return ret;
 }
 
-/* return true if the device available for general use */
-static int usable_device(struct hfi1_devdata *dd)
-{
-       struct hfi1_pportdata *ppd = dd->pport;
-
-       return driver_lstate(ppd) == IB_PORT_ACTIVE;
-}
-
 static int get_user_context(struct file *fp, struct hfi1_user_info *uinfo,
-                           int devno, unsigned alg)
+                           int devno)
 {
        struct hfi1_devdata *dd = NULL;
-       int ret = 0, devmax, npresent, nup, dev;
+       int devmax, npresent, nup;
 
        devmax = hfi1_count_units(&npresent, &nup);
-       if (!npresent) {
-               ret = -ENXIO;
-               goto done;
-       }
-       if (!nup) {
-               ret = -ENETDOWN;
-               goto done;
-       }
-       if (devno >= 0) {
-               dd = hfi1_lookup(devno);
-               if (!dd)
-                       ret = -ENODEV;
-               else if (!dd->freectxts)
-                       ret = -EBUSY;
-       } else {
-               struct hfi1_devdata *pdd;
-
-               if (alg == HFI1_ALG_ACROSS) {
-                       unsigned free = 0U;
-
-                       for (dev = 0; dev < devmax; dev++) {
-                               pdd = hfi1_lookup(dev);
-                               if (!pdd)
-                                       continue;
-                               if (!usable_device(pdd))
-                                       continue;
-                               if (pdd->freectxts &&
-                                   pdd->freectxts > free) {
-                                       dd = pdd;
-                                       free = pdd->freectxts;
-                               }
-                       }
-               } else {
-                       for (dev = 0; dev < devmax; dev++) {
-                               pdd = hfi1_lookup(dev);
-                               if (!pdd)
-                                       continue;
-                               if (!usable_device(pdd))
-                                       continue;
-                               if (pdd->freectxts) {
-                                       dd = pdd;
-                                       break;
-                               }
-                       }
-               }
-               if (!dd)
-                       ret = -EBUSY;
-       }
-done:
-       return ret ? ret : allocate_ctxt(fp, dd, uinfo);
+       if (!npresent)
+               return -ENXIO;
+
+       if (!nup)
+               return -ENETDOWN;
+
+       dd = hfi1_lookup(devno);
+       if (!dd)
+               return -ENODEV;
+       else if (!dd->freectxts)
+               return -EBUSY;
+
+       return allocate_ctxt(fp, dd, uinfo);
 }
 
 static int find_shared_ctxt(struct file *fp,
@@ -1127,27 +1263,13 @@ bail:
 
 static int user_init(struct file *fp)
 {
-       int ret;
        unsigned int rcvctrl_ops = 0;
        struct hfi1_filedata *fd = fp->private_data;
        struct hfi1_ctxtdata *uctxt = fd->uctxt;
 
        /* make sure that the context has already been setup */
-       if (!test_bit(HFI1_CTXT_SETUP_DONE, &uctxt->event_flags)) {
-               ret = -EFAULT;
-               goto done;
-       }
-
-       /*
-        * Subctxts don't need to initialize anything since master
-        * has done it.
-        */
-       if (fd->subctxt) {
-               ret = wait_event_interruptible(uctxt->wait, !test_bit(
-                                              HFI1_CTXT_MASTER_UNINIT,
-                                              &uctxt->event_flags));
-               goto expected;
-       }
+       if (!test_bit(HFI1_CTXT_SETUP_DONE, &uctxt->event_flags))
+               return -EFAULT;
 
        /* initialize poll variables... */
        uctxt->urgent = 0;
@@ -1202,19 +1324,7 @@ static int user_init(struct file *fp)
                wake_up(&uctxt->wait);
        }
 
-expected:
-       /*
-        * Expected receive has to be setup for all processes (including
-        * shared contexts). However, it has to be done after the master
-        * context has been fully configured as it depends on the
-        * eager/expected split of the RcvArray entries.
-        * Setting it up here ensures that the subcontexts will be waiting
-        * (due to the above wait_event_interruptible() until the master
-        * is setup.
-        */
-       ret = hfi1_user_exp_rcv_init(fp);
-done:
-       return ret;
+       return 0;
 }
 
 static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len)
@@ -1261,7 +1371,7 @@ static int setup_ctxt(struct file *fp)
        int ret = 0;
 
        /*
-        * Context should be set up only once (including allocation and
+        * Context should be set up only onceincluding allocation and
         * programming of eager buffers. This is done if context sharing
         * is not requested or by the master process.
         */
@@ -1282,8 +1392,27 @@ static int setup_ctxt(struct file *fp)
                        if (ret)
                                goto done;
                }
+       } else {
+               ret = wait_event_interruptible(uctxt->wait, !test_bit(
+                                              HFI1_CTXT_MASTER_UNINIT,
+                                              &uctxt->event_flags));
+               if (ret)
+                       goto done;
        }
+
        ret = hfi1_user_sdma_alloc_queues(uctxt, fp);
+       if (ret)
+               goto done;
+       /*
+        * Expected receive has to be setup for all processes (including
+        * shared contexts). However, it has to be done after the master
+        * context has been fully configured as it depends on the
+        * eager/expected split of the RcvArray entries.
+        * Setting it up here ensures that the subcontexts will be waiting
+        * (due to the above wait_event_interruptible() until the master
+        * is setup.
+        */
+       ret = hfi1_user_exp_rcv_init(fp);
        if (ret)
                goto done;
 
@@ -1546,191 +1675,10 @@ done:
        return ret;
 }
 
-static int ui_open(struct inode *inode, struct file *filp)
-{
-       struct hfi1_devdata *dd;
-
-       dd = container_of(inode->i_cdev, struct hfi1_devdata, ui_cdev);
-       filp->private_data = dd; /* for other methods */
-       return 0;
-}
-
-static int ui_release(struct inode *inode, struct file *filp)
-{
-       /* nothing to do */
-       return 0;
-}
-
-static loff_t ui_lseek(struct file *filp, loff_t offset, int whence)
-{
-       struct hfi1_devdata *dd = filp->private_data;
-
-       switch (whence) {
-       case SEEK_SET:
-               break;
-       case SEEK_CUR:
-               offset += filp->f_pos;
-               break;
-       case SEEK_END:
-               offset = ((dd->kregend - dd->kregbase) + DC8051_DATA_MEM_SIZE) -
-                       offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (offset < 0)
-               return -EINVAL;
-
-       if (offset >= (dd->kregend - dd->kregbase) + DC8051_DATA_MEM_SIZE)
-               return -EINVAL;
-
-       filp->f_pos = offset;
-
-       return filp->f_pos;
-}
-
-/* NOTE: assumes unsigned long is 8 bytes */
-static ssize_t ui_read(struct file *filp, char __user *buf, size_t count,
-                      loff_t *f_pos)
-{
-       struct hfi1_devdata *dd = filp->private_data;
-       void __iomem *base = dd->kregbase;
-       unsigned long total, csr_off,
-               barlen = (dd->kregend - dd->kregbase);
-       u64 data;
-
-       /* only read 8 byte quantities */
-       if ((count % 8) != 0)
-               return -EINVAL;
-       /* offset must be 8-byte aligned */
-       if ((*f_pos % 8) != 0)
-               return -EINVAL;
-       /* destination buffer must be 8-byte aligned */
-       if ((unsigned long)buf % 8 != 0)
-               return -EINVAL;
-       /* must be in range */
-       if (*f_pos + count > (barlen + DC8051_DATA_MEM_SIZE))
-               return -EINVAL;
-       /* only set the base if we are not starting past the BAR */
-       if (*f_pos < barlen)
-               base += *f_pos;
-       csr_off = *f_pos;
-       for (total = 0; total < count; total += 8, csr_off += 8) {
-               /* accessing LCB CSRs requires more checks */
-               if (is_lcb_offset(csr_off)) {
-                       if (read_lcb_csr(dd, csr_off, (u64 *)&data))
-                               break; /* failed */
-               }
-               /*
-                * Cannot read ASIC GPIO/QSFP* clear and force CSRs without a
-                * false parity error.  Avoid the whole issue by not reading
-                * them.  These registers are defined as having a read value
-                * of 0.
-                */
-               else if (csr_off == ASIC_GPIO_CLEAR ||
-                        csr_off == ASIC_GPIO_FORCE ||
-                        csr_off == ASIC_QSFP1_CLEAR ||
-                        csr_off == ASIC_QSFP1_FORCE ||
-                        csr_off == ASIC_QSFP2_CLEAR ||
-                        csr_off == ASIC_QSFP2_FORCE)
-                       data = 0;
-               else if (csr_off >= barlen) {
-                       /*
-                        * read_8051_data can read more than just 8 bytes at
-                        * a time. However, folding this into the loop and
-                        * handling the reads in 8 byte increments allows us
-                        * to smoothly transition from chip memory to 8051
-                        * memory.
-                        */
-                       if (read_8051_data(dd,
-                                          (u32)(csr_off - barlen),
-                                          sizeof(data), &data))
-                               break; /* failed */
-               } else
-                       data = readq(base + total);
-               if (put_user(data, (unsigned long __user *)(buf + total)))
-                       break;
-       }
-       *f_pos += total;
-       return total;
-}
-
-/* NOTE: assumes unsigned long is 8 bytes */
-static ssize_t ui_write(struct file *filp, const char __user *buf,
-                       size_t count, loff_t *f_pos)
-{
-       struct hfi1_devdata *dd = filp->private_data;
-       void __iomem *base;
-       unsigned long total, data, csr_off;
-       int in_lcb;
-
-       /* only write 8 byte quantities */
-       if ((count % 8) != 0)
-               return -EINVAL;
-       /* offset must be 8-byte aligned */
-       if ((*f_pos % 8) != 0)
-               return -EINVAL;
-       /* source buffer must be 8-byte aligned */
-       if ((unsigned long)buf % 8 != 0)
-               return -EINVAL;
-       /* must be in range */
-       if (*f_pos + count > dd->kregend - dd->kregbase)
-               return -EINVAL;
-
-       base = (void __iomem *)dd->kregbase + *f_pos;
-       csr_off = *f_pos;
-       in_lcb = 0;
-       for (total = 0; total < count; total += 8, csr_off += 8) {
-               if (get_user(data, (unsigned long __user *)(buf + total)))
-                       break;
-               /* accessing LCB CSRs requires a special procedure */
-               if (is_lcb_offset(csr_off)) {
-                       if (!in_lcb) {
-                               int ret = acquire_lcb_access(dd, 1);
-
-                               if (ret)
-                                       break;
-                               in_lcb = 1;
-                       }
-               } else {
-                       if (in_lcb) {
-                               release_lcb_access(dd, 1);
-                               in_lcb = 0;
-                       }
-               }
-               writeq(data, base + total);
-       }
-       if (in_lcb)
-               release_lcb_access(dd, 1);
-       *f_pos += total;
-       return total;
-}
-
-static const struct file_operations ui_file_ops = {
-       .owner = THIS_MODULE,
-       .llseek = ui_lseek,
-       .read = ui_read,
-       .write = ui_write,
-       .open = ui_open,
-       .release = ui_release,
-};
-
-#define UI_OFFSET 192  /* device minor offset for UI devices */
-static int create_ui = 1;
-
-static struct cdev wildcard_cdev;
-static struct device *wildcard_device;
-
-static atomic_t user_count = ATOMIC_INIT(0);
-
 static void user_remove(struct hfi1_devdata *dd)
 {
-       if (atomic_dec_return(&user_count) == 0)
-               hfi1_cdev_cleanup(&wildcard_cdev, &wildcard_device);
 
        hfi1_cdev_cleanup(&dd->user_cdev, &dd->user_device);
-       hfi1_cdev_cleanup(&dd->ui_cdev, &dd->ui_device);
 }
 
 static int user_add(struct hfi1_devdata *dd)
@@ -1738,34 +1686,13 @@ static int user_add(struct hfi1_devdata *dd)
        char name[10];
        int ret;
 
-       if (atomic_inc_return(&user_count) == 1) {
-               ret = hfi1_cdev_init(0, class_name(), &hfi1_file_ops,
-                                    &wildcard_cdev, &wildcard_device,
-                                    true);
-               if (ret)
-                       goto done;
-       }
-
        snprintf(name, sizeof(name), "%s_%d", class_name(), dd->unit);
-       ret = hfi1_cdev_init(dd->unit + 1, name, &hfi1_file_ops,
+       ret = hfi1_cdev_init(dd->unit, name, &hfi1_file_ops,
                             &dd->user_cdev, &dd->user_device,
                             true);
        if (ret)
-               goto done;
+               user_remove(dd);
 
-       if (create_ui) {
-               snprintf(name, sizeof(name),
-                        "%s_ui%d", class_name(), dd->unit);
-               ret = hfi1_cdev_init(dd->unit + UI_OFFSET, name, &ui_file_ops,
-                                    &dd->ui_cdev, &dd->ui_device,
-                                    false);
-               if (ret)
-                       goto done;
-       }
-
-       return 0;
-done:
-       user_remove(dd);
        return ret;
 }
 
@@ -1774,13 +1701,7 @@ done:
  */
 int hfi1_device_create(struct hfi1_devdata *dd)
 {
-       int r, ret;
-
-       r = user_add(dd);
-       ret = hfi1_diag_add(dd);
-       if (r && !ret)
-               ret = r;
-       return ret;
+       return user_add(dd);
 }
 
 /*
@@ -1790,5 +1711,4 @@ int hfi1_device_create(struct hfi1_devdata *dd)
 void hfi1_device_remove(struct hfi1_devdata *dd)
 {
        user_remove(dd);
-       hfi1_diag_remove(dd);
 }
This page took 0.03407 seconds and 5 git commands to generate.