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); }
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; }
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; }