Пример #1
0
static int
ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, size_t size)
{
	struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
	size_t xlat_size, buff_size;
	int rc;

	if (size == 0)
		return (EINVAL);

	xlat_size = roundup(size, mw->xlat_align_size);
	buff_size = xlat_size;

	/* No need to re-setup */
	if (mw->xlat_size == xlat_size)
		return (0);

	if (mw->buff_size != 0)
		ntb_free_mw(nt, num_mw);

	/* Alloc memory for receiving data.  Must be aligned */
	mw->xlat_size = xlat_size;
	mw->buff_size = buff_size;

	mw->virt_addr = contigmalloc(mw->buff_size, M_NTB_IF, M_ZERO, 0,
	    mw->addr_limit, mw->xlat_align, 0);
	if (mw->virt_addr == NULL) {
		ntb_printf(0, "Unable to allocate MW buffer of size %zu/%zu\n",
		    mw->buff_size, mw->xlat_size);
		mw->xlat_size = 0;
		mw->buff_size = 0;
		return (ENOMEM);
	}
	/* TODO: replace with bus_space_* functions */
	mw->dma_addr = vtophys(mw->virt_addr);

	/*
	 * Ensure that the allocation from contigmalloc is aligned as
	 * requested.  XXX: This may not be needed -- brought in for parity
	 * with the Linux driver.
	 */
	if (mw->dma_addr % mw->xlat_align != 0) {
		ntb_printf(0,
		    "DMA memory 0x%jx not aligned to BAR size 0x%zx\n",
		    (uintmax_t)mw->dma_addr, size);
		ntb_free_mw(nt, num_mw);
		return (ENOMEM);
	}

	/* Notify HW the memory location of the receive buffer */
	rc = ntb_mw_set_trans(nt->ntb, num_mw, mw->dma_addr, mw->xlat_size);
	if (rc) {
		ntb_printf(0, "Unable to set mw%d translation\n", num_mw);
		ntb_free_mw(nt, num_mw);
		return (rc);
	}

	return (0);
}
Пример #2
0
static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size)
{
	int rc;
	struct tool_mw *mw = &tc->mws[idx];
	resource_size_t size, align_addr, align_size;
	char buf[16];

	if (mw->peer)
		return 0;

	rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr,
				&align_size, &size);
	if (rc)
		return rc;

	mw->size = min_t(resource_size_t, req_size, size);
	mw->size = round_up(mw->size, align_addr);
	mw->size = round_up(mw->size, align_size);
	mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
				      &mw->peer_dma, GFP_KERNEL);

	if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr))
		return -ENOMEM;

	rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size);
	if (rc)
		goto err_free_dma;

	snprintf(buf, sizeof(buf), "peer_mw%d", idx);
	mw->peer_dbg_file = debugfs_create_file(buf, S_IRUSR | S_IWUSR,
						mw->tc->dbgfs, mw,
						&tool_peer_mw_fops);

	return 0;

err_free_dma:
	dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
			  mw->peer,
			  mw->peer_dma);
	mw->peer = NULL;
	mw->peer_dma = 0;
	mw->size = 0;

	return rc;
}
Пример #3
0
static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
{
	struct perf_mw *mw = &perf->mw;
	size_t xlat_size, buf_size;
	int rc;

	if (!size)
		return -EINVAL;

	xlat_size = round_up(size, mw->xlat_align_size);
	buf_size = round_up(size, mw->xlat_align);

	if (mw->xlat_size == xlat_size)
		return 0;

	if (mw->buf_size)
		perf_free_mw(perf);

	mw->xlat_size = xlat_size;
	mw->buf_size = buf_size;

	mw->virt_addr = dma_alloc_coherent(&perf->ntb->pdev->dev, buf_size,
					   &mw->dma_addr, GFP_KERNEL);
	if (!mw->virt_addr) {
		mw->xlat_size = 0;
		mw->buf_size = 0;
	}

	rc = ntb_mw_set_trans(perf->ntb, 0, mw->dma_addr, mw->xlat_size);
	if (rc) {
		dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n");
		perf_free_mw(perf);
		return -EIO;
	}

	return 0;
}