in hw/qib/qib_user_sdma.c [802:1051]
static int qib_user_sdma_queue_pkts(const struct qib_devdata *dd,
struct qib_pportdata *ppd,
struct qib_user_sdma_queue *pq,
const struct iovec *iov,
unsigned long niov,
struct list_head *list,
int *maxpkts, int *ndesc)
{
unsigned long idx = 0;
int ret = 0;
int npkts = 0;
__le32 *pbc;
dma_addr_t dma_addr;
struct qib_user_sdma_pkt *pkt = NULL;
size_t len;
size_t nw;
u32 counter = pq->counter;
u16 frag_size;
while (idx < niov && npkts < *maxpkts) {
const unsigned long addr = (unsigned long) iov[idx].iov_base;
const unsigned long idx_save = idx;
unsigned pktnw;
unsigned pktnwc;
int nfrags = 0;
size_t npages = 0;
size_t bytes_togo = 0;
int tiddma = 0;
int cfur;
len = iov[idx].iov_len;
nw = len >> 2;
if (len < QIB_USER_SDMA_MIN_HEADER_LENGTH ||
len > PAGE_SIZE || len & 3 || addr & 3) {
ret = -EINVAL;
goto free_list;
}
pbc = qib_user_sdma_alloc_header(pq, len, &dma_addr);
if (!pbc) {
ret = -ENOMEM;
goto free_list;
}
cfur = copy_from_user(pbc, iov[idx].iov_base, len);
if (cfur) {
ret = -EFAULT;
goto free_pbc;
}
/*
* This assignment is a bit strange. it's because the
* the pbc counts the number of 32 bit words in the full
* packet _except_ the first word of the pbc itself...
*/
pktnwc = nw - 1;
/*
* pktnw computation yields the number of 32 bit words
* that the caller has indicated in the PBC. note that
* this is one less than the total number of words that
* goes to the send DMA engine as the first 32 bit word
* of the PBC itself is not counted. Armed with this count,
* we can verify that the packet is consistent with the
* iovec lengths.
*/
pktnw = le32_to_cpu(*pbc) & 0xFFFF;
if (pktnw < pktnwc) {
ret = -EINVAL;
goto free_pbc;
}
idx++;
while (pktnwc < pktnw && idx < niov) {
const size_t slen = iov[idx].iov_len;
const unsigned long faddr =
(unsigned long) iov[idx].iov_base;
if (slen & 3 || faddr & 3 || !slen) {
ret = -EINVAL;
goto free_pbc;
}
npages += qib_user_sdma_num_pages(&iov[idx]);
if (check_add_overflow(bytes_togo, slen, &bytes_togo) ||
bytes_togo > type_max(typeof(pkt->bytes_togo))) {
ret = -EINVAL;
goto free_pbc;
}
pktnwc += slen >> 2;
idx++;
nfrags++;
}
if (pktnwc != pktnw) {
ret = -EINVAL;
goto free_pbc;
}
frag_size = ((le32_to_cpu(*pbc))>>16) & 0xFFFF;
if (((frag_size ? frag_size : bytes_togo) + len) >
ppd->ibmaxlen) {
ret = -EINVAL;
goto free_pbc;
}
if (frag_size) {
size_t tidsmsize, n, pktsize, sz, addrlimit;
n = npages*((2*PAGE_SIZE/frag_size)+1);
pktsize = struct_size(pkt, addr, n);
/*
* Determine if this is tid-sdma or just sdma.
*/
tiddma = (((le32_to_cpu(pbc[7])>>
QLOGIC_IB_I_TID_SHIFT)&
QLOGIC_IB_I_TID_MASK) !=
QLOGIC_IB_I_TID_MASK);
if (tiddma)
tidsmsize = iov[idx].iov_len;
else
tidsmsize = 0;
if (check_add_overflow(pktsize, tidsmsize, &sz)) {
ret = -EINVAL;
goto free_pbc;
}
pkt = kmalloc(sz, GFP_KERNEL);
if (!pkt) {
ret = -ENOMEM;
goto free_pbc;
}
pkt->largepkt = 1;
pkt->frag_size = frag_size;
if (check_add_overflow(n, ARRAY_SIZE(pkt->addr),
&addrlimit) ||
addrlimit > type_max(typeof(pkt->addrlimit))) {
ret = -EINVAL;
goto free_pkt;
}
pkt->addrlimit = addrlimit;
if (tiddma) {
char *tidsm = (char *)pkt + pktsize;
cfur = copy_from_user(tidsm,
iov[idx].iov_base, tidsmsize);
if (cfur) {
ret = -EFAULT;
goto free_pkt;
}
pkt->tidsm =
(struct qib_tid_session_member *)tidsm;
pkt->tidsmcount = tidsmsize/
sizeof(struct qib_tid_session_member);
pkt->tidsmidx = 0;
idx++;
}
/*
* pbc 'fill1' field is borrowed to pass frag size,
* we need to clear it after picking frag size, the
* hardware requires this field to be zero.
*/
*pbc = cpu_to_le32(le32_to_cpu(*pbc) & 0x0000FFFF);
} else {
pkt = kmem_cache_alloc(pq->pkt_slab, GFP_KERNEL);
if (!pkt) {
ret = -ENOMEM;
goto free_pbc;
}
pkt->largepkt = 0;
pkt->frag_size = bytes_togo;
pkt->addrlimit = ARRAY_SIZE(pkt->addr);
}
pkt->bytes_togo = bytes_togo;
pkt->payload_size = 0;
pkt->counter = counter;
pkt->tiddma = tiddma;
/* setup the first header */
qib_user_sdma_init_frag(pkt, 0, /* index */
0, len, /* offset, len */
1, 0, /* first last desc */
0, 0, /* put page, dma mapped */
NULL, pbc, /* struct page, virt addr */
dma_addr, len); /* dma addr, dma length */
pkt->index = 0;
pkt->naddr = 1;
if (nfrags) {
ret = qib_user_sdma_init_payload(dd, pq, pkt,
iov + idx_save + 1,
nfrags, npages);
if (ret < 0)
goto free_pkt;
} else {
/* since there is no payload, mark the
* header as the last desc. */
pkt->addr[0].last_desc = 1;
if (dma_addr == 0) {
/*
* the header is not dma mapped yet.
* it should be from kmalloc.
*/
dma_addr = dma_map_single(&dd->pcidev->dev,
pbc, len, DMA_TO_DEVICE);
if (dma_mapping_error(&dd->pcidev->dev,
dma_addr)) {
ret = -ENOMEM;
goto free_pkt;
}
pkt->addr[0].addr = dma_addr;
pkt->addr[0].dma_mapped = 1;
}
}
counter++;
npkts++;
pkt->pq = pq;
pkt->index = 0; /* reset index for push on hw */
*ndesc += pkt->naddr;
list_add_tail(&pkt->list, list);
}
*maxpkts = npkts;
ret = idx;
goto done;
free_pkt:
if (pkt->largepkt)
kfree(pkt);
else
kmem_cache_free(pq->pkt_slab, pkt);
free_pbc:
if (dma_addr)
dma_pool_free(pq->header_cache, pbc, dma_addr);
else
kfree(pbc);
free_list:
qib_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, list);
done:
return ret;
}