/* * This is called by a user process when it sees the DISARM_BUFS event * bit is set. */ int qib_disarm_piobufs_ifneeded(struct qib_ctxtdata *rcd) { struct qib_devdata *dd = rcd->dd; unsigned i; unsigned last; unsigned n = 0; last = rcd->pio_base + rcd->piocnt; /* * Don't need uctxt_lock here, since user has called in to us. * Clear at start in case more interrupts set bits while we * are disarming */ if (rcd->user_event_mask) { /* * subctxt_cnt is 0 if not shared, so do base * separately, first, then remaining subctxt, if any */ clear_bit(_QIB_EVENT_DISARM_BUFS_BIT, &rcd->user_event_mask[0]); for (i = 1; i < rcd->subctxt_cnt; i++) clear_bit(_QIB_EVENT_DISARM_BUFS_BIT, &rcd->user_event_mask[i]); } spin_lock_irq(&dd->pioavail_lock); for (i = rcd->pio_base; i < last; i++) { if (__test_and_clear_bit(i, dd->pio_need_disarm)) { n++; dd->f_sendctrl(rcd->ppd, QIB_SENDCTRL_DISARM_BUF(i)); } } spin_unlock_irq(&dd->pioavail_lock); return 0; }
/** * qib_disarm_piobufs - cancel a range of PIO buffers * @dd: the qlogic_ib device * @first: the first PIO buffer to cancel * @cnt: the number of PIO buffers to cancel * * Cancel a range of PIO buffers. Used at user process close, * in case it died while writing to a PIO buffer. */ void qib_disarm_piobufs(struct qib_devdata *dd, unsigned first, unsigned cnt) { unsigned long flags; unsigned i; unsigned last; last = first + cnt; spin_lock_irqsave(&dd->pioavail_lock, flags); for (i = first; i < last; i++) { __clear_bit(i, dd->pio_need_disarm); dd->f_sendctrl(dd->pport, QIB_SENDCTRL_DISARM_BUF(i)); } spin_unlock_irqrestore(&dd->pioavail_lock, flags); }
/** * qib_diagpkt_write - write an IB packet * @fp: the diag data device file pointer * @data: qib_diag_pkt structure saying where to get the packet * @count: size of data to write * @off: unused by this code */ static ssize_t qib_diagpkt_write(struct file *fp, const char __user *data, size_t count, loff_t *off) { u32 __iomem *piobuf; u32 plen, pbufn, maxlen_reserve; struct qib_diag_xpkt dp; u32 *tmpbuf = NULL; struct qib_devdata *dd; struct qib_pportdata *ppd; ssize_t ret = 0; if (count != sizeof(dp)) { ret = -EINVAL; goto bail; } if (copy_from_user(&dp, data, sizeof(dp))) { ret = -EFAULT; goto bail; } dd = qib_lookup(dp.unit); if (!dd || !(dd->flags & QIB_PRESENT) || !dd->kregbase) { ret = -ENODEV; goto bail; } if (!(dd->flags & QIB_INITTED)) { /* no hardware, freeze, etc. */ ret = -ENODEV; goto bail; } if (dp.version != _DIAG_XPKT_VERS) { qib_dev_err(dd, "Invalid version %u for diagpkt_write\n", dp.version); ret = -EINVAL; goto bail; } /* send count must be an exact number of dwords */ if (dp.len & 3) { ret = -EINVAL; goto bail; } if (!dp.port || dp.port > dd->num_pports) { ret = -EINVAL; goto bail; } ppd = &dd->pport[dp.port - 1]; /* * need total length before first word written, plus 2 Dwords. One Dword * is for padding so we get the full user data when not aligned on * a word boundary. The other Dword is to make sure we have room for the * ICRC which gets tacked on later. */ maxlen_reserve = 2 * sizeof(u32); if (dp.len > ppd->ibmaxlen - maxlen_reserve) { ret = -EINVAL; goto bail; } plen = sizeof(u32) + dp.len; tmpbuf = vmalloc(plen); if (!tmpbuf) { ret = -ENOMEM; goto bail; } if (copy_from_user(tmpbuf, u64_to_user_ptr(dp.data), dp.len)) { ret = -EFAULT; goto bail; } plen >>= 2; /* in dwords */ if (dp.pbc_wd == 0) dp.pbc_wd = plen; piobuf = dd->f_getsendbuf(ppd, dp.pbc_wd, &pbufn); if (!piobuf) { ret = -EBUSY; goto bail; } /* disarm it just to be extra sure */ dd->f_sendctrl(dd->pport, QIB_SENDCTRL_DISARM_BUF(pbufn)); /* disable header check on pbufn for this packet */ dd->f_txchk_change(dd, pbufn, 1, TXCHK_CHG_TYPE_DIS1, NULL); writeq(dp.pbc_wd, piobuf); /* * Copy all but the trigger word, then flush, so it's written * to chip before trigger word, then write trigger word, then * flush again, so packet is sent. */ if (dd->flags & QIB_PIO_FLUSH_WC) { qib_flush_wc(); qib_pio_copy(piobuf + 2, tmpbuf, plen - 1); qib_flush_wc(); __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1); } else qib_pio_copy(piobuf + 2, tmpbuf, plen); if (dd->flags & QIB_USE_SPCL_TRIG) { u32 spcl_off = (pbufn >= dd->piobcnt2k) ? 2047 : 1023; qib_flush_wc(); __raw_writel(0xaebecede, piobuf + spcl_off); } /* * Ensure buffer is written to the chip, then re-enable * header checks (if supported by chip). The txchk * code will ensure seen by chip before returning. */ qib_flush_wc(); qib_sendbuf_done(dd, pbufn); dd->f_txchk_change(dd, pbufn, 1, TXCHK_CHG_TYPE_ENAB1, NULL); ret = sizeof(dp); bail: vfree(tmpbuf); return ret; }