Loading drivers/infiniband/hw/hfi1/chip.c +28 −42 Original line number Diff line number Diff line Loading @@ -9956,7 +9956,7 @@ int hfi1_get_ib_cfg(struct hfi1_pportdata *ppd, int which) val = ppd->phy_error_threshold; break; case HFI1_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */ val = dd->link_default; val = HLS_DEFAULT; break; case HFI1_IB_CFG_HRTBT: /* Heartbeat off/enable/auto */ Loading Loading @@ -10159,6 +10159,10 @@ static const char * const state_complete_reasons[] = { [0x33] = "Link partner completed the VerifyCap state, but the passing lanes do not meet the local link width policy", [0x34] = tx_out_of_policy, [0x35] = "Negotiated link width is mutually exclusive", [0x36] = "Timed out before receiving verifycap frames in VerifyCap.Exchange", [0x37] = "Unable to resolve secure data exchange", }; static const char *state_complete_reason_code_string(struct hfi1_pportdata *ppd, Loading Loading @@ -10547,7 +10551,7 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state) orig_new_state = state; if (state == HLS_DN_DOWNDEF) state = dd->link_default; state = HLS_DEFAULT; /* interpret poll -> poll as a link bounce */ poll_bounce = ppd->host_link_state == HLS_DN_POLL && Loading Loading @@ -12925,7 +12929,7 @@ static void clean_up_interrupts(struct hfi1_devdata *dd) if (!me->arg) /* => no irq, no affinity */ continue; hfi1_put_irq_affinity(dd, me); free_irq(me->irq, me->arg); pci_free_irq(dd->pcidev, i, me->arg); } /* clean structures */ Loading @@ -12935,7 +12939,7 @@ static void clean_up_interrupts(struct hfi1_devdata *dd) } else { /* INTx */ if (dd->requested_intx_irq) { free_irq(dd->pcidev->irq, dd); pci_free_irq(dd->pcidev, 0, dd); dd->requested_intx_irq = 0; } disable_intx(dd->pcidev); Loading Loading @@ -12994,10 +12998,8 @@ static int request_intx_irq(struct hfi1_devdata *dd) { int ret; snprintf(dd->intx_name, sizeof(dd->intx_name), DRIVER_NAME "_%d", dd->unit); ret = request_irq(dd->pcidev->irq, general_interrupt, IRQF_SHARED, dd->intx_name, dd); ret = pci_request_irq(dd->pcidev, 0, general_interrupt, NULL, dd, DRIVER_NAME "_%d", dd->unit); if (ret) dd_dev_err(dd, "unable to request INTx interrupt, err %d\n", ret); Loading Loading @@ -13040,13 +13042,14 @@ static int request_msix_irqs(struct hfi1_devdata *dd) int idx; struct hfi1_ctxtdata *rcd = NULL; struct sdma_engine *sde = NULL; char name[MAX_NAME_SIZE]; /* obtain the arguments to request_irq */ /* obtain the arguments to pci_request_irq */ if (first_general <= i && i < last_general) { idx = i - first_general; handler = general_interrupt; arg = dd; snprintf(me->name, sizeof(me->name), snprintf(name, sizeof(name), DRIVER_NAME "_%d", dd->unit); err_info = "general"; me->type = IRQ_GENERAL; Loading @@ -13055,14 +13058,14 @@ static int request_msix_irqs(struct hfi1_devdata *dd) sde = &dd->per_sdma[idx]; handler = sdma_interrupt; arg = sde; snprintf(me->name, sizeof(me->name), snprintf(name, sizeof(name), DRIVER_NAME "_%d sdma%d", dd->unit, idx); err_info = "sdma"; remap_sdma_interrupts(dd, idx, i); me->type = IRQ_SDMA; } else if (first_rx <= i && i < last_rx) { idx = i - first_rx; rcd = hfi1_rcd_get_by_index(dd, idx); rcd = hfi1_rcd_get_by_index_safe(dd, idx); if (rcd) { /* * Set the interrupt register and mask for this Loading @@ -13074,7 +13077,7 @@ static int request_msix_irqs(struct hfi1_devdata *dd) handler = receive_context_interrupt; thread = receive_context_thread; arg = rcd; snprintf(me->name, sizeof(me->name), snprintf(name, sizeof(name), DRIVER_NAME "_%d kctxt%d", dd->unit, idx); err_info = "receive context"; Loading @@ -13095,18 +13098,10 @@ static int request_msix_irqs(struct hfi1_devdata *dd) if (!arg) continue; /* make sure the name is terminated */ me->name[sizeof(me->name) - 1] = 0; name[sizeof(name) - 1] = 0; me->irq = pci_irq_vector(dd->pcidev, i); /* * On err return me->irq. Don't need to clear this * because 'arg' has not been set, and cleanup will * do the right thing. */ if (me->irq < 0) return me->irq; ret = request_threaded_irq(me->irq, handler, thread, 0, me->name, arg); ret = pci_request_irq(dd->pcidev, i, handler, thread, arg, name); if (ret) { dd_dev_err(dd, "unable to allocate %s interrupt, irq %d, index %d, err %d\n", Loading @@ -13114,7 +13109,7 @@ static int request_msix_irqs(struct hfi1_devdata *dd) return ret; } /* * assign arg after request_irq call, so it will be * assign arg after pci_request_irq call, so it will be * cleaned up */ me->arg = arg; Loading @@ -13132,7 +13127,7 @@ void hfi1_vnic_synchronize_irq(struct hfi1_devdata *dd) int i; if (!dd->num_msix_entries) { synchronize_irq(dd->pcidev->irq); synchronize_irq(pci_irq_vector(dd->pcidev, 0)); return; } Loading @@ -13153,7 +13148,7 @@ void hfi1_reset_vnic_msix_info(struct hfi1_ctxtdata *rcd) return; hfi1_put_irq_affinity(dd, me); free_irq(me->irq, me->arg); pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg); me->arg = NULL; } Loading @@ -13176,28 +13171,21 @@ void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd) rcd->ireg = (IS_RCVAVAIL_START + idx) / 64; rcd->imask = ((u64)1) << ((IS_RCVAVAIL_START + idx) % 64); snprintf(me->name, sizeof(me->name), DRIVER_NAME "_%d kctxt%d", dd->unit, idx); me->name[sizeof(me->name) - 1] = 0; me->type = IRQ_RCVCTXT; me->irq = pci_irq_vector(dd->pcidev, rcd->msix_intr); if (me->irq < 0) { dd_dev_err(dd, "vnic irq vector request (idx %d) fail %d\n", idx, me->irq); return; } remap_intr(dd, IS_RCVAVAIL_START + idx, rcd->msix_intr); ret = request_threaded_irq(me->irq, receive_context_interrupt, receive_context_thread, 0, me->name, arg); ret = pci_request_irq(dd->pcidev, rcd->msix_intr, receive_context_interrupt, receive_context_thread, arg, DRIVER_NAME "_%d kctxt%d", dd->unit, idx); if (ret) { dd_dev_err(dd, "vnic irq request (irq %d, idx %d) fail %d\n", me->irq, idx, ret); return; } /* * assign arg after request_irq call, so it will be * assign arg after pci_request_irq call, so it will be * cleaned up */ me->arg = arg; Loading @@ -13206,7 +13194,7 @@ void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd) if (ret) { dd_dev_err(dd, "unable to pin IRQ %d\n", ret); free_irq(me->irq, me->arg); pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg); } } Loading Loading @@ -14907,8 +14895,6 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, init_vl_arb_caches(ppd); } dd->link_default = HLS_DN_POLL; /* * Do remaining PCIe setup and save PCIe values in dd. * Any error printing is already done by the init code. Loading drivers/infiniband/hw/hfi1/debugfs.c +2 −2 Original line number Diff line number Diff line Loading @@ -243,7 +243,7 @@ static int _ctx_stats_seq_show(struct seq_file *s, void *v) spos = v; i = *spos; rcd = hfi1_rcd_get_by_index(dd, i); rcd = hfi1_rcd_get_by_index_safe(dd, i); if (!rcd) return SEQ_SKIP; Loading Loading @@ -402,7 +402,7 @@ static int _rcds_seq_show(struct seq_file *s, void *v) loff_t *spos = v; loff_t i = *spos; rcd = hfi1_rcd_get_by_index(dd, i); rcd = hfi1_rcd_get_by_index_safe(dd, i); if (rcd) seqfile_dump_rcd(s, rcd); hfi1_rcd_put(rcd); Loading drivers/infiniband/hw/hfi1/driver.c +2 −2 Original line number Diff line number Diff line Loading @@ -866,7 +866,7 @@ static inline void set_nodma_rtail(struct hfi1_devdata *dd, u16 ctxt) * interrupt handler for all statically allocated kernel contexts. */ if (ctxt >= dd->first_dyn_alloc_ctxt) { rcd = hfi1_rcd_get_by_index(dd, ctxt); rcd = hfi1_rcd_get_by_index_safe(dd, ctxt); if (rcd) { rcd->do_interrupt = &handle_receive_interrupt_nodma_rtail; Loading Loading @@ -895,7 +895,7 @@ static inline void set_dma_rtail(struct hfi1_devdata *dd, u16 ctxt) * interrupt handler for all statically allocated kernel contexts. */ if (ctxt >= dd->first_dyn_alloc_ctxt) { rcd = hfi1_rcd_get_by_index(dd, ctxt); rcd = hfi1_rcd_get_by_index_safe(dd, ctxt); if (rcd) { rcd->do_interrupt = &handle_receive_interrupt_dma_rtail; Loading drivers/infiniband/hw/hfi1/file_ops.c +280 −204 Original line number Diff line number Diff line Loading @@ -78,16 +78,20 @@ static unsigned int hfi1_poll(struct file *fp, struct poll_table_struct *pt); static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma); static u64 kvirt_to_phys(void *addr); static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo); static int assign_ctxt(struct hfi1_filedata *fd, unsigned long arg, u32 len); static void init_subctxts(struct hfi1_ctxtdata *uctxt, const struct hfi1_user_info *uinfo); static int init_user_ctxt(struct hfi1_filedata *fd, struct hfi1_ctxtdata *uctxt); static void user_init(struct hfi1_ctxtdata *uctxt); static int get_ctxt_info(struct hfi1_filedata *fd, void __user *ubase, __u32 len); static int get_base_info(struct hfi1_filedata *fd, void __user *ubase, __u32 len); static int get_ctxt_info(struct hfi1_filedata *fd, unsigned long arg, u32 len); static int get_base_info(struct hfi1_filedata *fd, unsigned long arg, u32 len); static int user_exp_rcv_setup(struct hfi1_filedata *fd, unsigned long arg, u32 len); static int user_exp_rcv_clear(struct hfi1_filedata *fd, unsigned long arg, u32 len); static int user_exp_rcv_invalid(struct hfi1_filedata *fd, unsigned long arg, u32 len); static int setup_base_ctxt(struct hfi1_filedata *fd, struct hfi1_ctxtdata *uctxt); static int setup_subctxt(struct hfi1_ctxtdata *uctxt); Loading @@ -101,10 +105,11 @@ static void deallocate_ctxt(struct hfi1_ctxtdata *uctxt); static unsigned int poll_urgent(struct file *fp, struct poll_table_struct *pt); static unsigned int poll_next(struct file *fp, struct poll_table_struct *pt); static int user_event_ack(struct hfi1_ctxtdata *uctxt, u16 subctxt, unsigned long events); static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, u16 subctxt, u16 pkey); unsigned long arg); static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, unsigned long arg); static int ctxt_reset(struct hfi1_ctxtdata *uctxt); static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, int start_stop); unsigned long arg); static int vma_fault(struct vm_fault *vmf); static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); Loading Loading @@ -221,13 +226,8 @@ static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, { 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; hfi1_cdbg(IOCTL, "IOCTL recv: 0x%x", cmd); if (cmd != HFI1_IOCTL_ASSIGN_CTXT && Loading @@ -237,171 +237,55 @@ static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, switch (cmd) { case HFI1_IOCTL_ASSIGN_CTXT: if (uctxt) return -EINVAL; if (copy_from_user(&uinfo, (struct hfi1_user_info __user *)arg, sizeof(uinfo))) return -EFAULT; ret = assign_ctxt(fd, &uinfo); ret = assign_ctxt(fd, arg, _IOC_SIZE(cmd)); break; case HFI1_IOCTL_CTXT_INFO: ret = get_ctxt_info(fd, (void __user *)(unsigned long)arg, sizeof(struct hfi1_ctxt_info)); ret = get_ctxt_info(fd, arg, _IOC_SIZE(cmd)); break; case HFI1_IOCTL_USER_INFO: ret = get_base_info(fd, (void __user *)(unsigned long)arg, sizeof(struct hfi1_base_info)); ret = get_base_info(fd, arg, _IOC_SIZE(cmd)); break; case HFI1_IOCTL_CREDIT_UPD: if (uctxt) 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(fd, &tinfo); if (!ret) { /* * Copy the number of tidlist entries we used * and the length of the buffer we registered. */ addr = arg + offsetof(struct hfi1_tid_info, tidcnt); if (copy_to_user((void __user *)addr, &tinfo.tidcnt, sizeof(tinfo.tidcnt))) return -EFAULT; addr = arg + offsetof(struct hfi1_tid_info, length); if (copy_to_user((void __user *)addr, &tinfo.length, sizeof(tinfo.length))) ret = -EFAULT; } ret = user_exp_rcv_setup(fd, arg, _IOC_SIZE(cmd)); 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(fd, &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; ret = user_exp_rcv_clear(fd, arg, _IOC_SIZE(cmd)); 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(fd, &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; ret = user_exp_rcv_invalid(fd, arg, _IOC_SIZE(cmd)); 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); ret = manage_rcvq(uctxt, fd->subctxt, arg); break; case HFI1_IOCTL_POLL_TYPE: ret = get_user(uval, (int __user *)arg); if (ret != 0) if (get_user(uval, (int __user *)arg)) 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); ret = user_event_ack(uctxt, fd->subctxt, arg); 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; ret = set_ctxt_pkey(uctxt, arg); 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); } else { ret = sc_restart(sc); } if (!ret) sc_return_credits(sc); case HFI1_IOCTL_CTXT_RESET: ret = ctxt_reset(uctxt); break; } case HFI1_IOCTL_GET_VERS: uval = HFI1_USER_SWVERSION; Loading Loading @@ -595,9 +479,8 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) * Use the page where this context's flags are. User level * knows where it's own bitmap is within the page. */ memaddr = (unsigned long)(dd->events + ((uctxt->ctxt - dd->first_dyn_alloc_ctxt) * HFI1_MAX_SHARED_CTXTS)) & PAGE_MASK; memaddr = (unsigned long) (dd->events + uctxt_offset(uctxt)) & PAGE_MASK; memlen = PAGE_SIZE; /* * v3.7 removes VM_RESERVED but the effect is kept by Loading Loading @@ -779,8 +662,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) * Clear any left over, unhandled events so the next process that * gets this context doesn't get confused. */ ev = dd->events + ((uctxt->ctxt - dd->first_dyn_alloc_ctxt) * HFI1_MAX_SHARED_CTXTS) + fdata->subctxt; ev = dd->events + uctxt_offset(uctxt) + fdata->subctxt; *ev = 0; spin_lock_irqsave(&dd->uctxt_lock, flags); Loading Loading @@ -891,20 +773,30 @@ static int complete_subctxt(struct hfi1_filedata *fd) return ret; } static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo) static int assign_ctxt(struct hfi1_filedata *fd, unsigned long arg, u32 len) { int ret; unsigned int swmajor, swminor; struct hfi1_ctxtdata *uctxt = NULL; struct hfi1_user_info uinfo; if (fd->uctxt) return -EINVAL; swmajor = uinfo->userversion >> 16; if (sizeof(uinfo) != len) return -EINVAL; if (copy_from_user(&uinfo, (void __user *)arg, sizeof(uinfo))) return -EFAULT; swmajor = uinfo.userversion >> 16; if (swmajor != HFI1_USER_SWMAJOR) return -ENODEV; if (uinfo->subctxt_cnt > HFI1_MAX_SHARED_CTXTS) if (uinfo.subctxt_cnt > HFI1_MAX_SHARED_CTXTS) return -EINVAL; swminor = uinfo->userversion & 0xffff; swminor = uinfo.userversion & 0xffff; /* * Acquire the mutex to protect against multiple creations of what Loading @@ -915,14 +807,14 @@ static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo) * Get a sub context if available (fd->uctxt will be set). * ret < 0 error, 0 no context, 1 sub-context found */ ret = find_sub_ctxt(fd, uinfo); ret = find_sub_ctxt(fd, &uinfo); /* * Allocate a base context if context sharing is not required or a * sub context wasn't found. */ if (!ret) ret = allocate_ctxt(fd, fd->dd, uinfo, &uctxt); ret = allocate_ctxt(fd, fd->dd, &uinfo, &uctxt); mutex_unlock(&hfi1_mutex); Loading Loading @@ -1237,12 +1129,13 @@ static void user_init(struct hfi1_ctxtdata *uctxt) hfi1_rcvctrl(uctxt->dd, rcvctrl_ops, uctxt); } static int get_ctxt_info(struct hfi1_filedata *fd, void __user *ubase, __u32 len) static int get_ctxt_info(struct hfi1_filedata *fd, unsigned long arg, u32 len) { struct hfi1_ctxt_info cinfo; struct hfi1_ctxtdata *uctxt = fd->uctxt; int ret = 0; if (sizeof(cinfo) != len) return -EINVAL; memset(&cinfo, 0, sizeof(cinfo)); cinfo.runtime_flags = (((uctxt->flags >> HFI1_CAP_MISC_SHIFT) & Loading Loading @@ -1272,10 +1165,10 @@ static int get_ctxt_info(struct hfi1_filedata *fd, void __user *ubase, cinfo.rcvegr_size = uctxt->egrbufs.rcvtid_size; trace_hfi1_ctxt_info(uctxt->dd, uctxt->ctxt, fd->subctxt, cinfo); if (copy_to_user(ubase, &cinfo, sizeof(cinfo))) ret = -EFAULT; if (copy_to_user((void __user *)arg, &cinfo, len)) return -EFAULT; return ret; return 0; } static int init_user_ctxt(struct hfi1_filedata *fd, Loading Loading @@ -1341,18 +1234,18 @@ static int setup_base_ctxt(struct hfi1_filedata *fd, return ret; } static int get_base_info(struct hfi1_filedata *fd, void __user *ubase, __u32 len) static int get_base_info(struct hfi1_filedata *fd, unsigned long arg, u32 len) { struct hfi1_base_info binfo; struct hfi1_ctxtdata *uctxt = fd->uctxt; struct hfi1_devdata *dd = uctxt->dd; ssize_t sz; unsigned offset; int ret = 0; trace_hfi1_uctxtdata(uctxt->dd, uctxt, fd->subctxt); if (sizeof(binfo) != len) return -EINVAL; memset(&binfo, 0, sizeof(binfo)); binfo.hw_version = dd->revision; binfo.sw_version = HFI1_KERN_SWVERSION; Loading Loading @@ -1389,8 +1282,7 @@ static int get_base_info(struct hfi1_filedata *fd, void __user *ubase, */ binfo.user_regbase = HFI1_MMAP_TOKEN(UREGS, uctxt->ctxt, fd->subctxt, 0); offset = offset_in_page((((uctxt->ctxt - dd->first_dyn_alloc_ctxt) * HFI1_MAX_SHARED_CTXTS) + fd->subctxt) * offset = offset_in_page((uctxt_offset(uctxt) + fd->subctxt) * sizeof(*dd->events)); binfo.events_bufbase = HFI1_MMAP_TOKEN(EVENTS, uctxt->ctxt, fd->subctxt, Loading @@ -1412,9 +1304,123 @@ static int get_base_info(struct hfi1_filedata *fd, void __user *ubase, uctxt->ctxt, fd->subctxt, 0); } sz = (len < sizeof(binfo)) ? len : sizeof(binfo); if (copy_to_user(ubase, &binfo, sz)) if (copy_to_user((void __user *)arg, &binfo, len)) return -EFAULT; return 0; } /** * user_exp_rcv_setup - Set up the given tid rcv list * @fd: file data of the current driver instance * @arg: ioctl argumnent for user space information * @len: length of data structure associated with ioctl command * * Wrapper to validate ioctl information before doing _rcv_setup. * */ static int user_exp_rcv_setup(struct hfi1_filedata *fd, unsigned long arg, u32 len) { int ret; unsigned long addr; struct hfi1_tid_info tinfo; if (sizeof(tinfo) != len) return -EINVAL; if (copy_from_user(&tinfo, (void __user *)arg, (sizeof(tinfo)))) return -EFAULT; ret = hfi1_user_exp_rcv_setup(fd, &tinfo); if (!ret) { /* * Copy the number of tidlist entries we used * and the length of the buffer we registered. */ addr = arg + offsetof(struct hfi1_tid_info, tidcnt); if (copy_to_user((void __user *)addr, &tinfo.tidcnt, sizeof(tinfo.tidcnt))) return -EFAULT; addr = arg + offsetof(struct hfi1_tid_info, length); if (copy_to_user((void __user *)addr, &tinfo.length, sizeof(tinfo.length))) ret = -EFAULT; } return ret; } /** * user_exp_rcv_clear - Clear the given tid rcv list * @fd: file data of the current driver instance * @arg: ioctl argumnent for user space information * @len: length of data structure associated with ioctl command * * The hfi1_user_exp_rcv_clear() can be called from the error path. Because * of this, we need to use this wrapper to copy the user space information * before doing the clear. */ static int user_exp_rcv_clear(struct hfi1_filedata *fd, unsigned long arg, u32 len) { int ret; unsigned long addr; struct hfi1_tid_info tinfo; if (sizeof(tinfo) != len) return -EINVAL; if (copy_from_user(&tinfo, (void __user *)arg, (sizeof(tinfo)))) return -EFAULT; ret = hfi1_user_exp_rcv_clear(fd, &tinfo); if (!ret) { addr = arg + offsetof(struct hfi1_tid_info, tidcnt); if (copy_to_user((void __user *)addr, &tinfo.tidcnt, sizeof(tinfo.tidcnt))) return -EFAULT; } return ret; } /** * user_exp_rcv_invalid - Invalidate the given tid rcv list * @fd: file data of the current driver instance * @arg: ioctl argumnent for user space information * @len: length of data structure associated with ioctl command * * Wrapper to validate ioctl information before doing _rcv_invalid. * */ static int user_exp_rcv_invalid(struct hfi1_filedata *fd, unsigned long arg, u32 len) { int ret; unsigned long addr; struct hfi1_tid_info tinfo; if (sizeof(tinfo) != len) return -EINVAL; if (!fd->invalid_tids) return -EINVAL; if (copy_from_user(&tinfo, (void __user *)arg, (sizeof(tinfo)))) return -EFAULT; ret = hfi1_user_exp_rcv_invalid(fd, &tinfo); if (ret) return ret; addr = arg + offsetof(struct hfi1_tid_info, tidcnt); if (copy_to_user((void __user *)addr, &tinfo.tidcnt, sizeof(tinfo.tidcnt))) ret = -EFAULT; return ret; } Loading Loading @@ -1482,14 +1488,13 @@ int hfi1_set_uevent_bits(struct hfi1_pportdata *ppd, const int evtbit) ctxt++) { uctxt = hfi1_rcd_get_by_index(dd, ctxt); if (uctxt) { unsigned long *evs = dd->events + (uctxt->ctxt - dd->first_dyn_alloc_ctxt) * HFI1_MAX_SHARED_CTXTS; unsigned long *evs; int i; /* * subctxt_cnt is 0 if not shared, so do base * separately, first, then remaining subctxt, if any */ evs = dd->events + uctxt_offset(uctxt); set_bit(evtbit, evs); for (i = 1; i < uctxt->subctxt_cnt; i++) set_bit(evtbit, evs + i); Loading @@ -1511,13 +1516,18 @@ int hfi1_set_uevent_bits(struct hfi1_pportdata *ppd, const int evtbit) * re-init the software copy of the head register */ static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, int start_stop) unsigned long arg) { struct hfi1_devdata *dd = uctxt->dd; unsigned int rcvctrl_op; int start_stop; if (subctxt) goto bail; return 0; if (get_user(start_stop, (int __user *)arg)) return -EFAULT; /* atomically clear receive enable ctxt. */ if (start_stop) { /* Loading @@ -1536,7 +1546,7 @@ static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, } hfi1_rcvctrl(dd, rcvctrl_op, uctxt); /* always; new head should be equal to new tail; see above */ bail: return 0; } Loading @@ -1546,17 +1556,20 @@ static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, * set, if desired, and checks again in future. */ static int user_event_ack(struct hfi1_ctxtdata *uctxt, u16 subctxt, unsigned long events) unsigned long arg) { int i; struct hfi1_devdata *dd = uctxt->dd; unsigned long *evs; unsigned long events; if (!dd->events) return 0; evs = dd->events + ((uctxt->ctxt - dd->first_dyn_alloc_ctxt) * HFI1_MAX_SHARED_CTXTS) + subctxt; if (get_user(events, (unsigned long __user *)arg)) return -EFAULT; evs = dd->events + uctxt_offset(uctxt) + subctxt; for (i = 0; i <= _HFI1_MAX_EVENT_BIT; i++) { if (!test_bit(i, &events)) Loading @@ -1566,26 +1579,89 @@ static int user_event_ack(struct hfi1_ctxtdata *uctxt, u16 subctxt, return 0; } static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, u16 subctxt, u16 pkey) static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, unsigned long arg) { int ret = -ENOENT, i, intable = 0; int i; struct hfi1_pportdata *ppd = uctxt->ppd; struct hfi1_devdata *dd = uctxt->dd; u16 pkey; if (pkey == LIM_MGMT_P_KEY || pkey == FULL_MGMT_P_KEY) { ret = -EINVAL; goto done; } if (!HFI1_CAP_IS_USET(PKEY_CHECK)) return -EPERM; if (get_user(pkey, (u16 __user *)arg)) return -EFAULT; if (pkey == LIM_MGMT_P_KEY || pkey == FULL_MGMT_P_KEY) return -EINVAL; for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) if (pkey == ppd->pkeys[i]) { intable = 1; break; if (pkey == ppd->pkeys[i]) return hfi1_set_ctxt_pkey(dd, uctxt, pkey); return -ENOENT; } if (intable) ret = hfi1_set_ctxt_pkey(dd, uctxt, pkey); done: /** * ctxt_reset - Reset the user context * @uctxt: valid user context */ static int ctxt_reset(struct hfi1_ctxtdata *uctxt) { struct send_context *sc; struct hfi1_devdata *dd; int ret = 0; 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, !(READ_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); } else { ret = sc_restart(sc); } if (!ret) sc_return_credits(sc); return ret; } Loading drivers/infiniband/hw/hfi1/hfi.h +11 −7 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
drivers/infiniband/hw/hfi1/chip.c +28 −42 Original line number Diff line number Diff line Loading @@ -9956,7 +9956,7 @@ int hfi1_get_ib_cfg(struct hfi1_pportdata *ppd, int which) val = ppd->phy_error_threshold; break; case HFI1_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */ val = dd->link_default; val = HLS_DEFAULT; break; case HFI1_IB_CFG_HRTBT: /* Heartbeat off/enable/auto */ Loading Loading @@ -10159,6 +10159,10 @@ static const char * const state_complete_reasons[] = { [0x33] = "Link partner completed the VerifyCap state, but the passing lanes do not meet the local link width policy", [0x34] = tx_out_of_policy, [0x35] = "Negotiated link width is mutually exclusive", [0x36] = "Timed out before receiving verifycap frames in VerifyCap.Exchange", [0x37] = "Unable to resolve secure data exchange", }; static const char *state_complete_reason_code_string(struct hfi1_pportdata *ppd, Loading Loading @@ -10547,7 +10551,7 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state) orig_new_state = state; if (state == HLS_DN_DOWNDEF) state = dd->link_default; state = HLS_DEFAULT; /* interpret poll -> poll as a link bounce */ poll_bounce = ppd->host_link_state == HLS_DN_POLL && Loading Loading @@ -12925,7 +12929,7 @@ static void clean_up_interrupts(struct hfi1_devdata *dd) if (!me->arg) /* => no irq, no affinity */ continue; hfi1_put_irq_affinity(dd, me); free_irq(me->irq, me->arg); pci_free_irq(dd->pcidev, i, me->arg); } /* clean structures */ Loading @@ -12935,7 +12939,7 @@ static void clean_up_interrupts(struct hfi1_devdata *dd) } else { /* INTx */ if (dd->requested_intx_irq) { free_irq(dd->pcidev->irq, dd); pci_free_irq(dd->pcidev, 0, dd); dd->requested_intx_irq = 0; } disable_intx(dd->pcidev); Loading Loading @@ -12994,10 +12998,8 @@ static int request_intx_irq(struct hfi1_devdata *dd) { int ret; snprintf(dd->intx_name, sizeof(dd->intx_name), DRIVER_NAME "_%d", dd->unit); ret = request_irq(dd->pcidev->irq, general_interrupt, IRQF_SHARED, dd->intx_name, dd); ret = pci_request_irq(dd->pcidev, 0, general_interrupt, NULL, dd, DRIVER_NAME "_%d", dd->unit); if (ret) dd_dev_err(dd, "unable to request INTx interrupt, err %d\n", ret); Loading Loading @@ -13040,13 +13042,14 @@ static int request_msix_irqs(struct hfi1_devdata *dd) int idx; struct hfi1_ctxtdata *rcd = NULL; struct sdma_engine *sde = NULL; char name[MAX_NAME_SIZE]; /* obtain the arguments to request_irq */ /* obtain the arguments to pci_request_irq */ if (first_general <= i && i < last_general) { idx = i - first_general; handler = general_interrupt; arg = dd; snprintf(me->name, sizeof(me->name), snprintf(name, sizeof(name), DRIVER_NAME "_%d", dd->unit); err_info = "general"; me->type = IRQ_GENERAL; Loading @@ -13055,14 +13058,14 @@ static int request_msix_irqs(struct hfi1_devdata *dd) sde = &dd->per_sdma[idx]; handler = sdma_interrupt; arg = sde; snprintf(me->name, sizeof(me->name), snprintf(name, sizeof(name), DRIVER_NAME "_%d sdma%d", dd->unit, idx); err_info = "sdma"; remap_sdma_interrupts(dd, idx, i); me->type = IRQ_SDMA; } else if (first_rx <= i && i < last_rx) { idx = i - first_rx; rcd = hfi1_rcd_get_by_index(dd, idx); rcd = hfi1_rcd_get_by_index_safe(dd, idx); if (rcd) { /* * Set the interrupt register and mask for this Loading @@ -13074,7 +13077,7 @@ static int request_msix_irqs(struct hfi1_devdata *dd) handler = receive_context_interrupt; thread = receive_context_thread; arg = rcd; snprintf(me->name, sizeof(me->name), snprintf(name, sizeof(name), DRIVER_NAME "_%d kctxt%d", dd->unit, idx); err_info = "receive context"; Loading @@ -13095,18 +13098,10 @@ static int request_msix_irqs(struct hfi1_devdata *dd) if (!arg) continue; /* make sure the name is terminated */ me->name[sizeof(me->name) - 1] = 0; name[sizeof(name) - 1] = 0; me->irq = pci_irq_vector(dd->pcidev, i); /* * On err return me->irq. Don't need to clear this * because 'arg' has not been set, and cleanup will * do the right thing. */ if (me->irq < 0) return me->irq; ret = request_threaded_irq(me->irq, handler, thread, 0, me->name, arg); ret = pci_request_irq(dd->pcidev, i, handler, thread, arg, name); if (ret) { dd_dev_err(dd, "unable to allocate %s interrupt, irq %d, index %d, err %d\n", Loading @@ -13114,7 +13109,7 @@ static int request_msix_irqs(struct hfi1_devdata *dd) return ret; } /* * assign arg after request_irq call, so it will be * assign arg after pci_request_irq call, so it will be * cleaned up */ me->arg = arg; Loading @@ -13132,7 +13127,7 @@ void hfi1_vnic_synchronize_irq(struct hfi1_devdata *dd) int i; if (!dd->num_msix_entries) { synchronize_irq(dd->pcidev->irq); synchronize_irq(pci_irq_vector(dd->pcidev, 0)); return; } Loading @@ -13153,7 +13148,7 @@ void hfi1_reset_vnic_msix_info(struct hfi1_ctxtdata *rcd) return; hfi1_put_irq_affinity(dd, me); free_irq(me->irq, me->arg); pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg); me->arg = NULL; } Loading @@ -13176,28 +13171,21 @@ void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd) rcd->ireg = (IS_RCVAVAIL_START + idx) / 64; rcd->imask = ((u64)1) << ((IS_RCVAVAIL_START + idx) % 64); snprintf(me->name, sizeof(me->name), DRIVER_NAME "_%d kctxt%d", dd->unit, idx); me->name[sizeof(me->name) - 1] = 0; me->type = IRQ_RCVCTXT; me->irq = pci_irq_vector(dd->pcidev, rcd->msix_intr); if (me->irq < 0) { dd_dev_err(dd, "vnic irq vector request (idx %d) fail %d\n", idx, me->irq); return; } remap_intr(dd, IS_RCVAVAIL_START + idx, rcd->msix_intr); ret = request_threaded_irq(me->irq, receive_context_interrupt, receive_context_thread, 0, me->name, arg); ret = pci_request_irq(dd->pcidev, rcd->msix_intr, receive_context_interrupt, receive_context_thread, arg, DRIVER_NAME "_%d kctxt%d", dd->unit, idx); if (ret) { dd_dev_err(dd, "vnic irq request (irq %d, idx %d) fail %d\n", me->irq, idx, ret); return; } /* * assign arg after request_irq call, so it will be * assign arg after pci_request_irq call, so it will be * cleaned up */ me->arg = arg; Loading @@ -13206,7 +13194,7 @@ void hfi1_set_vnic_msix_info(struct hfi1_ctxtdata *rcd) if (ret) { dd_dev_err(dd, "unable to pin IRQ %d\n", ret); free_irq(me->irq, me->arg); pci_free_irq(dd->pcidev, rcd->msix_intr, me->arg); } } Loading Loading @@ -14907,8 +14895,6 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, init_vl_arb_caches(ppd); } dd->link_default = HLS_DN_POLL; /* * Do remaining PCIe setup and save PCIe values in dd. * Any error printing is already done by the init code. Loading
drivers/infiniband/hw/hfi1/debugfs.c +2 −2 Original line number Diff line number Diff line Loading @@ -243,7 +243,7 @@ static int _ctx_stats_seq_show(struct seq_file *s, void *v) spos = v; i = *spos; rcd = hfi1_rcd_get_by_index(dd, i); rcd = hfi1_rcd_get_by_index_safe(dd, i); if (!rcd) return SEQ_SKIP; Loading Loading @@ -402,7 +402,7 @@ static int _rcds_seq_show(struct seq_file *s, void *v) loff_t *spos = v; loff_t i = *spos; rcd = hfi1_rcd_get_by_index(dd, i); rcd = hfi1_rcd_get_by_index_safe(dd, i); if (rcd) seqfile_dump_rcd(s, rcd); hfi1_rcd_put(rcd); Loading
drivers/infiniband/hw/hfi1/driver.c +2 −2 Original line number Diff line number Diff line Loading @@ -866,7 +866,7 @@ static inline void set_nodma_rtail(struct hfi1_devdata *dd, u16 ctxt) * interrupt handler for all statically allocated kernel contexts. */ if (ctxt >= dd->first_dyn_alloc_ctxt) { rcd = hfi1_rcd_get_by_index(dd, ctxt); rcd = hfi1_rcd_get_by_index_safe(dd, ctxt); if (rcd) { rcd->do_interrupt = &handle_receive_interrupt_nodma_rtail; Loading Loading @@ -895,7 +895,7 @@ static inline void set_dma_rtail(struct hfi1_devdata *dd, u16 ctxt) * interrupt handler for all statically allocated kernel contexts. */ if (ctxt >= dd->first_dyn_alloc_ctxt) { rcd = hfi1_rcd_get_by_index(dd, ctxt); rcd = hfi1_rcd_get_by_index_safe(dd, ctxt); if (rcd) { rcd->do_interrupt = &handle_receive_interrupt_dma_rtail; Loading
drivers/infiniband/hw/hfi1/file_ops.c +280 −204 Original line number Diff line number Diff line Loading @@ -78,16 +78,20 @@ static unsigned int hfi1_poll(struct file *fp, struct poll_table_struct *pt); static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma); static u64 kvirt_to_phys(void *addr); static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo); static int assign_ctxt(struct hfi1_filedata *fd, unsigned long arg, u32 len); static void init_subctxts(struct hfi1_ctxtdata *uctxt, const struct hfi1_user_info *uinfo); static int init_user_ctxt(struct hfi1_filedata *fd, struct hfi1_ctxtdata *uctxt); static void user_init(struct hfi1_ctxtdata *uctxt); static int get_ctxt_info(struct hfi1_filedata *fd, void __user *ubase, __u32 len); static int get_base_info(struct hfi1_filedata *fd, void __user *ubase, __u32 len); static int get_ctxt_info(struct hfi1_filedata *fd, unsigned long arg, u32 len); static int get_base_info(struct hfi1_filedata *fd, unsigned long arg, u32 len); static int user_exp_rcv_setup(struct hfi1_filedata *fd, unsigned long arg, u32 len); static int user_exp_rcv_clear(struct hfi1_filedata *fd, unsigned long arg, u32 len); static int user_exp_rcv_invalid(struct hfi1_filedata *fd, unsigned long arg, u32 len); static int setup_base_ctxt(struct hfi1_filedata *fd, struct hfi1_ctxtdata *uctxt); static int setup_subctxt(struct hfi1_ctxtdata *uctxt); Loading @@ -101,10 +105,11 @@ static void deallocate_ctxt(struct hfi1_ctxtdata *uctxt); static unsigned int poll_urgent(struct file *fp, struct poll_table_struct *pt); static unsigned int poll_next(struct file *fp, struct poll_table_struct *pt); static int user_event_ack(struct hfi1_ctxtdata *uctxt, u16 subctxt, unsigned long events); static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, u16 subctxt, u16 pkey); unsigned long arg); static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, unsigned long arg); static int ctxt_reset(struct hfi1_ctxtdata *uctxt); static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, int start_stop); unsigned long arg); static int vma_fault(struct vm_fault *vmf); static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); Loading Loading @@ -221,13 +226,8 @@ static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, { 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; hfi1_cdbg(IOCTL, "IOCTL recv: 0x%x", cmd); if (cmd != HFI1_IOCTL_ASSIGN_CTXT && Loading @@ -237,171 +237,55 @@ static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, switch (cmd) { case HFI1_IOCTL_ASSIGN_CTXT: if (uctxt) return -EINVAL; if (copy_from_user(&uinfo, (struct hfi1_user_info __user *)arg, sizeof(uinfo))) return -EFAULT; ret = assign_ctxt(fd, &uinfo); ret = assign_ctxt(fd, arg, _IOC_SIZE(cmd)); break; case HFI1_IOCTL_CTXT_INFO: ret = get_ctxt_info(fd, (void __user *)(unsigned long)arg, sizeof(struct hfi1_ctxt_info)); ret = get_ctxt_info(fd, arg, _IOC_SIZE(cmd)); break; case HFI1_IOCTL_USER_INFO: ret = get_base_info(fd, (void __user *)(unsigned long)arg, sizeof(struct hfi1_base_info)); ret = get_base_info(fd, arg, _IOC_SIZE(cmd)); break; case HFI1_IOCTL_CREDIT_UPD: if (uctxt) 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(fd, &tinfo); if (!ret) { /* * Copy the number of tidlist entries we used * and the length of the buffer we registered. */ addr = arg + offsetof(struct hfi1_tid_info, tidcnt); if (copy_to_user((void __user *)addr, &tinfo.tidcnt, sizeof(tinfo.tidcnt))) return -EFAULT; addr = arg + offsetof(struct hfi1_tid_info, length); if (copy_to_user((void __user *)addr, &tinfo.length, sizeof(tinfo.length))) ret = -EFAULT; } ret = user_exp_rcv_setup(fd, arg, _IOC_SIZE(cmd)); 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(fd, &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; ret = user_exp_rcv_clear(fd, arg, _IOC_SIZE(cmd)); 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(fd, &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; ret = user_exp_rcv_invalid(fd, arg, _IOC_SIZE(cmd)); 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); ret = manage_rcvq(uctxt, fd->subctxt, arg); break; case HFI1_IOCTL_POLL_TYPE: ret = get_user(uval, (int __user *)arg); if (ret != 0) if (get_user(uval, (int __user *)arg)) 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); ret = user_event_ack(uctxt, fd->subctxt, arg); 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; ret = set_ctxt_pkey(uctxt, arg); 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); } else { ret = sc_restart(sc); } if (!ret) sc_return_credits(sc); case HFI1_IOCTL_CTXT_RESET: ret = ctxt_reset(uctxt); break; } case HFI1_IOCTL_GET_VERS: uval = HFI1_USER_SWVERSION; Loading Loading @@ -595,9 +479,8 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) * Use the page where this context's flags are. User level * knows where it's own bitmap is within the page. */ memaddr = (unsigned long)(dd->events + ((uctxt->ctxt - dd->first_dyn_alloc_ctxt) * HFI1_MAX_SHARED_CTXTS)) & PAGE_MASK; memaddr = (unsigned long) (dd->events + uctxt_offset(uctxt)) & PAGE_MASK; memlen = PAGE_SIZE; /* * v3.7 removes VM_RESERVED but the effect is kept by Loading Loading @@ -779,8 +662,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) * Clear any left over, unhandled events so the next process that * gets this context doesn't get confused. */ ev = dd->events + ((uctxt->ctxt - dd->first_dyn_alloc_ctxt) * HFI1_MAX_SHARED_CTXTS) + fdata->subctxt; ev = dd->events + uctxt_offset(uctxt) + fdata->subctxt; *ev = 0; spin_lock_irqsave(&dd->uctxt_lock, flags); Loading Loading @@ -891,20 +773,30 @@ static int complete_subctxt(struct hfi1_filedata *fd) return ret; } static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo) static int assign_ctxt(struct hfi1_filedata *fd, unsigned long arg, u32 len) { int ret; unsigned int swmajor, swminor; struct hfi1_ctxtdata *uctxt = NULL; struct hfi1_user_info uinfo; if (fd->uctxt) return -EINVAL; swmajor = uinfo->userversion >> 16; if (sizeof(uinfo) != len) return -EINVAL; if (copy_from_user(&uinfo, (void __user *)arg, sizeof(uinfo))) return -EFAULT; swmajor = uinfo.userversion >> 16; if (swmajor != HFI1_USER_SWMAJOR) return -ENODEV; if (uinfo->subctxt_cnt > HFI1_MAX_SHARED_CTXTS) if (uinfo.subctxt_cnt > HFI1_MAX_SHARED_CTXTS) return -EINVAL; swminor = uinfo->userversion & 0xffff; swminor = uinfo.userversion & 0xffff; /* * Acquire the mutex to protect against multiple creations of what Loading @@ -915,14 +807,14 @@ static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo) * Get a sub context if available (fd->uctxt will be set). * ret < 0 error, 0 no context, 1 sub-context found */ ret = find_sub_ctxt(fd, uinfo); ret = find_sub_ctxt(fd, &uinfo); /* * Allocate a base context if context sharing is not required or a * sub context wasn't found. */ if (!ret) ret = allocate_ctxt(fd, fd->dd, uinfo, &uctxt); ret = allocate_ctxt(fd, fd->dd, &uinfo, &uctxt); mutex_unlock(&hfi1_mutex); Loading Loading @@ -1237,12 +1129,13 @@ static void user_init(struct hfi1_ctxtdata *uctxt) hfi1_rcvctrl(uctxt->dd, rcvctrl_ops, uctxt); } static int get_ctxt_info(struct hfi1_filedata *fd, void __user *ubase, __u32 len) static int get_ctxt_info(struct hfi1_filedata *fd, unsigned long arg, u32 len) { struct hfi1_ctxt_info cinfo; struct hfi1_ctxtdata *uctxt = fd->uctxt; int ret = 0; if (sizeof(cinfo) != len) return -EINVAL; memset(&cinfo, 0, sizeof(cinfo)); cinfo.runtime_flags = (((uctxt->flags >> HFI1_CAP_MISC_SHIFT) & Loading Loading @@ -1272,10 +1165,10 @@ static int get_ctxt_info(struct hfi1_filedata *fd, void __user *ubase, cinfo.rcvegr_size = uctxt->egrbufs.rcvtid_size; trace_hfi1_ctxt_info(uctxt->dd, uctxt->ctxt, fd->subctxt, cinfo); if (copy_to_user(ubase, &cinfo, sizeof(cinfo))) ret = -EFAULT; if (copy_to_user((void __user *)arg, &cinfo, len)) return -EFAULT; return ret; return 0; } static int init_user_ctxt(struct hfi1_filedata *fd, Loading Loading @@ -1341,18 +1234,18 @@ static int setup_base_ctxt(struct hfi1_filedata *fd, return ret; } static int get_base_info(struct hfi1_filedata *fd, void __user *ubase, __u32 len) static int get_base_info(struct hfi1_filedata *fd, unsigned long arg, u32 len) { struct hfi1_base_info binfo; struct hfi1_ctxtdata *uctxt = fd->uctxt; struct hfi1_devdata *dd = uctxt->dd; ssize_t sz; unsigned offset; int ret = 0; trace_hfi1_uctxtdata(uctxt->dd, uctxt, fd->subctxt); if (sizeof(binfo) != len) return -EINVAL; memset(&binfo, 0, sizeof(binfo)); binfo.hw_version = dd->revision; binfo.sw_version = HFI1_KERN_SWVERSION; Loading Loading @@ -1389,8 +1282,7 @@ static int get_base_info(struct hfi1_filedata *fd, void __user *ubase, */ binfo.user_regbase = HFI1_MMAP_TOKEN(UREGS, uctxt->ctxt, fd->subctxt, 0); offset = offset_in_page((((uctxt->ctxt - dd->first_dyn_alloc_ctxt) * HFI1_MAX_SHARED_CTXTS) + fd->subctxt) * offset = offset_in_page((uctxt_offset(uctxt) + fd->subctxt) * sizeof(*dd->events)); binfo.events_bufbase = HFI1_MMAP_TOKEN(EVENTS, uctxt->ctxt, fd->subctxt, Loading @@ -1412,9 +1304,123 @@ static int get_base_info(struct hfi1_filedata *fd, void __user *ubase, uctxt->ctxt, fd->subctxt, 0); } sz = (len < sizeof(binfo)) ? len : sizeof(binfo); if (copy_to_user(ubase, &binfo, sz)) if (copy_to_user((void __user *)arg, &binfo, len)) return -EFAULT; return 0; } /** * user_exp_rcv_setup - Set up the given tid rcv list * @fd: file data of the current driver instance * @arg: ioctl argumnent for user space information * @len: length of data structure associated with ioctl command * * Wrapper to validate ioctl information before doing _rcv_setup. * */ static int user_exp_rcv_setup(struct hfi1_filedata *fd, unsigned long arg, u32 len) { int ret; unsigned long addr; struct hfi1_tid_info tinfo; if (sizeof(tinfo) != len) return -EINVAL; if (copy_from_user(&tinfo, (void __user *)arg, (sizeof(tinfo)))) return -EFAULT; ret = hfi1_user_exp_rcv_setup(fd, &tinfo); if (!ret) { /* * Copy the number of tidlist entries we used * and the length of the buffer we registered. */ addr = arg + offsetof(struct hfi1_tid_info, tidcnt); if (copy_to_user((void __user *)addr, &tinfo.tidcnt, sizeof(tinfo.tidcnt))) return -EFAULT; addr = arg + offsetof(struct hfi1_tid_info, length); if (copy_to_user((void __user *)addr, &tinfo.length, sizeof(tinfo.length))) ret = -EFAULT; } return ret; } /** * user_exp_rcv_clear - Clear the given tid rcv list * @fd: file data of the current driver instance * @arg: ioctl argumnent for user space information * @len: length of data structure associated with ioctl command * * The hfi1_user_exp_rcv_clear() can be called from the error path. Because * of this, we need to use this wrapper to copy the user space information * before doing the clear. */ static int user_exp_rcv_clear(struct hfi1_filedata *fd, unsigned long arg, u32 len) { int ret; unsigned long addr; struct hfi1_tid_info tinfo; if (sizeof(tinfo) != len) return -EINVAL; if (copy_from_user(&tinfo, (void __user *)arg, (sizeof(tinfo)))) return -EFAULT; ret = hfi1_user_exp_rcv_clear(fd, &tinfo); if (!ret) { addr = arg + offsetof(struct hfi1_tid_info, tidcnt); if (copy_to_user((void __user *)addr, &tinfo.tidcnt, sizeof(tinfo.tidcnt))) return -EFAULT; } return ret; } /** * user_exp_rcv_invalid - Invalidate the given tid rcv list * @fd: file data of the current driver instance * @arg: ioctl argumnent for user space information * @len: length of data structure associated with ioctl command * * Wrapper to validate ioctl information before doing _rcv_invalid. * */ static int user_exp_rcv_invalid(struct hfi1_filedata *fd, unsigned long arg, u32 len) { int ret; unsigned long addr; struct hfi1_tid_info tinfo; if (sizeof(tinfo) != len) return -EINVAL; if (!fd->invalid_tids) return -EINVAL; if (copy_from_user(&tinfo, (void __user *)arg, (sizeof(tinfo)))) return -EFAULT; ret = hfi1_user_exp_rcv_invalid(fd, &tinfo); if (ret) return ret; addr = arg + offsetof(struct hfi1_tid_info, tidcnt); if (copy_to_user((void __user *)addr, &tinfo.tidcnt, sizeof(tinfo.tidcnt))) ret = -EFAULT; return ret; } Loading Loading @@ -1482,14 +1488,13 @@ int hfi1_set_uevent_bits(struct hfi1_pportdata *ppd, const int evtbit) ctxt++) { uctxt = hfi1_rcd_get_by_index(dd, ctxt); if (uctxt) { unsigned long *evs = dd->events + (uctxt->ctxt - dd->first_dyn_alloc_ctxt) * HFI1_MAX_SHARED_CTXTS; unsigned long *evs; int i; /* * subctxt_cnt is 0 if not shared, so do base * separately, first, then remaining subctxt, if any */ evs = dd->events + uctxt_offset(uctxt); set_bit(evtbit, evs); for (i = 1; i < uctxt->subctxt_cnt; i++) set_bit(evtbit, evs + i); Loading @@ -1511,13 +1516,18 @@ int hfi1_set_uevent_bits(struct hfi1_pportdata *ppd, const int evtbit) * re-init the software copy of the head register */ static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, int start_stop) unsigned long arg) { struct hfi1_devdata *dd = uctxt->dd; unsigned int rcvctrl_op; int start_stop; if (subctxt) goto bail; return 0; if (get_user(start_stop, (int __user *)arg)) return -EFAULT; /* atomically clear receive enable ctxt. */ if (start_stop) { /* Loading @@ -1536,7 +1546,7 @@ static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, } hfi1_rcvctrl(dd, rcvctrl_op, uctxt); /* always; new head should be equal to new tail; see above */ bail: return 0; } Loading @@ -1546,17 +1556,20 @@ static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, * set, if desired, and checks again in future. */ static int user_event_ack(struct hfi1_ctxtdata *uctxt, u16 subctxt, unsigned long events) unsigned long arg) { int i; struct hfi1_devdata *dd = uctxt->dd; unsigned long *evs; unsigned long events; if (!dd->events) return 0; evs = dd->events + ((uctxt->ctxt - dd->first_dyn_alloc_ctxt) * HFI1_MAX_SHARED_CTXTS) + subctxt; if (get_user(events, (unsigned long __user *)arg)) return -EFAULT; evs = dd->events + uctxt_offset(uctxt) + subctxt; for (i = 0; i <= _HFI1_MAX_EVENT_BIT; i++) { if (!test_bit(i, &events)) Loading @@ -1566,26 +1579,89 @@ static int user_event_ack(struct hfi1_ctxtdata *uctxt, u16 subctxt, return 0; } static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, u16 subctxt, u16 pkey) static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, unsigned long arg) { int ret = -ENOENT, i, intable = 0; int i; struct hfi1_pportdata *ppd = uctxt->ppd; struct hfi1_devdata *dd = uctxt->dd; u16 pkey; if (pkey == LIM_MGMT_P_KEY || pkey == FULL_MGMT_P_KEY) { ret = -EINVAL; goto done; } if (!HFI1_CAP_IS_USET(PKEY_CHECK)) return -EPERM; if (get_user(pkey, (u16 __user *)arg)) return -EFAULT; if (pkey == LIM_MGMT_P_KEY || pkey == FULL_MGMT_P_KEY) return -EINVAL; for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) if (pkey == ppd->pkeys[i]) { intable = 1; break; if (pkey == ppd->pkeys[i]) return hfi1_set_ctxt_pkey(dd, uctxt, pkey); return -ENOENT; } if (intable) ret = hfi1_set_ctxt_pkey(dd, uctxt, pkey); done: /** * ctxt_reset - Reset the user context * @uctxt: valid user context */ static int ctxt_reset(struct hfi1_ctxtdata *uctxt) { struct send_context *sc; struct hfi1_devdata *dd; int ret = 0; 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, !(READ_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); } else { ret = sc_restart(sc); } if (!ret) sc_return_credits(sc); return ret; } Loading
drivers/infiniband/hw/hfi1/hfi.h +11 −7 File changed.Preview size limit exceeded, changes collapsed. Show changes