static ssize_t store_link_state(struct device *dev,
			 struct device_attribute *attr,
			  const char *buf,
			  size_t count)
{
	struct ipath_devdata *dd = dev_get_drvdata(dev);
	int ret, r;
	u16 state;

	ret = ipath_parse_ushort(buf, &state);
	if (ret < 0)
		goto invalid;

	r = ipath_set_linkstate(dd, state);
	if (r < 0) {
		ret = r;
		goto bail;
	}

	goto bail;
invalid:
	ipath_dev_err(dd, "attempt to set invalid link state\n");
bail:
	return ret;
}
Exemple #2
0
/**
 * ipath_diagpkt_write - write an IB packet
 * @fp: the diag data device file pointer
 * @data: ipath_diag_pkt structure saying where to get the packet
 * @count: size of data to write
 * @off: unused by this code
 */
static ssize_t ipath_diagpkt_write(struct file *fp,
				   const char __user *data,
				   size_t count, loff_t *off)
{
	u32 __iomem *piobuf;
	u32 plen, clen, pbufn;
	struct ipath_diag_pkt dp;
	u32 *tmpbuf = NULL;
	struct ipath_devdata *dd;
	ssize_t ret = 0;
	u64 val;

	if (count < sizeof(dp)) {
		ret = -EINVAL;
		goto bail;
	}

	if (copy_from_user(&dp, data, sizeof(dp))) {
		ret = -EFAULT;
		goto bail;
	}

	/* send count must be an exact number of dwords */
	if (dp.len & 3) {
		ret = -EINVAL;
		goto bail;
	}

	clen = dp.len >> 2;

	dd = ipath_lookup(dp.unit);
	if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
	    !dd->ipath_kregbase) {
		ipath_cdbg(VERBOSE, "illegal unit %u for diag data send\n",
			   dp.unit);
		ret = -ENODEV;
		goto bail;
	}

	if (ipath_diag_inuse && !diag_set_link &&
	    !(dd->ipath_flags & IPATH_LINKACTIVE)) {
		diag_set_link = 1;
		ipath_cdbg(VERBOSE, "Trying to set to set link active for "
			   "diag pkt\n");
		ipath_set_linkstate(dd, IPATH_IB_LINKARM);
		ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
	}

	if (!(dd->ipath_flags & IPATH_INITTED)) {
		/* no hardware, freeze, etc. */
		ipath_cdbg(VERBOSE, "unit %u not usable\n", dd->ipath_unit);
		ret = -ENODEV;
		goto bail;
	}
	val = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK;
	if (val != IPATH_IBSTATE_INIT && val != IPATH_IBSTATE_ARM &&
	    val != IPATH_IBSTATE_ACTIVE) {
		ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n",
			   dd->ipath_unit, (unsigned long long) val);
		ret = -EINVAL;
		goto bail;
	}

	/* need total length before first word written */
	/* +1 word is for the qword padding */
	plen = sizeof(u32) + dp.len;

	if ((plen + 4) > dd->ipath_ibmaxlen) {
		ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
			  plen - 4, dd->ipath_ibmaxlen);
		ret = -EINVAL;
		goto bail;	/* before writing pbc */
	}
	tmpbuf = vmalloc(plen);
	if (!tmpbuf) {
		dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
			 "failing\n");
		ret = -ENOMEM;
		goto bail;
	}

	if (copy_from_user(tmpbuf,
			   (const void __user *) (unsigned long) dp.data,
			   dp.len)) {
		ret = -EFAULT;
		goto bail;
	}

	piobuf = ipath_getpiobuf(dd, &pbufn);
	if (!piobuf) {
		ipath_cdbg(VERBOSE, "No PIO buffers avail unit for %u\n",
			   dd->ipath_unit);
		ret = -EBUSY;
		goto bail;
	}

	plen >>= 2;		/* in dwords */

	if (ipath_debug & __IPATH_PKTDBG)
		ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n",
			   dd->ipath_unit, plen - 1, pbufn);

	/* we have to flush after the PBC for correctness on some cpus
	 * or WC buffer can be written out of order */
	writeq(plen, piobuf);
	ipath_flush_wc();
	/* copy all by 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. */
	__iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
	ipath_flush_wc();
	__raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
	ipath_flush_wc();

	ret = sizeof(dp);

bail:
	vfree(tmpbuf);
	return ret;
}
Exemple #3
0
/**
 * ipath_diagpkt_write - write an IB packet
 * @fp: the diag data device file pointer
 * @data: ipath_diag_pkt structure saying where to get the packet
 * @count: size of data to write
 * @off: unused by this code
 */
static ssize_t ipath_diagpkt_write(struct file *fp,
				   const char __user *data,
				   size_t count, loff_t *off)
{
	u32 __iomem *piobuf;
	u32 plen, clen, pbufn;
	struct ipath_diag_pkt odp;
	struct ipath_diag_xpkt dp;
	u32 *tmpbuf = NULL;
	struct ipath_devdata *dd;
	ssize_t ret = 0;
	u64 val;
	u32 l_state, lt_state; /* LinkState, LinkTrainingState */

	if (count < sizeof(odp)) {
		ret = -EINVAL;
		goto bail;
	}

	if (count == sizeof(dp)) {
		if (copy_from_user(&dp, data, sizeof(dp))) {
			ret = -EFAULT;
			goto bail;
		}
	} else if (copy_from_user(&odp, data, sizeof(odp))) {
		ret = -EFAULT;
		goto bail;
	}

	/*
	 * Due to padding/alignment issues (lessened with new struct)
	 * the old and new structs are the same length. We need to
	 * disambiguate them, which we can do because odp.len has never
	 * been less than the total of LRH+BTH+DETH so far, while
	 * dp.unit (same offset) unit is unlikely to get that high.
	 * Similarly, dp.data, the pointer to user at the same offset
	 * as odp.unit, is almost certainly at least one (512byte)page
	 * "above" NULL. The if-block below can be omitted if compatibility
	 * between a new driver and older diagnostic code is unimportant.
	 * compatibility the other direction (new diags, old driver) is
	 * handled in the diagnostic code, with a warning.
	 */
	if (dp.unit >= 20 && dp.data < 512) {
		/* very probable version mismatch. Fix it up */
		memcpy(&odp, &dp, sizeof(odp));
		/* We got a legacy dp, copy elements to dp */
		dp.unit = odp.unit;
		dp.data = odp.data;
		dp.len = odp.len;
		dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */
	}

	/* send count must be an exact number of dwords */
	if (dp.len & 3) {
		ret = -EINVAL;
		goto bail;
	}

	clen = dp.len >> 2;

	dd = ipath_lookup(dp.unit);
	if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
	    !dd->ipath_kregbase) {
		ipath_cdbg(VERBOSE, "illegal unit %u for diag data send\n",
			   dp.unit);
		ret = -ENODEV;
		goto bail;
	}

	if (ipath_diag_inuse && !diag_set_link &&
	    !(dd->ipath_flags & IPATH_LINKACTIVE)) {
		diag_set_link = 1;
		ipath_cdbg(VERBOSE, "Trying to set to set link active for "
			   "diag pkt\n");
		ipath_set_linkstate(dd, IPATH_IB_LINKARM);
		ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
	}

	if (!(dd->ipath_flags & IPATH_INITTED)) {
		/* no hardware, freeze, etc. */
		ipath_cdbg(VERBOSE, "unit %u not usable\n", dd->ipath_unit);
		ret = -ENODEV;
		goto bail;
	}
	/*
	 * Want to skip check for l_state if using custom PBC,
	 * because we might be trying to force an SM packet out.
	 * first-cut, skip _all_ state checking in that case.
	 */
	val = ipath_ib_state(dd, dd->ipath_lastibcstat);
	lt_state = ipath_ib_linktrstate(dd, dd->ipath_lastibcstat);
	l_state = ipath_ib_linkstate(dd, dd->ipath_lastibcstat);
	if (!dp.pbc_wd && (lt_state != INFINIPATH_IBCS_LT_STATE_LINKUP ||
	    (val != dd->ib_init && val != dd->ib_arm &&
	    val != dd->ib_active))) {
		ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n",
			   dd->ipath_unit, (unsigned long long) val);
		ret = -EINVAL;
		goto bail;
	}

	/* need total length before first word written */
	/* +1 word is for the qword padding */
	plen = sizeof(u32) + dp.len;

	if ((plen + 4) > dd->ipath_ibmaxlen) {
		ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
			  plen - 4, dd->ipath_ibmaxlen);
		ret = -EINVAL;
		goto bail;	/* before writing pbc */
	}
	tmpbuf = vmalloc(plen);
	if (!tmpbuf) {
		dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
			 "failing\n");
		ret = -ENOMEM;
		goto bail;
	}

	if (copy_from_user(tmpbuf,
			   (const void __user *) (unsigned long) dp.data,
			   dp.len)) {
		ret = -EFAULT;
		goto bail;
	}

	plen >>= 2;		/* in dwords */

	piobuf = ipath_getpiobuf(dd, plen, &pbufn);
	if (!piobuf) {
		ipath_cdbg(VERBOSE, "No PIO buffers avail unit for %u\n",
			   dd->ipath_unit);
		ret = -EBUSY;
		goto bail;
	}
	/* disarm it just to be extra sure */
	ipath_disarm_piobufs(dd, pbufn, 1);

	if (ipath_debug & __IPATH_PKTDBG)
		ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n",
			   dd->ipath_unit, plen - 1, pbufn);

	if (dp.pbc_wd == 0)
		dp.pbc_wd = plen;
	writeq(dp.pbc_wd, piobuf);
	/*
	 * Copy all by 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->ipath_flags & IPATH_PIO_FLUSH_WC) {
		ipath_flush_wc();
		__iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
		ipath_flush_wc();
		__raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
	} else
		__iowrite32_copy(piobuf + 2, tmpbuf, clen);

	ipath_flush_wc();

	ret = sizeof(dp);

bail:
	vfree(tmpbuf);
	return ret;
}
Exemple #4
0
/**
 * ipath_diagpkt_write - write an IB packet
 * @fp: the diag data device file pointer
 * @data: ipath_diag_pkt structure saying where to get the packet
 * @count: size of data to write
 * @off: unused by this code
 */
static ssize_t ipath_diagpkt_write(struct file *fp,
				   const char __user *data,
				   size_t count, loff_t *off)
{
	u32 __iomem *piobuf;
	u32 plen, pbufn, maxlen_reserve;
	struct ipath_diag_pkt odp;
	struct ipath_diag_xpkt dp;
	u32 *tmpbuf = NULL;
	struct ipath_devdata *dd;
	ssize_t ret = 0;
	u64 val;
	u32 l_state, lt_state; /* LinkState, LinkTrainingState */


	if (count == sizeof(dp)) {
		if (copy_from_user(&dp, data, sizeof(dp))) {
			ret = -EFAULT;
			goto bail;
		}
	} else if (count == sizeof(odp)) {
		if (copy_from_user(&odp, data, sizeof(odp))) {
			ret = -EFAULT;
			goto bail;
		}
	} else {
		ret = -EINVAL;
		goto bail;
	}

	/* send count must be an exact number of dwords */
	if (dp.len & 3) {
		ret = -EINVAL;
		goto bail;
	}

	plen = dp.len >> 2;

	dd = ipath_lookup(dp.unit);
	if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
	    !dd->ipath_kregbase) {
		ipath_cdbg(VERBOSE, "illegal unit %u for diag data send\n",
			   dp.unit);
		ret = -ENODEV;
		goto bail;
	}

	if (ipath_diag_inuse && !diag_set_link &&
	    !(dd->ipath_flags & IPATH_LINKACTIVE)) {
		diag_set_link = 1;
		ipath_cdbg(VERBOSE, "Trying to set to set link active for "
			   "diag pkt\n");
		ipath_set_linkstate(dd, IPATH_IB_LINKARM);
		ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
	}

	if (!(dd->ipath_flags & IPATH_INITTED)) {
		/* no hardware, freeze, etc. */
		ipath_cdbg(VERBOSE, "unit %u not usable\n", dd->ipath_unit);
		ret = -ENODEV;
		goto bail;
	}
	/*
	 * Want to skip check for l_state if using custom PBC,
	 * because we might be trying to force an SM packet out.
	 * first-cut, skip _all_ state checking in that case.
	 */
	val = ipath_ib_state(dd, dd->ipath_lastibcstat);
	lt_state = ipath_ib_linktrstate(dd, dd->ipath_lastibcstat);
	l_state = ipath_ib_linkstate(dd, dd->ipath_lastibcstat);
	if (!dp.pbc_wd && (lt_state != INFINIPATH_IBCS_LT_STATE_LINKUP ||
	    (val != dd->ib_init && val != dd->ib_arm &&
	    val != dd->ib_active))) {
		ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n",
			   dd->ipath_unit, (unsigned long long) val);
		ret = -EINVAL;
		goto bail;
	}

	/*
	 * 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 > dd->ipath_ibmaxlen - maxlen_reserve) {
		ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
			  dp.len, dd->ipath_ibmaxlen);
		ret = -EINVAL;
		goto bail;
	}

	plen = sizeof(u32) + dp.len;

	tmpbuf = vmalloc(plen);
	if (!tmpbuf) {
		dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
			 "failing\n");
		ret = -ENOMEM;
		goto bail;
	}

	if (copy_from_user(tmpbuf,
			   (const void __user *) (unsigned long) dp.data,
			   dp.len)) {
		ret = -EFAULT;
		goto bail;
	}

	plen >>= 2;		/* in dwords */

	piobuf = ipath_getpiobuf(dd, plen, &pbufn);
	if (!piobuf) {
		ipath_cdbg(VERBOSE, "No PIO buffers avail unit for %u\n",
			   dd->ipath_unit);
		ret = -EBUSY;
		goto bail;
	}
	/* disarm it just to be extra sure */
	ipath_disarm_piobufs(dd, pbufn, 1);

	if (ipath_debug & __IPATH_PKTDBG)
		ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n",
			   dd->ipath_unit, plen - 1, pbufn);

	if (dp.pbc_wd == 0)
		dp.pbc_wd = plen;
	writeq(dp.pbc_wd, piobuf);
	/*
	 * Copy all by 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->ipath_flags & IPATH_PIO_FLUSH_WC) {
		ipath_flush_wc();
		__iowrite32_copy(piobuf + 2, tmpbuf, plen - 1);
		ipath_flush_wc();
		__raw_writel(tmpbuf[plen - 1], piobuf + plen + 1);
	} else
		__iowrite32_copy(piobuf + 2, tmpbuf, plen);

	ipath_flush_wc();

	ret = sizeof(dp);

bail:
	vfree(tmpbuf);
	return ret;
}