18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2007, 2008, 2009 QLogic Corporation. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
58c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
118c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
128c2ecf20Sopenharmony_ci *     conditions are met:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
158c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
168c2ecf20Sopenharmony_ci *        disclaimer.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
198c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
218c2ecf20Sopenharmony_ci *        provided with the distribution.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
308c2ecf20Sopenharmony_ci * SOFTWARE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci#include <linux/mm.h>
338c2ecf20Sopenharmony_ci#include <linux/types.h>
348c2ecf20Sopenharmony_ci#include <linux/device.h>
358c2ecf20Sopenharmony_ci#include <linux/dmapool.h>
368c2ecf20Sopenharmony_ci#include <linux/slab.h>
378c2ecf20Sopenharmony_ci#include <linux/list.h>
388c2ecf20Sopenharmony_ci#include <linux/highmem.h>
398c2ecf20Sopenharmony_ci#include <linux/io.h>
408c2ecf20Sopenharmony_ci#include <linux/uio.h>
418c2ecf20Sopenharmony_ci#include <linux/rbtree.h>
428c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
438c2ecf20Sopenharmony_ci#include <linux/delay.h>
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#include "qib.h"
468c2ecf20Sopenharmony_ci#include "qib_user_sdma.h"
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* minimum size of header */
498c2ecf20Sopenharmony_ci#define QIB_USER_SDMA_MIN_HEADER_LENGTH 64
508c2ecf20Sopenharmony_ci/* expected size of headers (for dma_pool) */
518c2ecf20Sopenharmony_ci#define QIB_USER_SDMA_EXP_HEADER_LENGTH 64
528c2ecf20Sopenharmony_ci/* attempt to drain the queue for 5secs */
538c2ecf20Sopenharmony_ci#define QIB_USER_SDMA_DRAIN_TIMEOUT 250
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/*
568c2ecf20Sopenharmony_ci * track how many times a process open this driver.
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_cistatic struct rb_root qib_user_sdma_rb_root = RB_ROOT;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistruct qib_user_sdma_rb_node {
618c2ecf20Sopenharmony_ci	struct rb_node node;
628c2ecf20Sopenharmony_ci	int refcount;
638c2ecf20Sopenharmony_ci	pid_t pid;
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistruct qib_user_sdma_pkt {
678c2ecf20Sopenharmony_ci	struct list_head list;  /* list element */
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	u8  tiddma;		/* if this is NEW tid-sdma */
708c2ecf20Sopenharmony_ci	u8  largepkt;		/* this is large pkt from kmalloc */
718c2ecf20Sopenharmony_ci	u16 frag_size;		/* frag size used by PSM */
728c2ecf20Sopenharmony_ci	u16 index;              /* last header index or push index */
738c2ecf20Sopenharmony_ci	u16 naddr;              /* dimension of addr (1..3) ... */
748c2ecf20Sopenharmony_ci	u16 addrlimit;		/* addr array size */
758c2ecf20Sopenharmony_ci	u16 tidsmidx;		/* current tidsm index */
768c2ecf20Sopenharmony_ci	u16 tidsmcount;		/* tidsm array item count */
778c2ecf20Sopenharmony_ci	u16 payload_size;	/* payload size so far for header */
788c2ecf20Sopenharmony_ci	u32 bytes_togo;		/* bytes for processing */
798c2ecf20Sopenharmony_ci	u32 counter;            /* sdma pkts queued counter for this entry */
808c2ecf20Sopenharmony_ci	struct qib_tid_session_member *tidsm;	/* tid session member array */
818c2ecf20Sopenharmony_ci	struct qib_user_sdma_queue *pq;	/* which pq this pkt belongs to */
828c2ecf20Sopenharmony_ci	u64 added;              /* global descq number of entries */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	struct {
858c2ecf20Sopenharmony_ci		u16 offset;                     /* offset for kvaddr, addr */
868c2ecf20Sopenharmony_ci		u16 length;                     /* length in page */
878c2ecf20Sopenharmony_ci		u16 first_desc;			/* first desc */
888c2ecf20Sopenharmony_ci		u16 last_desc;			/* last desc */
898c2ecf20Sopenharmony_ci		u16 put_page;                   /* should we put_page? */
908c2ecf20Sopenharmony_ci		u16 dma_mapped;                 /* is page dma_mapped? */
918c2ecf20Sopenharmony_ci		u16 dma_length;			/* for dma_unmap_page() */
928c2ecf20Sopenharmony_ci		u16 padding;
938c2ecf20Sopenharmony_ci		struct page *page;              /* may be NULL (coherent mem) */
948c2ecf20Sopenharmony_ci		void *kvaddr;                   /* FIXME: only for pio hack */
958c2ecf20Sopenharmony_ci		dma_addr_t addr;
968c2ecf20Sopenharmony_ci	} addr[4];   /* max pages, any more and we coalesce */
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistruct qib_user_sdma_queue {
1008c2ecf20Sopenharmony_ci	/*
1018c2ecf20Sopenharmony_ci	 * pkts sent to dma engine are queued on this
1028c2ecf20Sopenharmony_ci	 * list head.  the type of the elements of this
1038c2ecf20Sopenharmony_ci	 * list are struct qib_user_sdma_pkt...
1048c2ecf20Sopenharmony_ci	 */
1058c2ecf20Sopenharmony_ci	struct list_head sent;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/*
1088c2ecf20Sopenharmony_ci	 * Because above list will be accessed by both process and
1098c2ecf20Sopenharmony_ci	 * signal handler, we need a spinlock for it.
1108c2ecf20Sopenharmony_ci	 */
1118c2ecf20Sopenharmony_ci	spinlock_t sent_lock ____cacheline_aligned_in_smp;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* headers with expected length are allocated from here... */
1148c2ecf20Sopenharmony_ci	char header_cache_name[64];
1158c2ecf20Sopenharmony_ci	struct dma_pool *header_cache;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* packets are allocated from the slab cache... */
1188c2ecf20Sopenharmony_ci	char pkt_slab_name[64];
1198c2ecf20Sopenharmony_ci	struct kmem_cache *pkt_slab;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* as packets go on the queued queue, they are counted... */
1228c2ecf20Sopenharmony_ci	u32 counter;
1238c2ecf20Sopenharmony_ci	u32 sent_counter;
1248c2ecf20Sopenharmony_ci	/* pending packets, not sending yet */
1258c2ecf20Sopenharmony_ci	u32 num_pending;
1268c2ecf20Sopenharmony_ci	/* sending packets, not complete yet */
1278c2ecf20Sopenharmony_ci	u32 num_sending;
1288c2ecf20Sopenharmony_ci	/* global descq number of entry of last sending packet */
1298c2ecf20Sopenharmony_ci	u64 added;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* dma page table */
1328c2ecf20Sopenharmony_ci	struct rb_root dma_pages_root;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	struct qib_user_sdma_rb_node *sdma_rb_node;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	/* protect everything above... */
1378c2ecf20Sopenharmony_ci	struct mutex lock;
1388c2ecf20Sopenharmony_ci};
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic struct qib_user_sdma_rb_node *
1418c2ecf20Sopenharmony_ciqib_user_sdma_rb_search(struct rb_root *root, pid_t pid)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct qib_user_sdma_rb_node *sdma_rb_node;
1448c2ecf20Sopenharmony_ci	struct rb_node *node = root->rb_node;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	while (node) {
1478c2ecf20Sopenharmony_ci		sdma_rb_node = rb_entry(node, struct qib_user_sdma_rb_node,
1488c2ecf20Sopenharmony_ci					node);
1498c2ecf20Sopenharmony_ci		if (pid < sdma_rb_node->pid)
1508c2ecf20Sopenharmony_ci			node = node->rb_left;
1518c2ecf20Sopenharmony_ci		else if (pid > sdma_rb_node->pid)
1528c2ecf20Sopenharmony_ci			node = node->rb_right;
1538c2ecf20Sopenharmony_ci		else
1548c2ecf20Sopenharmony_ci			return sdma_rb_node;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci	return NULL;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic int
1608c2ecf20Sopenharmony_ciqib_user_sdma_rb_insert(struct rb_root *root, struct qib_user_sdma_rb_node *new)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct rb_node **node = &(root->rb_node);
1638c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
1648c2ecf20Sopenharmony_ci	struct qib_user_sdma_rb_node *got;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	while (*node) {
1678c2ecf20Sopenharmony_ci		got = rb_entry(*node, struct qib_user_sdma_rb_node, node);
1688c2ecf20Sopenharmony_ci		parent = *node;
1698c2ecf20Sopenharmony_ci		if (new->pid < got->pid)
1708c2ecf20Sopenharmony_ci			node = &((*node)->rb_left);
1718c2ecf20Sopenharmony_ci		else if (new->pid > got->pid)
1728c2ecf20Sopenharmony_ci			node = &((*node)->rb_right);
1738c2ecf20Sopenharmony_ci		else
1748c2ecf20Sopenharmony_ci			return 0;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	rb_link_node(&new->node, parent, node);
1788c2ecf20Sopenharmony_ci	rb_insert_color(&new->node, root);
1798c2ecf20Sopenharmony_ci	return 1;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistruct qib_user_sdma_queue *
1838c2ecf20Sopenharmony_ciqib_user_sdma_queue_create(struct device *dev, int unit, int ctxt, int sctxt)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	struct qib_user_sdma_queue *pq =
1868c2ecf20Sopenharmony_ci		kmalloc(sizeof(struct qib_user_sdma_queue), GFP_KERNEL);
1878c2ecf20Sopenharmony_ci	struct qib_user_sdma_rb_node *sdma_rb_node;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (!pq)
1908c2ecf20Sopenharmony_ci		goto done;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	pq->counter = 0;
1938c2ecf20Sopenharmony_ci	pq->sent_counter = 0;
1948c2ecf20Sopenharmony_ci	pq->num_pending = 0;
1958c2ecf20Sopenharmony_ci	pq->num_sending = 0;
1968c2ecf20Sopenharmony_ci	pq->added = 0;
1978c2ecf20Sopenharmony_ci	pq->sdma_rb_node = NULL;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pq->sent);
2008c2ecf20Sopenharmony_ci	spin_lock_init(&pq->sent_lock);
2018c2ecf20Sopenharmony_ci	mutex_init(&pq->lock);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	snprintf(pq->pkt_slab_name, sizeof(pq->pkt_slab_name),
2048c2ecf20Sopenharmony_ci		 "qib-user-sdma-pkts-%u-%02u.%02u", unit, ctxt, sctxt);
2058c2ecf20Sopenharmony_ci	pq->pkt_slab = kmem_cache_create(pq->pkt_slab_name,
2068c2ecf20Sopenharmony_ci					 sizeof(struct qib_user_sdma_pkt),
2078c2ecf20Sopenharmony_ci					 0, 0, NULL);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (!pq->pkt_slab)
2108c2ecf20Sopenharmony_ci		goto err_kfree;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	snprintf(pq->header_cache_name, sizeof(pq->header_cache_name),
2138c2ecf20Sopenharmony_ci		 "qib-user-sdma-headers-%u-%02u.%02u", unit, ctxt, sctxt);
2148c2ecf20Sopenharmony_ci	pq->header_cache = dma_pool_create(pq->header_cache_name,
2158c2ecf20Sopenharmony_ci					   dev,
2168c2ecf20Sopenharmony_ci					   QIB_USER_SDMA_EXP_HEADER_LENGTH,
2178c2ecf20Sopenharmony_ci					   4, 0);
2188c2ecf20Sopenharmony_ci	if (!pq->header_cache)
2198c2ecf20Sopenharmony_ci		goto err_slab;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	pq->dma_pages_root = RB_ROOT;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	sdma_rb_node = qib_user_sdma_rb_search(&qib_user_sdma_rb_root,
2248c2ecf20Sopenharmony_ci					current->pid);
2258c2ecf20Sopenharmony_ci	if (sdma_rb_node) {
2268c2ecf20Sopenharmony_ci		sdma_rb_node->refcount++;
2278c2ecf20Sopenharmony_ci	} else {
2288c2ecf20Sopenharmony_ci		sdma_rb_node = kmalloc(sizeof(
2298c2ecf20Sopenharmony_ci			struct qib_user_sdma_rb_node), GFP_KERNEL);
2308c2ecf20Sopenharmony_ci		if (!sdma_rb_node)
2318c2ecf20Sopenharmony_ci			goto err_rb;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		sdma_rb_node->refcount = 1;
2348c2ecf20Sopenharmony_ci		sdma_rb_node->pid = current->pid;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		qib_user_sdma_rb_insert(&qib_user_sdma_rb_root, sdma_rb_node);
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci	pq->sdma_rb_node = sdma_rb_node;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	goto done;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cierr_rb:
2438c2ecf20Sopenharmony_ci	dma_pool_destroy(pq->header_cache);
2448c2ecf20Sopenharmony_cierr_slab:
2458c2ecf20Sopenharmony_ci	kmem_cache_destroy(pq->pkt_slab);
2468c2ecf20Sopenharmony_cierr_kfree:
2478c2ecf20Sopenharmony_ci	kfree(pq);
2488c2ecf20Sopenharmony_ci	pq = NULL;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cidone:
2518c2ecf20Sopenharmony_ci	return pq;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic void qib_user_sdma_init_frag(struct qib_user_sdma_pkt *pkt,
2558c2ecf20Sopenharmony_ci				    int i, u16 offset, u16 len,
2568c2ecf20Sopenharmony_ci				    u16 first_desc, u16 last_desc,
2578c2ecf20Sopenharmony_ci				    u16 put_page, u16 dma_mapped,
2588c2ecf20Sopenharmony_ci				    struct page *page, void *kvaddr,
2598c2ecf20Sopenharmony_ci				    dma_addr_t dma_addr, u16 dma_length)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	pkt->addr[i].offset = offset;
2628c2ecf20Sopenharmony_ci	pkt->addr[i].length = len;
2638c2ecf20Sopenharmony_ci	pkt->addr[i].first_desc = first_desc;
2648c2ecf20Sopenharmony_ci	pkt->addr[i].last_desc = last_desc;
2658c2ecf20Sopenharmony_ci	pkt->addr[i].put_page = put_page;
2668c2ecf20Sopenharmony_ci	pkt->addr[i].dma_mapped = dma_mapped;
2678c2ecf20Sopenharmony_ci	pkt->addr[i].page = page;
2688c2ecf20Sopenharmony_ci	pkt->addr[i].kvaddr = kvaddr;
2698c2ecf20Sopenharmony_ci	pkt->addr[i].addr = dma_addr;
2708c2ecf20Sopenharmony_ci	pkt->addr[i].dma_length = dma_length;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic void *qib_user_sdma_alloc_header(struct qib_user_sdma_queue *pq,
2748c2ecf20Sopenharmony_ci				size_t len, dma_addr_t *dma_addr)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	void *hdr;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (len == QIB_USER_SDMA_EXP_HEADER_LENGTH)
2798c2ecf20Sopenharmony_ci		hdr = dma_pool_alloc(pq->header_cache, GFP_KERNEL,
2808c2ecf20Sopenharmony_ci					     dma_addr);
2818c2ecf20Sopenharmony_ci	else
2828c2ecf20Sopenharmony_ci		hdr = NULL;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (!hdr) {
2858c2ecf20Sopenharmony_ci		hdr = kmalloc(len, GFP_KERNEL);
2868c2ecf20Sopenharmony_ci		if (!hdr)
2878c2ecf20Sopenharmony_ci			return NULL;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci		*dma_addr = 0;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	return hdr;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic int qib_user_sdma_page_to_frags(const struct qib_devdata *dd,
2968c2ecf20Sopenharmony_ci				       struct qib_user_sdma_queue *pq,
2978c2ecf20Sopenharmony_ci				       struct qib_user_sdma_pkt *pkt,
2988c2ecf20Sopenharmony_ci				       struct page *page, u16 put,
2998c2ecf20Sopenharmony_ci				       u16 offset, u16 len, void *kvaddr)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	__le16 *pbc16;
3028c2ecf20Sopenharmony_ci	void *pbcvaddr;
3038c2ecf20Sopenharmony_ci	struct qib_message_header *hdr;
3048c2ecf20Sopenharmony_ci	u16 newlen, pbclen, lastdesc, dma_mapped;
3058c2ecf20Sopenharmony_ci	u32 vcto;
3068c2ecf20Sopenharmony_ci	union qib_seqnum seqnum;
3078c2ecf20Sopenharmony_ci	dma_addr_t pbcdaddr;
3088c2ecf20Sopenharmony_ci	dma_addr_t dma_addr =
3098c2ecf20Sopenharmony_ci		dma_map_page(&dd->pcidev->dev,
3108c2ecf20Sopenharmony_ci			page, offset, len, DMA_TO_DEVICE);
3118c2ecf20Sopenharmony_ci	int ret = 0;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (dma_mapping_error(&dd->pcidev->dev, dma_addr)) {
3148c2ecf20Sopenharmony_ci		/*
3158c2ecf20Sopenharmony_ci		 * dma mapping error, pkt has not managed
3168c2ecf20Sopenharmony_ci		 * this page yet, return the page here so
3178c2ecf20Sopenharmony_ci		 * the caller can ignore this page.
3188c2ecf20Sopenharmony_ci		 */
3198c2ecf20Sopenharmony_ci		if (put) {
3208c2ecf20Sopenharmony_ci			unpin_user_page(page);
3218c2ecf20Sopenharmony_ci		} else {
3228c2ecf20Sopenharmony_ci			/* coalesce case */
3238c2ecf20Sopenharmony_ci			kunmap(page);
3248c2ecf20Sopenharmony_ci			__free_page(page);
3258c2ecf20Sopenharmony_ci		}
3268c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3278c2ecf20Sopenharmony_ci		goto done;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci	offset = 0;
3308c2ecf20Sopenharmony_ci	dma_mapped = 1;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cinext_fragment:
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/*
3368c2ecf20Sopenharmony_ci	 * In tid-sdma, the transfer length is restricted by
3378c2ecf20Sopenharmony_ci	 * receiver side current tid page length.
3388c2ecf20Sopenharmony_ci	 */
3398c2ecf20Sopenharmony_ci	if (pkt->tiddma && len > pkt->tidsm[pkt->tidsmidx].length)
3408c2ecf20Sopenharmony_ci		newlen = pkt->tidsm[pkt->tidsmidx].length;
3418c2ecf20Sopenharmony_ci	else
3428c2ecf20Sopenharmony_ci		newlen = len;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	/*
3458c2ecf20Sopenharmony_ci	 * Then the transfer length is restricted by MTU.
3468c2ecf20Sopenharmony_ci	 * the last descriptor flag is determined by:
3478c2ecf20Sopenharmony_ci	 * 1. the current packet is at frag size length.
3488c2ecf20Sopenharmony_ci	 * 2. the current tid page is done if tid-sdma.
3498c2ecf20Sopenharmony_ci	 * 3. there is no more byte togo if sdma.
3508c2ecf20Sopenharmony_ci	 */
3518c2ecf20Sopenharmony_ci	lastdesc = 0;
3528c2ecf20Sopenharmony_ci	if ((pkt->payload_size + newlen) >= pkt->frag_size) {
3538c2ecf20Sopenharmony_ci		newlen = pkt->frag_size - pkt->payload_size;
3548c2ecf20Sopenharmony_ci		lastdesc = 1;
3558c2ecf20Sopenharmony_ci	} else if (pkt->tiddma) {
3568c2ecf20Sopenharmony_ci		if (newlen == pkt->tidsm[pkt->tidsmidx].length)
3578c2ecf20Sopenharmony_ci			lastdesc = 1;
3588c2ecf20Sopenharmony_ci	} else {
3598c2ecf20Sopenharmony_ci		if (newlen == pkt->bytes_togo)
3608c2ecf20Sopenharmony_ci			lastdesc = 1;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* fill the next fragment in this page */
3648c2ecf20Sopenharmony_ci	qib_user_sdma_init_frag(pkt, pkt->naddr, /* index */
3658c2ecf20Sopenharmony_ci		offset, newlen,		/* offset, len */
3668c2ecf20Sopenharmony_ci		0, lastdesc,		/* first last desc */
3678c2ecf20Sopenharmony_ci		put, dma_mapped,	/* put page, dma mapped */
3688c2ecf20Sopenharmony_ci		page, kvaddr,		/* struct page, virt addr */
3698c2ecf20Sopenharmony_ci		dma_addr, len);		/* dma addr, dma length */
3708c2ecf20Sopenharmony_ci	pkt->bytes_togo -= newlen;
3718c2ecf20Sopenharmony_ci	pkt->payload_size += newlen;
3728c2ecf20Sopenharmony_ci	pkt->naddr++;
3738c2ecf20Sopenharmony_ci	if (pkt->naddr == pkt->addrlimit) {
3748c2ecf20Sopenharmony_ci		ret = -EFAULT;
3758c2ecf20Sopenharmony_ci		goto done;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* If there is no more byte togo. (lastdesc==1) */
3798c2ecf20Sopenharmony_ci	if (pkt->bytes_togo == 0) {
3808c2ecf20Sopenharmony_ci		/* The packet is done, header is not dma mapped yet.
3818c2ecf20Sopenharmony_ci		 * it should be from kmalloc */
3828c2ecf20Sopenharmony_ci		if (!pkt->addr[pkt->index].addr) {
3838c2ecf20Sopenharmony_ci			pkt->addr[pkt->index].addr =
3848c2ecf20Sopenharmony_ci				dma_map_single(&dd->pcidev->dev,
3858c2ecf20Sopenharmony_ci					pkt->addr[pkt->index].kvaddr,
3868c2ecf20Sopenharmony_ci					pkt->addr[pkt->index].dma_length,
3878c2ecf20Sopenharmony_ci					DMA_TO_DEVICE);
3888c2ecf20Sopenharmony_ci			if (dma_mapping_error(&dd->pcidev->dev,
3898c2ecf20Sopenharmony_ci					pkt->addr[pkt->index].addr)) {
3908c2ecf20Sopenharmony_ci				ret = -ENOMEM;
3918c2ecf20Sopenharmony_ci				goto done;
3928c2ecf20Sopenharmony_ci			}
3938c2ecf20Sopenharmony_ci			pkt->addr[pkt->index].dma_mapped = 1;
3948c2ecf20Sopenharmony_ci		}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci		goto done;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	/* If tid-sdma, advance tid info. */
4008c2ecf20Sopenharmony_ci	if (pkt->tiddma) {
4018c2ecf20Sopenharmony_ci		pkt->tidsm[pkt->tidsmidx].length -= newlen;
4028c2ecf20Sopenharmony_ci		if (pkt->tidsm[pkt->tidsmidx].length) {
4038c2ecf20Sopenharmony_ci			pkt->tidsm[pkt->tidsmidx].offset += newlen;
4048c2ecf20Sopenharmony_ci		} else {
4058c2ecf20Sopenharmony_ci			pkt->tidsmidx++;
4068c2ecf20Sopenharmony_ci			if (pkt->tidsmidx == pkt->tidsmcount) {
4078c2ecf20Sopenharmony_ci				ret = -EFAULT;
4088c2ecf20Sopenharmony_ci				goto done;
4098c2ecf20Sopenharmony_ci			}
4108c2ecf20Sopenharmony_ci		}
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	/*
4148c2ecf20Sopenharmony_ci	 * If this is NOT the last descriptor. (newlen==len)
4158c2ecf20Sopenharmony_ci	 * the current packet is not done yet, but the current
4168c2ecf20Sopenharmony_ci	 * send side page is done.
4178c2ecf20Sopenharmony_ci	 */
4188c2ecf20Sopenharmony_ci	if (lastdesc == 0)
4198c2ecf20Sopenharmony_ci		goto done;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	/*
4228c2ecf20Sopenharmony_ci	 * If running this driver under PSM with message size
4238c2ecf20Sopenharmony_ci	 * fitting into one transfer unit, it is not possible
4248c2ecf20Sopenharmony_ci	 * to pass this line. otherwise, it is a buggggg.
4258c2ecf20Sopenharmony_ci	 */
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	/*
4288c2ecf20Sopenharmony_ci	 * Since the current packet is done, and there are more
4298c2ecf20Sopenharmony_ci	 * bytes togo, we need to create a new sdma header, copying
4308c2ecf20Sopenharmony_ci	 * from previous sdma header and modify both.
4318c2ecf20Sopenharmony_ci	 */
4328c2ecf20Sopenharmony_ci	pbclen = pkt->addr[pkt->index].length;
4338c2ecf20Sopenharmony_ci	pbcvaddr = qib_user_sdma_alloc_header(pq, pbclen, &pbcdaddr);
4348c2ecf20Sopenharmony_ci	if (!pbcvaddr) {
4358c2ecf20Sopenharmony_ci		ret = -ENOMEM;
4368c2ecf20Sopenharmony_ci		goto done;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci	/* Copy the previous sdma header to new sdma header */
4398c2ecf20Sopenharmony_ci	pbc16 = (__le16 *)pkt->addr[pkt->index].kvaddr;
4408c2ecf20Sopenharmony_ci	memcpy(pbcvaddr, pbc16, pbclen);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	/* Modify the previous sdma header */
4438c2ecf20Sopenharmony_ci	hdr = (struct qib_message_header *)&pbc16[4];
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/* New pbc length */
4468c2ecf20Sopenharmony_ci	pbc16[0] = cpu_to_le16(le16_to_cpu(pbc16[0])-(pkt->bytes_togo>>2));
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/* New packet length */
4498c2ecf20Sopenharmony_ci	hdr->lrh[2] = cpu_to_be16(le16_to_cpu(pbc16[0]));
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (pkt->tiddma) {
4528c2ecf20Sopenharmony_ci		/* turn on the header suppression */
4538c2ecf20Sopenharmony_ci		hdr->iph.pkt_flags =
4548c2ecf20Sopenharmony_ci			cpu_to_le16(le16_to_cpu(hdr->iph.pkt_flags)|0x2);
4558c2ecf20Sopenharmony_ci		/* turn off ACK_REQ: 0x04 and EXPECTED_DONE: 0x20 */
4568c2ecf20Sopenharmony_ci		hdr->flags &= ~(0x04|0x20);
4578c2ecf20Sopenharmony_ci	} else {
4588c2ecf20Sopenharmony_ci		/* turn off extra bytes: 20-21 bits */
4598c2ecf20Sopenharmony_ci		hdr->bth[0] = cpu_to_be32(be32_to_cpu(hdr->bth[0])&0xFFCFFFFF);
4608c2ecf20Sopenharmony_ci		/* turn off ACK_REQ: 0x04 */
4618c2ecf20Sopenharmony_ci		hdr->flags &= ~(0x04);
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	/* New kdeth checksum */
4658c2ecf20Sopenharmony_ci	vcto = le32_to_cpu(hdr->iph.ver_ctxt_tid_offset);
4668c2ecf20Sopenharmony_ci	hdr->iph.chksum = cpu_to_le16(QIB_LRH_BTH +
4678c2ecf20Sopenharmony_ci		be16_to_cpu(hdr->lrh[2]) -
4688c2ecf20Sopenharmony_ci		((vcto>>16)&0xFFFF) - (vcto&0xFFFF) -
4698c2ecf20Sopenharmony_ci		le16_to_cpu(hdr->iph.pkt_flags));
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/* The packet is done, header is not dma mapped yet.
4728c2ecf20Sopenharmony_ci	 * it should be from kmalloc */
4738c2ecf20Sopenharmony_ci	if (!pkt->addr[pkt->index].addr) {
4748c2ecf20Sopenharmony_ci		pkt->addr[pkt->index].addr =
4758c2ecf20Sopenharmony_ci			dma_map_single(&dd->pcidev->dev,
4768c2ecf20Sopenharmony_ci				pkt->addr[pkt->index].kvaddr,
4778c2ecf20Sopenharmony_ci				pkt->addr[pkt->index].dma_length,
4788c2ecf20Sopenharmony_ci				DMA_TO_DEVICE);
4798c2ecf20Sopenharmony_ci		if (dma_mapping_error(&dd->pcidev->dev,
4808c2ecf20Sopenharmony_ci				pkt->addr[pkt->index].addr)) {
4818c2ecf20Sopenharmony_ci			ret = -ENOMEM;
4828c2ecf20Sopenharmony_ci			goto done;
4838c2ecf20Sopenharmony_ci		}
4848c2ecf20Sopenharmony_ci		pkt->addr[pkt->index].dma_mapped = 1;
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/* Modify the new sdma header */
4888c2ecf20Sopenharmony_ci	pbc16 = (__le16 *)pbcvaddr;
4898c2ecf20Sopenharmony_ci	hdr = (struct qib_message_header *)&pbc16[4];
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	/* New pbc length */
4928c2ecf20Sopenharmony_ci	pbc16[0] = cpu_to_le16(le16_to_cpu(pbc16[0])-(pkt->payload_size>>2));
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	/* New packet length */
4958c2ecf20Sopenharmony_ci	hdr->lrh[2] = cpu_to_be16(le16_to_cpu(pbc16[0]));
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (pkt->tiddma) {
4988c2ecf20Sopenharmony_ci		/* Set new tid and offset for new sdma header */
4998c2ecf20Sopenharmony_ci		hdr->iph.ver_ctxt_tid_offset = cpu_to_le32(
5008c2ecf20Sopenharmony_ci			(le32_to_cpu(hdr->iph.ver_ctxt_tid_offset)&0xFF000000) +
5018c2ecf20Sopenharmony_ci			(pkt->tidsm[pkt->tidsmidx].tid<<QLOGIC_IB_I_TID_SHIFT) +
5028c2ecf20Sopenharmony_ci			(pkt->tidsm[pkt->tidsmidx].offset>>2));
5038c2ecf20Sopenharmony_ci	} else {
5048c2ecf20Sopenharmony_ci		/* Middle protocol new packet offset */
5058c2ecf20Sopenharmony_ci		hdr->uwords[2] += pkt->payload_size;
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	/* New kdeth checksum */
5098c2ecf20Sopenharmony_ci	vcto = le32_to_cpu(hdr->iph.ver_ctxt_tid_offset);
5108c2ecf20Sopenharmony_ci	hdr->iph.chksum = cpu_to_le16(QIB_LRH_BTH +
5118c2ecf20Sopenharmony_ci		be16_to_cpu(hdr->lrh[2]) -
5128c2ecf20Sopenharmony_ci		((vcto>>16)&0xFFFF) - (vcto&0xFFFF) -
5138c2ecf20Sopenharmony_ci		le16_to_cpu(hdr->iph.pkt_flags));
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/* Next sequence number in new sdma header */
5168c2ecf20Sopenharmony_ci	seqnum.val = be32_to_cpu(hdr->bth[2]);
5178c2ecf20Sopenharmony_ci	if (pkt->tiddma)
5188c2ecf20Sopenharmony_ci		seqnum.seq++;
5198c2ecf20Sopenharmony_ci	else
5208c2ecf20Sopenharmony_ci		seqnum.pkt++;
5218c2ecf20Sopenharmony_ci	hdr->bth[2] = cpu_to_be32(seqnum.val);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	/* Init new sdma header. */
5248c2ecf20Sopenharmony_ci	qib_user_sdma_init_frag(pkt, pkt->naddr, /* index */
5258c2ecf20Sopenharmony_ci		0, pbclen,		/* offset, len */
5268c2ecf20Sopenharmony_ci		1, 0,			/* first last desc */
5278c2ecf20Sopenharmony_ci		0, 0,			/* put page, dma mapped */
5288c2ecf20Sopenharmony_ci		NULL, pbcvaddr,		/* struct page, virt addr */
5298c2ecf20Sopenharmony_ci		pbcdaddr, pbclen);	/* dma addr, dma length */
5308c2ecf20Sopenharmony_ci	pkt->index = pkt->naddr;
5318c2ecf20Sopenharmony_ci	pkt->payload_size = 0;
5328c2ecf20Sopenharmony_ci	pkt->naddr++;
5338c2ecf20Sopenharmony_ci	if (pkt->naddr == pkt->addrlimit) {
5348c2ecf20Sopenharmony_ci		ret = -EFAULT;
5358c2ecf20Sopenharmony_ci		goto done;
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	/* Prepare for next fragment in this page */
5398c2ecf20Sopenharmony_ci	if (newlen != len) {
5408c2ecf20Sopenharmony_ci		if (dma_mapped) {
5418c2ecf20Sopenharmony_ci			put = 0;
5428c2ecf20Sopenharmony_ci			dma_mapped = 0;
5438c2ecf20Sopenharmony_ci			page = NULL;
5448c2ecf20Sopenharmony_ci			kvaddr = NULL;
5458c2ecf20Sopenharmony_ci		}
5468c2ecf20Sopenharmony_ci		len -= newlen;
5478c2ecf20Sopenharmony_ci		offset += newlen;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci		goto next_fragment;
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cidone:
5538c2ecf20Sopenharmony_ci	return ret;
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci/* we've too many pages in the iovec, coalesce to a single page */
5578c2ecf20Sopenharmony_cistatic int qib_user_sdma_coalesce(const struct qib_devdata *dd,
5588c2ecf20Sopenharmony_ci				  struct qib_user_sdma_queue *pq,
5598c2ecf20Sopenharmony_ci				  struct qib_user_sdma_pkt *pkt,
5608c2ecf20Sopenharmony_ci				  const struct iovec *iov,
5618c2ecf20Sopenharmony_ci				  unsigned long niov)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	int ret = 0;
5648c2ecf20Sopenharmony_ci	struct page *page = alloc_page(GFP_KERNEL);
5658c2ecf20Sopenharmony_ci	void *mpage_save;
5668c2ecf20Sopenharmony_ci	char *mpage;
5678c2ecf20Sopenharmony_ci	int i;
5688c2ecf20Sopenharmony_ci	int len = 0;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (!page) {
5718c2ecf20Sopenharmony_ci		ret = -ENOMEM;
5728c2ecf20Sopenharmony_ci		goto done;
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	mpage = kmap(page);
5768c2ecf20Sopenharmony_ci	mpage_save = mpage;
5778c2ecf20Sopenharmony_ci	for (i = 0; i < niov; i++) {
5788c2ecf20Sopenharmony_ci		int cfur;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		cfur = copy_from_user(mpage,
5818c2ecf20Sopenharmony_ci				      iov[i].iov_base, iov[i].iov_len);
5828c2ecf20Sopenharmony_ci		if (cfur) {
5838c2ecf20Sopenharmony_ci			ret = -EFAULT;
5848c2ecf20Sopenharmony_ci			goto free_unmap;
5858c2ecf20Sopenharmony_ci		}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		mpage += iov[i].iov_len;
5888c2ecf20Sopenharmony_ci		len += iov[i].iov_len;
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	ret = qib_user_sdma_page_to_frags(dd, pq, pkt,
5928c2ecf20Sopenharmony_ci			page, 0, 0, len, mpage_save);
5938c2ecf20Sopenharmony_ci	goto done;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cifree_unmap:
5968c2ecf20Sopenharmony_ci	kunmap(page);
5978c2ecf20Sopenharmony_ci	__free_page(page);
5988c2ecf20Sopenharmony_cidone:
5998c2ecf20Sopenharmony_ci	return ret;
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci/*
6038c2ecf20Sopenharmony_ci * How many pages in this iovec element?
6048c2ecf20Sopenharmony_ci */
6058c2ecf20Sopenharmony_cistatic size_t qib_user_sdma_num_pages(const struct iovec *iov)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	const unsigned long addr  = (unsigned long) iov->iov_base;
6088c2ecf20Sopenharmony_ci	const unsigned long  len  = iov->iov_len;
6098c2ecf20Sopenharmony_ci	const unsigned long spage = addr & PAGE_MASK;
6108c2ecf20Sopenharmony_ci	const unsigned long epage = (addr + len - 1) & PAGE_MASK;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	return 1 + ((epage - spage) >> PAGE_SHIFT);
6138c2ecf20Sopenharmony_ci}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_cistatic void qib_user_sdma_free_pkt_frag(struct device *dev,
6168c2ecf20Sopenharmony_ci					struct qib_user_sdma_queue *pq,
6178c2ecf20Sopenharmony_ci					struct qib_user_sdma_pkt *pkt,
6188c2ecf20Sopenharmony_ci					int frag)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	const int i = frag;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (pkt->addr[i].page) {
6238c2ecf20Sopenharmony_ci		/* only user data has page */
6248c2ecf20Sopenharmony_ci		if (pkt->addr[i].dma_mapped)
6258c2ecf20Sopenharmony_ci			dma_unmap_page(dev,
6268c2ecf20Sopenharmony_ci				       pkt->addr[i].addr,
6278c2ecf20Sopenharmony_ci				       pkt->addr[i].dma_length,
6288c2ecf20Sopenharmony_ci				       DMA_TO_DEVICE);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci		if (pkt->addr[i].kvaddr)
6318c2ecf20Sopenharmony_ci			kunmap(pkt->addr[i].page);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci		if (pkt->addr[i].put_page)
6348c2ecf20Sopenharmony_ci			unpin_user_page(pkt->addr[i].page);
6358c2ecf20Sopenharmony_ci		else
6368c2ecf20Sopenharmony_ci			__free_page(pkt->addr[i].page);
6378c2ecf20Sopenharmony_ci	} else if (pkt->addr[i].kvaddr) {
6388c2ecf20Sopenharmony_ci		/* for headers */
6398c2ecf20Sopenharmony_ci		if (pkt->addr[i].dma_mapped) {
6408c2ecf20Sopenharmony_ci			/* from kmalloc & dma mapped */
6418c2ecf20Sopenharmony_ci			dma_unmap_single(dev,
6428c2ecf20Sopenharmony_ci				       pkt->addr[i].addr,
6438c2ecf20Sopenharmony_ci				       pkt->addr[i].dma_length,
6448c2ecf20Sopenharmony_ci				       DMA_TO_DEVICE);
6458c2ecf20Sopenharmony_ci			kfree(pkt->addr[i].kvaddr);
6468c2ecf20Sopenharmony_ci		} else if (pkt->addr[i].addr) {
6478c2ecf20Sopenharmony_ci			/* free coherent mem from cache... */
6488c2ecf20Sopenharmony_ci			dma_pool_free(pq->header_cache,
6498c2ecf20Sopenharmony_ci			      pkt->addr[i].kvaddr, pkt->addr[i].addr);
6508c2ecf20Sopenharmony_ci		} else {
6518c2ecf20Sopenharmony_ci			/* from kmalloc but not dma mapped */
6528c2ecf20Sopenharmony_ci			kfree(pkt->addr[i].kvaddr);
6538c2ecf20Sopenharmony_ci		}
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci/* return number of pages pinned... */
6588c2ecf20Sopenharmony_cistatic int qib_user_sdma_pin_pages(const struct qib_devdata *dd,
6598c2ecf20Sopenharmony_ci				   struct qib_user_sdma_queue *pq,
6608c2ecf20Sopenharmony_ci				   struct qib_user_sdma_pkt *pkt,
6618c2ecf20Sopenharmony_ci				   unsigned long addr, int tlen, size_t npages)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	struct page *pages[8];
6648c2ecf20Sopenharmony_ci	int i, j;
6658c2ecf20Sopenharmony_ci	int ret = 0;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	while (npages) {
6688c2ecf20Sopenharmony_ci		if (npages > 8)
6698c2ecf20Sopenharmony_ci			j = 8;
6708c2ecf20Sopenharmony_ci		else
6718c2ecf20Sopenharmony_ci			j = npages;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci		ret = pin_user_pages_fast(addr, j, FOLL_LONGTERM, pages);
6748c2ecf20Sopenharmony_ci		if (ret != j) {
6758c2ecf20Sopenharmony_ci			i = 0;
6768c2ecf20Sopenharmony_ci			j = ret;
6778c2ecf20Sopenharmony_ci			ret = -ENOMEM;
6788c2ecf20Sopenharmony_ci			goto free_pages;
6798c2ecf20Sopenharmony_ci		}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci		for (i = 0; i < j; i++) {
6828c2ecf20Sopenharmony_ci			/* map the pages... */
6838c2ecf20Sopenharmony_ci			unsigned long fofs = addr & ~PAGE_MASK;
6848c2ecf20Sopenharmony_ci			int flen = ((fofs + tlen) > PAGE_SIZE) ?
6858c2ecf20Sopenharmony_ci				(PAGE_SIZE - fofs) : tlen;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci			ret = qib_user_sdma_page_to_frags(dd, pq, pkt,
6888c2ecf20Sopenharmony_ci				pages[i], 1, fofs, flen, NULL);
6898c2ecf20Sopenharmony_ci			if (ret < 0) {
6908c2ecf20Sopenharmony_ci				/* current page has beed taken
6918c2ecf20Sopenharmony_ci				 * care of inside above call.
6928c2ecf20Sopenharmony_ci				 */
6938c2ecf20Sopenharmony_ci				i++;
6948c2ecf20Sopenharmony_ci				goto free_pages;
6958c2ecf20Sopenharmony_ci			}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci			addr += flen;
6988c2ecf20Sopenharmony_ci			tlen -= flen;
6998c2ecf20Sopenharmony_ci		}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		npages -= j;
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	goto done;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	/* if error, return all pages not managed by pkt */
7078c2ecf20Sopenharmony_cifree_pages:
7088c2ecf20Sopenharmony_ci	while (i < j)
7098c2ecf20Sopenharmony_ci		unpin_user_page(pages[i++]);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_cidone:
7128c2ecf20Sopenharmony_ci	return ret;
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_cistatic int qib_user_sdma_pin_pkt(const struct qib_devdata *dd,
7168c2ecf20Sopenharmony_ci				 struct qib_user_sdma_queue *pq,
7178c2ecf20Sopenharmony_ci				 struct qib_user_sdma_pkt *pkt,
7188c2ecf20Sopenharmony_ci				 const struct iovec *iov,
7198c2ecf20Sopenharmony_ci				 unsigned long niov)
7208c2ecf20Sopenharmony_ci{
7218c2ecf20Sopenharmony_ci	int ret = 0;
7228c2ecf20Sopenharmony_ci	unsigned long idx;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	for (idx = 0; idx < niov; idx++) {
7258c2ecf20Sopenharmony_ci		const size_t npages = qib_user_sdma_num_pages(iov + idx);
7268c2ecf20Sopenharmony_ci		const unsigned long addr = (unsigned long) iov[idx].iov_base;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci		ret = qib_user_sdma_pin_pages(dd, pq, pkt, addr,
7298c2ecf20Sopenharmony_ci					      iov[idx].iov_len, npages);
7308c2ecf20Sopenharmony_ci		if (ret < 0)
7318c2ecf20Sopenharmony_ci			goto free_pkt;
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	goto done;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cifree_pkt:
7378c2ecf20Sopenharmony_ci	/* we need to ignore the first entry here */
7388c2ecf20Sopenharmony_ci	for (idx = 1; idx < pkt->naddr; idx++)
7398c2ecf20Sopenharmony_ci		qib_user_sdma_free_pkt_frag(&dd->pcidev->dev, pq, pkt, idx);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	/* need to dma unmap the first entry, this is to restore to
7428c2ecf20Sopenharmony_ci	 * the original state so that caller can free the memory in
7438c2ecf20Sopenharmony_ci	 * error condition. Caller does not know if dma mapped or not*/
7448c2ecf20Sopenharmony_ci	if (pkt->addr[0].dma_mapped) {
7458c2ecf20Sopenharmony_ci		dma_unmap_single(&dd->pcidev->dev,
7468c2ecf20Sopenharmony_ci		       pkt->addr[0].addr,
7478c2ecf20Sopenharmony_ci		       pkt->addr[0].dma_length,
7488c2ecf20Sopenharmony_ci		       DMA_TO_DEVICE);
7498c2ecf20Sopenharmony_ci		pkt->addr[0].addr = 0;
7508c2ecf20Sopenharmony_ci		pkt->addr[0].dma_mapped = 0;
7518c2ecf20Sopenharmony_ci	}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_cidone:
7548c2ecf20Sopenharmony_ci	return ret;
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_cistatic int qib_user_sdma_init_payload(const struct qib_devdata *dd,
7588c2ecf20Sopenharmony_ci				      struct qib_user_sdma_queue *pq,
7598c2ecf20Sopenharmony_ci				      struct qib_user_sdma_pkt *pkt,
7608c2ecf20Sopenharmony_ci				      const struct iovec *iov,
7618c2ecf20Sopenharmony_ci				      unsigned long niov, int npages)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	int ret = 0;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	if (pkt->frag_size == pkt->bytes_togo &&
7668c2ecf20Sopenharmony_ci			npages >= ARRAY_SIZE(pkt->addr))
7678c2ecf20Sopenharmony_ci		ret = qib_user_sdma_coalesce(dd, pq, pkt, iov, niov);
7688c2ecf20Sopenharmony_ci	else
7698c2ecf20Sopenharmony_ci		ret = qib_user_sdma_pin_pkt(dd, pq, pkt, iov, niov);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	return ret;
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci/* free a packet list -- return counter value of last packet */
7758c2ecf20Sopenharmony_cistatic void qib_user_sdma_free_pkt_list(struct device *dev,
7768c2ecf20Sopenharmony_ci					struct qib_user_sdma_queue *pq,
7778c2ecf20Sopenharmony_ci					struct list_head *list)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	struct qib_user_sdma_pkt *pkt, *pkt_next;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	list_for_each_entry_safe(pkt, pkt_next, list, list) {
7828c2ecf20Sopenharmony_ci		int i;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci		for (i = 0; i < pkt->naddr; i++)
7858c2ecf20Sopenharmony_ci			qib_user_sdma_free_pkt_frag(dev, pq, pkt, i);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci		if (pkt->largepkt)
7888c2ecf20Sopenharmony_ci			kfree(pkt);
7898c2ecf20Sopenharmony_ci		else
7908c2ecf20Sopenharmony_ci			kmem_cache_free(pq->pkt_slab, pkt);
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(list);
7938c2ecf20Sopenharmony_ci}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci/*
7968c2ecf20Sopenharmony_ci * copy headers, coalesce etc -- pq->lock must be held
7978c2ecf20Sopenharmony_ci *
7988c2ecf20Sopenharmony_ci * we queue all the packets to list, returning the
7998c2ecf20Sopenharmony_ci * number of bytes total.  list must be empty initially,
8008c2ecf20Sopenharmony_ci * as, if there is an error we clean it...
8018c2ecf20Sopenharmony_ci */
8028c2ecf20Sopenharmony_cistatic int qib_user_sdma_queue_pkts(const struct qib_devdata *dd,
8038c2ecf20Sopenharmony_ci				    struct qib_pportdata *ppd,
8048c2ecf20Sopenharmony_ci				    struct qib_user_sdma_queue *pq,
8058c2ecf20Sopenharmony_ci				    const struct iovec *iov,
8068c2ecf20Sopenharmony_ci				    unsigned long niov,
8078c2ecf20Sopenharmony_ci				    struct list_head *list,
8088c2ecf20Sopenharmony_ci				    int *maxpkts, int *ndesc)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	unsigned long idx = 0;
8118c2ecf20Sopenharmony_ci	int ret = 0;
8128c2ecf20Sopenharmony_ci	int npkts = 0;
8138c2ecf20Sopenharmony_ci	__le32 *pbc;
8148c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
8158c2ecf20Sopenharmony_ci	struct qib_user_sdma_pkt *pkt = NULL;
8168c2ecf20Sopenharmony_ci	size_t len;
8178c2ecf20Sopenharmony_ci	size_t nw;
8188c2ecf20Sopenharmony_ci	u32 counter = pq->counter;
8198c2ecf20Sopenharmony_ci	u16 frag_size;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	while (idx < niov && npkts < *maxpkts) {
8228c2ecf20Sopenharmony_ci		const unsigned long addr = (unsigned long) iov[idx].iov_base;
8238c2ecf20Sopenharmony_ci		const unsigned long idx_save = idx;
8248c2ecf20Sopenharmony_ci		unsigned pktnw;
8258c2ecf20Sopenharmony_ci		unsigned pktnwc;
8268c2ecf20Sopenharmony_ci		int nfrags = 0;
8278c2ecf20Sopenharmony_ci		size_t npages = 0;
8288c2ecf20Sopenharmony_ci		size_t bytes_togo = 0;
8298c2ecf20Sopenharmony_ci		int tiddma = 0;
8308c2ecf20Sopenharmony_ci		int cfur;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci		len = iov[idx].iov_len;
8338c2ecf20Sopenharmony_ci		nw = len >> 2;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci		if (len < QIB_USER_SDMA_MIN_HEADER_LENGTH ||
8368c2ecf20Sopenharmony_ci		    len > PAGE_SIZE || len & 3 || addr & 3) {
8378c2ecf20Sopenharmony_ci			ret = -EINVAL;
8388c2ecf20Sopenharmony_ci			goto free_list;
8398c2ecf20Sopenharmony_ci		}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci		pbc = qib_user_sdma_alloc_header(pq, len, &dma_addr);
8428c2ecf20Sopenharmony_ci		if (!pbc) {
8438c2ecf20Sopenharmony_ci			ret = -ENOMEM;
8448c2ecf20Sopenharmony_ci			goto free_list;
8458c2ecf20Sopenharmony_ci		}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci		cfur = copy_from_user(pbc, iov[idx].iov_base, len);
8488c2ecf20Sopenharmony_ci		if (cfur) {
8498c2ecf20Sopenharmony_ci			ret = -EFAULT;
8508c2ecf20Sopenharmony_ci			goto free_pbc;
8518c2ecf20Sopenharmony_ci		}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci		/*
8548c2ecf20Sopenharmony_ci		 * This assignment is a bit strange.  it's because the
8558c2ecf20Sopenharmony_ci		 * the pbc counts the number of 32 bit words in the full
8568c2ecf20Sopenharmony_ci		 * packet _except_ the first word of the pbc itself...
8578c2ecf20Sopenharmony_ci		 */
8588c2ecf20Sopenharmony_ci		pktnwc = nw - 1;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci		/*
8618c2ecf20Sopenharmony_ci		 * pktnw computation yields the number of 32 bit words
8628c2ecf20Sopenharmony_ci		 * that the caller has indicated in the PBC.  note that
8638c2ecf20Sopenharmony_ci		 * this is one less than the total number of words that
8648c2ecf20Sopenharmony_ci		 * goes to the send DMA engine as the first 32 bit word
8658c2ecf20Sopenharmony_ci		 * of the PBC itself is not counted.  Armed with this count,
8668c2ecf20Sopenharmony_ci		 * we can verify that the packet is consistent with the
8678c2ecf20Sopenharmony_ci		 * iovec lengths.
8688c2ecf20Sopenharmony_ci		 */
8698c2ecf20Sopenharmony_ci		pktnw = le32_to_cpu(*pbc) & 0xFFFF;
8708c2ecf20Sopenharmony_ci		if (pktnw < pktnwc) {
8718c2ecf20Sopenharmony_ci			ret = -EINVAL;
8728c2ecf20Sopenharmony_ci			goto free_pbc;
8738c2ecf20Sopenharmony_ci		}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci		idx++;
8768c2ecf20Sopenharmony_ci		while (pktnwc < pktnw && idx < niov) {
8778c2ecf20Sopenharmony_ci			const size_t slen = iov[idx].iov_len;
8788c2ecf20Sopenharmony_ci			const unsigned long faddr =
8798c2ecf20Sopenharmony_ci				(unsigned long) iov[idx].iov_base;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci			if (slen & 3 || faddr & 3 || !slen) {
8828c2ecf20Sopenharmony_ci				ret = -EINVAL;
8838c2ecf20Sopenharmony_ci				goto free_pbc;
8848c2ecf20Sopenharmony_ci			}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci			npages += qib_user_sdma_num_pages(&iov[idx]);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci			if (check_add_overflow(bytes_togo, slen, &bytes_togo) ||
8898c2ecf20Sopenharmony_ci			    bytes_togo > type_max(typeof(pkt->bytes_togo))) {
8908c2ecf20Sopenharmony_ci				ret = -EINVAL;
8918c2ecf20Sopenharmony_ci				goto free_pbc;
8928c2ecf20Sopenharmony_ci			}
8938c2ecf20Sopenharmony_ci			pktnwc += slen >> 2;
8948c2ecf20Sopenharmony_ci			idx++;
8958c2ecf20Sopenharmony_ci			nfrags++;
8968c2ecf20Sopenharmony_ci		}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci		if (pktnwc != pktnw) {
8998c2ecf20Sopenharmony_ci			ret = -EINVAL;
9008c2ecf20Sopenharmony_ci			goto free_pbc;
9018c2ecf20Sopenharmony_ci		}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci		frag_size = ((le32_to_cpu(*pbc))>>16) & 0xFFFF;
9048c2ecf20Sopenharmony_ci		if (((frag_size ? frag_size : bytes_togo) + len) >
9058c2ecf20Sopenharmony_ci						ppd->ibmaxlen) {
9068c2ecf20Sopenharmony_ci			ret = -EINVAL;
9078c2ecf20Sopenharmony_ci			goto free_pbc;
9088c2ecf20Sopenharmony_ci		}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci		if (frag_size) {
9118c2ecf20Sopenharmony_ci			size_t tidsmsize, n, pktsize, sz, addrlimit;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci			n = npages*((2*PAGE_SIZE/frag_size)+1);
9148c2ecf20Sopenharmony_ci			pktsize = struct_size(pkt, addr, n);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci			/*
9178c2ecf20Sopenharmony_ci			 * Determine if this is tid-sdma or just sdma.
9188c2ecf20Sopenharmony_ci			 */
9198c2ecf20Sopenharmony_ci			tiddma = (((le32_to_cpu(pbc[7])>>
9208c2ecf20Sopenharmony_ci				QLOGIC_IB_I_TID_SHIFT)&
9218c2ecf20Sopenharmony_ci				QLOGIC_IB_I_TID_MASK) !=
9228c2ecf20Sopenharmony_ci				QLOGIC_IB_I_TID_MASK);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci			if (tiddma)
9258c2ecf20Sopenharmony_ci				tidsmsize = iov[idx].iov_len;
9268c2ecf20Sopenharmony_ci			else
9278c2ecf20Sopenharmony_ci				tidsmsize = 0;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci			if (check_add_overflow(pktsize, tidsmsize, &sz)) {
9308c2ecf20Sopenharmony_ci				ret = -EINVAL;
9318c2ecf20Sopenharmony_ci				goto free_pbc;
9328c2ecf20Sopenharmony_ci			}
9338c2ecf20Sopenharmony_ci			pkt = kmalloc(sz, GFP_KERNEL);
9348c2ecf20Sopenharmony_ci			if (!pkt) {
9358c2ecf20Sopenharmony_ci				ret = -ENOMEM;
9368c2ecf20Sopenharmony_ci				goto free_pbc;
9378c2ecf20Sopenharmony_ci			}
9388c2ecf20Sopenharmony_ci			pkt->largepkt = 1;
9398c2ecf20Sopenharmony_ci			pkt->frag_size = frag_size;
9408c2ecf20Sopenharmony_ci			if (check_add_overflow(n, ARRAY_SIZE(pkt->addr),
9418c2ecf20Sopenharmony_ci					       &addrlimit) ||
9428c2ecf20Sopenharmony_ci			    addrlimit > type_max(typeof(pkt->addrlimit))) {
9438c2ecf20Sopenharmony_ci				ret = -EINVAL;
9448c2ecf20Sopenharmony_ci				goto free_pkt;
9458c2ecf20Sopenharmony_ci			}
9468c2ecf20Sopenharmony_ci			pkt->addrlimit = addrlimit;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci			if (tiddma) {
9498c2ecf20Sopenharmony_ci				char *tidsm = (char *)pkt + pktsize;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci				cfur = copy_from_user(tidsm,
9528c2ecf20Sopenharmony_ci					iov[idx].iov_base, tidsmsize);
9538c2ecf20Sopenharmony_ci				if (cfur) {
9548c2ecf20Sopenharmony_ci					ret = -EFAULT;
9558c2ecf20Sopenharmony_ci					goto free_pkt;
9568c2ecf20Sopenharmony_ci				}
9578c2ecf20Sopenharmony_ci				pkt->tidsm =
9588c2ecf20Sopenharmony_ci					(struct qib_tid_session_member *)tidsm;
9598c2ecf20Sopenharmony_ci				pkt->tidsmcount = tidsmsize/
9608c2ecf20Sopenharmony_ci					sizeof(struct qib_tid_session_member);
9618c2ecf20Sopenharmony_ci				pkt->tidsmidx = 0;
9628c2ecf20Sopenharmony_ci				idx++;
9638c2ecf20Sopenharmony_ci			}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci			/*
9668c2ecf20Sopenharmony_ci			 * pbc 'fill1' field is borrowed to pass frag size,
9678c2ecf20Sopenharmony_ci			 * we need to clear it after picking frag size, the
9688c2ecf20Sopenharmony_ci			 * hardware requires this field to be zero.
9698c2ecf20Sopenharmony_ci			 */
9708c2ecf20Sopenharmony_ci			*pbc = cpu_to_le32(le32_to_cpu(*pbc) & 0x0000FFFF);
9718c2ecf20Sopenharmony_ci		} else {
9728c2ecf20Sopenharmony_ci			pkt = kmem_cache_alloc(pq->pkt_slab, GFP_KERNEL);
9738c2ecf20Sopenharmony_ci			if (!pkt) {
9748c2ecf20Sopenharmony_ci				ret = -ENOMEM;
9758c2ecf20Sopenharmony_ci				goto free_pbc;
9768c2ecf20Sopenharmony_ci			}
9778c2ecf20Sopenharmony_ci			pkt->largepkt = 0;
9788c2ecf20Sopenharmony_ci			pkt->frag_size = bytes_togo;
9798c2ecf20Sopenharmony_ci			pkt->addrlimit = ARRAY_SIZE(pkt->addr);
9808c2ecf20Sopenharmony_ci		}
9818c2ecf20Sopenharmony_ci		pkt->bytes_togo = bytes_togo;
9828c2ecf20Sopenharmony_ci		pkt->payload_size = 0;
9838c2ecf20Sopenharmony_ci		pkt->counter = counter;
9848c2ecf20Sopenharmony_ci		pkt->tiddma = tiddma;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci		/* setup the first header */
9878c2ecf20Sopenharmony_ci		qib_user_sdma_init_frag(pkt, 0, /* index */
9888c2ecf20Sopenharmony_ci			0, len,		/* offset, len */
9898c2ecf20Sopenharmony_ci			1, 0,		/* first last desc */
9908c2ecf20Sopenharmony_ci			0, 0,		/* put page, dma mapped */
9918c2ecf20Sopenharmony_ci			NULL, pbc,	/* struct page, virt addr */
9928c2ecf20Sopenharmony_ci			dma_addr, len);	/* dma addr, dma length */
9938c2ecf20Sopenharmony_ci		pkt->index = 0;
9948c2ecf20Sopenharmony_ci		pkt->naddr = 1;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci		if (nfrags) {
9978c2ecf20Sopenharmony_ci			ret = qib_user_sdma_init_payload(dd, pq, pkt,
9988c2ecf20Sopenharmony_ci							 iov + idx_save + 1,
9998c2ecf20Sopenharmony_ci							 nfrags, npages);
10008c2ecf20Sopenharmony_ci			if (ret < 0)
10018c2ecf20Sopenharmony_ci				goto free_pkt;
10028c2ecf20Sopenharmony_ci		} else {
10038c2ecf20Sopenharmony_ci			/* since there is no payload, mark the
10048c2ecf20Sopenharmony_ci			 * header as the last desc. */
10058c2ecf20Sopenharmony_ci			pkt->addr[0].last_desc = 1;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci			if (dma_addr == 0) {
10088c2ecf20Sopenharmony_ci				/*
10098c2ecf20Sopenharmony_ci				 * the header is not dma mapped yet.
10108c2ecf20Sopenharmony_ci				 * it should be from kmalloc.
10118c2ecf20Sopenharmony_ci				 */
10128c2ecf20Sopenharmony_ci				dma_addr = dma_map_single(&dd->pcidev->dev,
10138c2ecf20Sopenharmony_ci					pbc, len, DMA_TO_DEVICE);
10148c2ecf20Sopenharmony_ci				if (dma_mapping_error(&dd->pcidev->dev,
10158c2ecf20Sopenharmony_ci								dma_addr)) {
10168c2ecf20Sopenharmony_ci					ret = -ENOMEM;
10178c2ecf20Sopenharmony_ci					goto free_pkt;
10188c2ecf20Sopenharmony_ci				}
10198c2ecf20Sopenharmony_ci				pkt->addr[0].addr = dma_addr;
10208c2ecf20Sopenharmony_ci				pkt->addr[0].dma_mapped = 1;
10218c2ecf20Sopenharmony_ci			}
10228c2ecf20Sopenharmony_ci		}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci		counter++;
10258c2ecf20Sopenharmony_ci		npkts++;
10268c2ecf20Sopenharmony_ci		pkt->pq = pq;
10278c2ecf20Sopenharmony_ci		pkt->index = 0; /* reset index for push on hw */
10288c2ecf20Sopenharmony_ci		*ndesc += pkt->naddr;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci		list_add_tail(&pkt->list, list);
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	*maxpkts = npkts;
10348c2ecf20Sopenharmony_ci	ret = idx;
10358c2ecf20Sopenharmony_ci	goto done;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cifree_pkt:
10388c2ecf20Sopenharmony_ci	if (pkt->largepkt)
10398c2ecf20Sopenharmony_ci		kfree(pkt);
10408c2ecf20Sopenharmony_ci	else
10418c2ecf20Sopenharmony_ci		kmem_cache_free(pq->pkt_slab, pkt);
10428c2ecf20Sopenharmony_cifree_pbc:
10438c2ecf20Sopenharmony_ci	if (dma_addr)
10448c2ecf20Sopenharmony_ci		dma_pool_free(pq->header_cache, pbc, dma_addr);
10458c2ecf20Sopenharmony_ci	else
10468c2ecf20Sopenharmony_ci		kfree(pbc);
10478c2ecf20Sopenharmony_cifree_list:
10488c2ecf20Sopenharmony_ci	qib_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, list);
10498c2ecf20Sopenharmony_cidone:
10508c2ecf20Sopenharmony_ci	return ret;
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_cistatic void qib_user_sdma_set_complete_counter(struct qib_user_sdma_queue *pq,
10548c2ecf20Sopenharmony_ci					       u32 c)
10558c2ecf20Sopenharmony_ci{
10568c2ecf20Sopenharmony_ci	pq->sent_counter = c;
10578c2ecf20Sopenharmony_ci}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci/* try to clean out queue -- needs pq->lock */
10608c2ecf20Sopenharmony_cistatic int qib_user_sdma_queue_clean(struct qib_pportdata *ppd,
10618c2ecf20Sopenharmony_ci				     struct qib_user_sdma_queue *pq)
10628c2ecf20Sopenharmony_ci{
10638c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
10648c2ecf20Sopenharmony_ci	struct list_head free_list;
10658c2ecf20Sopenharmony_ci	struct qib_user_sdma_pkt *pkt;
10668c2ecf20Sopenharmony_ci	struct qib_user_sdma_pkt *pkt_prev;
10678c2ecf20Sopenharmony_ci	unsigned long flags;
10688c2ecf20Sopenharmony_ci	int ret = 0;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (!pq->num_sending)
10718c2ecf20Sopenharmony_ci		return 0;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&free_list);
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	/*
10768c2ecf20Sopenharmony_ci	 * We need this spin lock here because interrupt handler
10778c2ecf20Sopenharmony_ci	 * might modify this list in qib_user_sdma_send_desc(), also
10788c2ecf20Sopenharmony_ci	 * we can not get interrupted, otherwise it is a deadlock.
10798c2ecf20Sopenharmony_ci	 */
10808c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pq->sent_lock, flags);
10818c2ecf20Sopenharmony_ci	list_for_each_entry_safe(pkt, pkt_prev, &pq->sent, list) {
10828c2ecf20Sopenharmony_ci		s64 descd = ppd->sdma_descq_removed - pkt->added;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci		if (descd < 0)
10858c2ecf20Sopenharmony_ci			break;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci		list_move_tail(&pkt->list, &free_list);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci		/* one more packet cleaned */
10908c2ecf20Sopenharmony_ci		ret++;
10918c2ecf20Sopenharmony_ci		pq->num_sending--;
10928c2ecf20Sopenharmony_ci	}
10938c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pq->sent_lock, flags);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	if (!list_empty(&free_list)) {
10968c2ecf20Sopenharmony_ci		u32 counter;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci		pkt = list_entry(free_list.prev,
10998c2ecf20Sopenharmony_ci				 struct qib_user_sdma_pkt, list);
11008c2ecf20Sopenharmony_ci		counter = pkt->counter;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci		qib_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, &free_list);
11038c2ecf20Sopenharmony_ci		qib_user_sdma_set_complete_counter(pq, counter);
11048c2ecf20Sopenharmony_ci	}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	return ret;
11078c2ecf20Sopenharmony_ci}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_civoid qib_user_sdma_queue_destroy(struct qib_user_sdma_queue *pq)
11108c2ecf20Sopenharmony_ci{
11118c2ecf20Sopenharmony_ci	if (!pq)
11128c2ecf20Sopenharmony_ci		return;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	pq->sdma_rb_node->refcount--;
11158c2ecf20Sopenharmony_ci	if (pq->sdma_rb_node->refcount == 0) {
11168c2ecf20Sopenharmony_ci		rb_erase(&pq->sdma_rb_node->node, &qib_user_sdma_rb_root);
11178c2ecf20Sopenharmony_ci		kfree(pq->sdma_rb_node);
11188c2ecf20Sopenharmony_ci	}
11198c2ecf20Sopenharmony_ci	dma_pool_destroy(pq->header_cache);
11208c2ecf20Sopenharmony_ci	kmem_cache_destroy(pq->pkt_slab);
11218c2ecf20Sopenharmony_ci	kfree(pq);
11228c2ecf20Sopenharmony_ci}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci/* clean descriptor queue, returns > 0 if some elements cleaned */
11258c2ecf20Sopenharmony_cistatic int qib_user_sdma_hwqueue_clean(struct qib_pportdata *ppd)
11268c2ecf20Sopenharmony_ci{
11278c2ecf20Sopenharmony_ci	int ret;
11288c2ecf20Sopenharmony_ci	unsigned long flags;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ppd->sdma_lock, flags);
11318c2ecf20Sopenharmony_ci	ret = qib_sdma_make_progress(ppd);
11328c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ppd->sdma_lock, flags);
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	return ret;
11358c2ecf20Sopenharmony_ci}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci/* we're in close, drain packets so that we can cleanup successfully... */
11388c2ecf20Sopenharmony_civoid qib_user_sdma_queue_drain(struct qib_pportdata *ppd,
11398c2ecf20Sopenharmony_ci			       struct qib_user_sdma_queue *pq)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
11428c2ecf20Sopenharmony_ci	unsigned long flags;
11438c2ecf20Sopenharmony_ci	int i;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	if (!pq)
11468c2ecf20Sopenharmony_ci		return;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	for (i = 0; i < QIB_USER_SDMA_DRAIN_TIMEOUT; i++) {
11498c2ecf20Sopenharmony_ci		mutex_lock(&pq->lock);
11508c2ecf20Sopenharmony_ci		if (!pq->num_pending && !pq->num_sending) {
11518c2ecf20Sopenharmony_ci			mutex_unlock(&pq->lock);
11528c2ecf20Sopenharmony_ci			break;
11538c2ecf20Sopenharmony_ci		}
11548c2ecf20Sopenharmony_ci		qib_user_sdma_hwqueue_clean(ppd);
11558c2ecf20Sopenharmony_ci		qib_user_sdma_queue_clean(ppd, pq);
11568c2ecf20Sopenharmony_ci		mutex_unlock(&pq->lock);
11578c2ecf20Sopenharmony_ci		msleep(20);
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	if (pq->num_pending || pq->num_sending) {
11618c2ecf20Sopenharmony_ci		struct qib_user_sdma_pkt *pkt;
11628c2ecf20Sopenharmony_ci		struct qib_user_sdma_pkt *pkt_prev;
11638c2ecf20Sopenharmony_ci		struct list_head free_list;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci		mutex_lock(&pq->lock);
11668c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ppd->sdma_lock, flags);
11678c2ecf20Sopenharmony_ci		/*
11688c2ecf20Sopenharmony_ci		 * Since we hold sdma_lock, it is safe without sent_lock.
11698c2ecf20Sopenharmony_ci		 */
11708c2ecf20Sopenharmony_ci		if (pq->num_pending) {
11718c2ecf20Sopenharmony_ci			list_for_each_entry_safe(pkt, pkt_prev,
11728c2ecf20Sopenharmony_ci					&ppd->sdma_userpending, list) {
11738c2ecf20Sopenharmony_ci				if (pkt->pq == pq) {
11748c2ecf20Sopenharmony_ci					list_move_tail(&pkt->list, &pq->sent);
11758c2ecf20Sopenharmony_ci					pq->num_pending--;
11768c2ecf20Sopenharmony_ci					pq->num_sending++;
11778c2ecf20Sopenharmony_ci				}
11788c2ecf20Sopenharmony_ci			}
11798c2ecf20Sopenharmony_ci		}
11808c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ppd->sdma_lock, flags);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci		qib_dev_err(dd, "user sdma lists not empty: forcing!\n");
11838c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&free_list);
11848c2ecf20Sopenharmony_ci		list_splice_init(&pq->sent, &free_list);
11858c2ecf20Sopenharmony_ci		pq->num_sending = 0;
11868c2ecf20Sopenharmony_ci		qib_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, &free_list);
11878c2ecf20Sopenharmony_ci		mutex_unlock(&pq->lock);
11888c2ecf20Sopenharmony_ci	}
11898c2ecf20Sopenharmony_ci}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_cistatic inline __le64 qib_sdma_make_desc0(u8 gen,
11928c2ecf20Sopenharmony_ci					 u64 addr, u64 dwlen, u64 dwoffset)
11938c2ecf20Sopenharmony_ci{
11948c2ecf20Sopenharmony_ci	return cpu_to_le64(/* SDmaPhyAddr[31:0] */
11958c2ecf20Sopenharmony_ci			   ((addr & 0xfffffffcULL) << 32) |
11968c2ecf20Sopenharmony_ci			   /* SDmaGeneration[1:0] */
11978c2ecf20Sopenharmony_ci			   ((gen & 3ULL) << 30) |
11988c2ecf20Sopenharmony_ci			   /* SDmaDwordCount[10:0] */
11998c2ecf20Sopenharmony_ci			   ((dwlen & 0x7ffULL) << 16) |
12008c2ecf20Sopenharmony_ci			   /* SDmaBufOffset[12:2] */
12018c2ecf20Sopenharmony_ci			   (dwoffset & 0x7ffULL));
12028c2ecf20Sopenharmony_ci}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_cistatic inline __le64 qib_sdma_make_first_desc0(__le64 descq)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	return descq | cpu_to_le64(1ULL << 12);
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_cistatic inline __le64 qib_sdma_make_last_desc0(__le64 descq)
12108c2ecf20Sopenharmony_ci{
12118c2ecf20Sopenharmony_ci					      /* last */  /* dma head */
12128c2ecf20Sopenharmony_ci	return descq | cpu_to_le64(1ULL << 11 | 1ULL << 13);
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_cistatic inline __le64 qib_sdma_make_desc1(u64 addr)
12168c2ecf20Sopenharmony_ci{
12178c2ecf20Sopenharmony_ci	/* SDmaPhyAddr[47:32] */
12188c2ecf20Sopenharmony_ci	return cpu_to_le64(addr >> 32);
12198c2ecf20Sopenharmony_ci}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_cistatic void qib_user_sdma_send_frag(struct qib_pportdata *ppd,
12228c2ecf20Sopenharmony_ci				    struct qib_user_sdma_pkt *pkt, int idx,
12238c2ecf20Sopenharmony_ci				    unsigned ofs, u16 tail, u8 gen)
12248c2ecf20Sopenharmony_ci{
12258c2ecf20Sopenharmony_ci	const u64 addr = (u64) pkt->addr[idx].addr +
12268c2ecf20Sopenharmony_ci		(u64) pkt->addr[idx].offset;
12278c2ecf20Sopenharmony_ci	const u64 dwlen = (u64) pkt->addr[idx].length / 4;
12288c2ecf20Sopenharmony_ci	__le64 *descqp;
12298c2ecf20Sopenharmony_ci	__le64 descq0;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	descqp = &ppd->sdma_descq[tail].qw[0];
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	descq0 = qib_sdma_make_desc0(gen, addr, dwlen, ofs);
12348c2ecf20Sopenharmony_ci	if (pkt->addr[idx].first_desc)
12358c2ecf20Sopenharmony_ci		descq0 = qib_sdma_make_first_desc0(descq0);
12368c2ecf20Sopenharmony_ci	if (pkt->addr[idx].last_desc) {
12378c2ecf20Sopenharmony_ci		descq0 = qib_sdma_make_last_desc0(descq0);
12388c2ecf20Sopenharmony_ci		if (ppd->sdma_intrequest) {
12398c2ecf20Sopenharmony_ci			descq0 |= cpu_to_le64(1ULL << 15);
12408c2ecf20Sopenharmony_ci			ppd->sdma_intrequest = 0;
12418c2ecf20Sopenharmony_ci		}
12428c2ecf20Sopenharmony_ci	}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	descqp[0] = descq0;
12458c2ecf20Sopenharmony_ci	descqp[1] = qib_sdma_make_desc1(addr);
12468c2ecf20Sopenharmony_ci}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_civoid qib_user_sdma_send_desc(struct qib_pportdata *ppd,
12498c2ecf20Sopenharmony_ci				struct list_head *pktlist)
12508c2ecf20Sopenharmony_ci{
12518c2ecf20Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
12528c2ecf20Sopenharmony_ci	u16 nfree, nsent;
12538c2ecf20Sopenharmony_ci	u16 tail, tail_c;
12548c2ecf20Sopenharmony_ci	u8 gen, gen_c;
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	nfree = qib_sdma_descq_freecnt(ppd);
12578c2ecf20Sopenharmony_ci	if (!nfree)
12588c2ecf20Sopenharmony_ci		return;
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ciretry:
12618c2ecf20Sopenharmony_ci	nsent = 0;
12628c2ecf20Sopenharmony_ci	tail_c = tail = ppd->sdma_descq_tail;
12638c2ecf20Sopenharmony_ci	gen_c = gen = ppd->sdma_generation;
12648c2ecf20Sopenharmony_ci	while (!list_empty(pktlist)) {
12658c2ecf20Sopenharmony_ci		struct qib_user_sdma_pkt *pkt =
12668c2ecf20Sopenharmony_ci			list_entry(pktlist->next, struct qib_user_sdma_pkt,
12678c2ecf20Sopenharmony_ci				   list);
12688c2ecf20Sopenharmony_ci		int i, j, c = 0;
12698c2ecf20Sopenharmony_ci		unsigned ofs = 0;
12708c2ecf20Sopenharmony_ci		u16 dtail = tail;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci		for (i = pkt->index; i < pkt->naddr && nfree; i++) {
12738c2ecf20Sopenharmony_ci			qib_user_sdma_send_frag(ppd, pkt, i, ofs, tail, gen);
12748c2ecf20Sopenharmony_ci			ofs += pkt->addr[i].length >> 2;
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci			if (++tail == ppd->sdma_descq_cnt) {
12778c2ecf20Sopenharmony_ci				tail = 0;
12788c2ecf20Sopenharmony_ci				++gen;
12798c2ecf20Sopenharmony_ci				ppd->sdma_intrequest = 1;
12808c2ecf20Sopenharmony_ci			} else if (tail == (ppd->sdma_descq_cnt>>1)) {
12818c2ecf20Sopenharmony_ci				ppd->sdma_intrequest = 1;
12828c2ecf20Sopenharmony_ci			}
12838c2ecf20Sopenharmony_ci			nfree--;
12848c2ecf20Sopenharmony_ci			if (pkt->addr[i].last_desc == 0)
12858c2ecf20Sopenharmony_ci				continue;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci			/*
12888c2ecf20Sopenharmony_ci			 * If the packet is >= 2KB mtu equivalent, we
12898c2ecf20Sopenharmony_ci			 * have to use the large buffers, and have to
12908c2ecf20Sopenharmony_ci			 * mark each descriptor as part of a large
12918c2ecf20Sopenharmony_ci			 * buffer packet.
12928c2ecf20Sopenharmony_ci			 */
12938c2ecf20Sopenharmony_ci			if (ofs > dd->piosize2kmax_dwords) {
12948c2ecf20Sopenharmony_ci				for (j = pkt->index; j <= i; j++) {
12958c2ecf20Sopenharmony_ci					ppd->sdma_descq[dtail].qw[0] |=
12968c2ecf20Sopenharmony_ci						cpu_to_le64(1ULL << 14);
12978c2ecf20Sopenharmony_ci					if (++dtail == ppd->sdma_descq_cnt)
12988c2ecf20Sopenharmony_ci						dtail = 0;
12998c2ecf20Sopenharmony_ci				}
13008c2ecf20Sopenharmony_ci			}
13018c2ecf20Sopenharmony_ci			c += i + 1 - pkt->index;
13028c2ecf20Sopenharmony_ci			pkt->index = i + 1; /* index for next first */
13038c2ecf20Sopenharmony_ci			tail_c = dtail = tail;
13048c2ecf20Sopenharmony_ci			gen_c = gen;
13058c2ecf20Sopenharmony_ci			ofs = 0;  /* reset for next packet */
13068c2ecf20Sopenharmony_ci		}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci		ppd->sdma_descq_added += c;
13098c2ecf20Sopenharmony_ci		nsent += c;
13108c2ecf20Sopenharmony_ci		if (pkt->index == pkt->naddr) {
13118c2ecf20Sopenharmony_ci			pkt->added = ppd->sdma_descq_added;
13128c2ecf20Sopenharmony_ci			pkt->pq->added = pkt->added;
13138c2ecf20Sopenharmony_ci			pkt->pq->num_pending--;
13148c2ecf20Sopenharmony_ci			spin_lock(&pkt->pq->sent_lock);
13158c2ecf20Sopenharmony_ci			pkt->pq->num_sending++;
13168c2ecf20Sopenharmony_ci			list_move_tail(&pkt->list, &pkt->pq->sent);
13178c2ecf20Sopenharmony_ci			spin_unlock(&pkt->pq->sent_lock);
13188c2ecf20Sopenharmony_ci		}
13198c2ecf20Sopenharmony_ci		if (!nfree || (nsent<<2) > ppd->sdma_descq_cnt)
13208c2ecf20Sopenharmony_ci			break;
13218c2ecf20Sopenharmony_ci	}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	/* advance the tail on the chip if necessary */
13248c2ecf20Sopenharmony_ci	if (ppd->sdma_descq_tail != tail_c) {
13258c2ecf20Sopenharmony_ci		ppd->sdma_generation = gen_c;
13268c2ecf20Sopenharmony_ci		dd->f_sdma_update_tail(ppd, tail_c);
13278c2ecf20Sopenharmony_ci	}
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	if (nfree && !list_empty(pktlist))
13308c2ecf20Sopenharmony_ci		goto retry;
13318c2ecf20Sopenharmony_ci}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci/* pq->lock must be held, get packets on the wire... */
13348c2ecf20Sopenharmony_cistatic int qib_user_sdma_push_pkts(struct qib_pportdata *ppd,
13358c2ecf20Sopenharmony_ci				 struct qib_user_sdma_queue *pq,
13368c2ecf20Sopenharmony_ci				 struct list_head *pktlist, int count)
13378c2ecf20Sopenharmony_ci{
13388c2ecf20Sopenharmony_ci	unsigned long flags;
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	if (unlikely(!(ppd->lflags & QIBL_LINKACTIVE)))
13418c2ecf20Sopenharmony_ci		return -ECOMM;
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	/* non-blocking mode */
13448c2ecf20Sopenharmony_ci	if (pq->sdma_rb_node->refcount > 1) {
13458c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ppd->sdma_lock, flags);
13468c2ecf20Sopenharmony_ci		if (unlikely(!__qib_sdma_running(ppd))) {
13478c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ppd->sdma_lock, flags);
13488c2ecf20Sopenharmony_ci			return -ECOMM;
13498c2ecf20Sopenharmony_ci		}
13508c2ecf20Sopenharmony_ci		pq->num_pending += count;
13518c2ecf20Sopenharmony_ci		list_splice_tail_init(pktlist, &ppd->sdma_userpending);
13528c2ecf20Sopenharmony_ci		qib_user_sdma_send_desc(ppd, &ppd->sdma_userpending);
13538c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ppd->sdma_lock, flags);
13548c2ecf20Sopenharmony_ci		return 0;
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	/* In this case, descriptors from this process are not
13588c2ecf20Sopenharmony_ci	 * linked to ppd pending queue, interrupt handler
13598c2ecf20Sopenharmony_ci	 * won't update this process, it is OK to directly
13608c2ecf20Sopenharmony_ci	 * modify without sdma lock.
13618c2ecf20Sopenharmony_ci	 */
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	pq->num_pending += count;
13658c2ecf20Sopenharmony_ci	/*
13668c2ecf20Sopenharmony_ci	 * Blocking mode for single rail process, we must
13678c2ecf20Sopenharmony_ci	 * release/regain sdma_lock to give other process
13688c2ecf20Sopenharmony_ci	 * chance to make progress. This is important for
13698c2ecf20Sopenharmony_ci	 * performance.
13708c2ecf20Sopenharmony_ci	 */
13718c2ecf20Sopenharmony_ci	do {
13728c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ppd->sdma_lock, flags);
13738c2ecf20Sopenharmony_ci		if (unlikely(!__qib_sdma_running(ppd))) {
13748c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ppd->sdma_lock, flags);
13758c2ecf20Sopenharmony_ci			return -ECOMM;
13768c2ecf20Sopenharmony_ci		}
13778c2ecf20Sopenharmony_ci		qib_user_sdma_send_desc(ppd, pktlist);
13788c2ecf20Sopenharmony_ci		if (!list_empty(pktlist))
13798c2ecf20Sopenharmony_ci			qib_sdma_make_progress(ppd);
13808c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ppd->sdma_lock, flags);
13818c2ecf20Sopenharmony_ci	} while (!list_empty(pktlist));
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	return 0;
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ciint qib_user_sdma_writev(struct qib_ctxtdata *rcd,
13878c2ecf20Sopenharmony_ci			 struct qib_user_sdma_queue *pq,
13888c2ecf20Sopenharmony_ci			 const struct iovec *iov,
13898c2ecf20Sopenharmony_ci			 unsigned long dim)
13908c2ecf20Sopenharmony_ci{
13918c2ecf20Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
13928c2ecf20Sopenharmony_ci	struct qib_pportdata *ppd = rcd->ppd;
13938c2ecf20Sopenharmony_ci	int ret = 0;
13948c2ecf20Sopenharmony_ci	struct list_head list;
13958c2ecf20Sopenharmony_ci	int npkts = 0;
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&list);
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	mutex_lock(&pq->lock);
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	/* why not -ECOMM like qib_user_sdma_push_pkts() below? */
14028c2ecf20Sopenharmony_ci	if (!qib_sdma_running(ppd))
14038c2ecf20Sopenharmony_ci		goto done_unlock;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	/* if I have packets not complete yet */
14068c2ecf20Sopenharmony_ci	if (pq->added > ppd->sdma_descq_removed)
14078c2ecf20Sopenharmony_ci		qib_user_sdma_hwqueue_clean(ppd);
14088c2ecf20Sopenharmony_ci	/* if I have complete packets to be freed */
14098c2ecf20Sopenharmony_ci	if (pq->num_sending)
14108c2ecf20Sopenharmony_ci		qib_user_sdma_queue_clean(ppd, pq);
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	while (dim) {
14138c2ecf20Sopenharmony_ci		int mxp = 1;
14148c2ecf20Sopenharmony_ci		int ndesc = 0;
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci		ret = qib_user_sdma_queue_pkts(dd, ppd, pq,
14178c2ecf20Sopenharmony_ci				iov, dim, &list, &mxp, &ndesc);
14188c2ecf20Sopenharmony_ci		if (ret < 0)
14198c2ecf20Sopenharmony_ci			goto done_unlock;
14208c2ecf20Sopenharmony_ci		else {
14218c2ecf20Sopenharmony_ci			dim -= ret;
14228c2ecf20Sopenharmony_ci			iov += ret;
14238c2ecf20Sopenharmony_ci		}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci		/* force packets onto the sdma hw queue... */
14268c2ecf20Sopenharmony_ci		if (!list_empty(&list)) {
14278c2ecf20Sopenharmony_ci			/*
14288c2ecf20Sopenharmony_ci			 * Lazily clean hw queue.
14298c2ecf20Sopenharmony_ci			 */
14308c2ecf20Sopenharmony_ci			if (qib_sdma_descq_freecnt(ppd) < ndesc) {
14318c2ecf20Sopenharmony_ci				qib_user_sdma_hwqueue_clean(ppd);
14328c2ecf20Sopenharmony_ci				if (pq->num_sending)
14338c2ecf20Sopenharmony_ci					qib_user_sdma_queue_clean(ppd, pq);
14348c2ecf20Sopenharmony_ci			}
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci			ret = qib_user_sdma_push_pkts(ppd, pq, &list, mxp);
14378c2ecf20Sopenharmony_ci			if (ret < 0)
14388c2ecf20Sopenharmony_ci				goto done_unlock;
14398c2ecf20Sopenharmony_ci			else {
14408c2ecf20Sopenharmony_ci				npkts += mxp;
14418c2ecf20Sopenharmony_ci				pq->counter += mxp;
14428c2ecf20Sopenharmony_ci			}
14438c2ecf20Sopenharmony_ci		}
14448c2ecf20Sopenharmony_ci	}
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_cidone_unlock:
14478c2ecf20Sopenharmony_ci	if (!list_empty(&list))
14488c2ecf20Sopenharmony_ci		qib_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, &list);
14498c2ecf20Sopenharmony_ci	mutex_unlock(&pq->lock);
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	return (ret < 0) ? ret : npkts;
14528c2ecf20Sopenharmony_ci}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ciint qib_user_sdma_make_progress(struct qib_pportdata *ppd,
14558c2ecf20Sopenharmony_ci				struct qib_user_sdma_queue *pq)
14568c2ecf20Sopenharmony_ci{
14578c2ecf20Sopenharmony_ci	int ret = 0;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	mutex_lock(&pq->lock);
14608c2ecf20Sopenharmony_ci	qib_user_sdma_hwqueue_clean(ppd);
14618c2ecf20Sopenharmony_ci	ret = qib_user_sdma_queue_clean(ppd, pq);
14628c2ecf20Sopenharmony_ci	mutex_unlock(&pq->lock);
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	return ret;
14658c2ecf20Sopenharmony_ci}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ciu32 qib_user_sdma_complete_counter(const struct qib_user_sdma_queue *pq)
14688c2ecf20Sopenharmony_ci{
14698c2ecf20Sopenharmony_ci	return pq ? pq->sent_counter : 0;
14708c2ecf20Sopenharmony_ci}
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ciu32 qib_user_sdma_inflight_counter(struct qib_user_sdma_queue *pq)
14738c2ecf20Sopenharmony_ci{
14748c2ecf20Sopenharmony_ci	return pq ? pq->counter : 0;
14758c2ecf20Sopenharmony_ci}
1476