162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved.
362306a36Sopenharmony_ci * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
462306a36Sopenharmony_ci * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This software is available to you under a choice of one of two
762306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
1062306a36Sopenharmony_ci * OpenIB.org BSD license below:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1362306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1462306a36Sopenharmony_ci *     conditions are met:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1762306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1862306a36Sopenharmony_ci *        disclaimer.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2162306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2262306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2362306a36Sopenharmony_ci *        provided with the distribution.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3262306a36Sopenharmony_ci * SOFTWARE.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/pci.h>
3662306a36Sopenharmony_ci#include <linux/poll.h>
3762306a36Sopenharmony_ci#include <linux/cdev.h>
3862306a36Sopenharmony_ci#include <linux/swap.h>
3962306a36Sopenharmony_ci#include <linux/vmalloc.h>
4062306a36Sopenharmony_ci#include <linux/highmem.h>
4162306a36Sopenharmony_ci#include <linux/io.h>
4262306a36Sopenharmony_ci#include <linux/jiffies.h>
4362306a36Sopenharmony_ci#include <linux/delay.h>
4462306a36Sopenharmony_ci#include <linux/export.h>
4562306a36Sopenharmony_ci#include <linux/uio.h>
4662306a36Sopenharmony_ci#include <linux/pgtable.h>
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#include <rdma/ib.h>
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#include "qib.h"
5162306a36Sopenharmony_ci#include "qib_common.h"
5262306a36Sopenharmony_ci#include "qib_user_sdma.h"
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#undef pr_fmt
5562306a36Sopenharmony_ci#define pr_fmt(fmt) QIB_DRV_NAME ": " fmt
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic int qib_open(struct inode *, struct file *);
5862306a36Sopenharmony_cistatic int qib_close(struct inode *, struct file *);
5962306a36Sopenharmony_cistatic ssize_t qib_write(struct file *, const char __user *, size_t, loff_t *);
6062306a36Sopenharmony_cistatic ssize_t qib_write_iter(struct kiocb *, struct iov_iter *);
6162306a36Sopenharmony_cistatic __poll_t qib_poll(struct file *, struct poll_table_struct *);
6262306a36Sopenharmony_cistatic int qib_mmapf(struct file *, struct vm_area_struct *);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/*
6562306a36Sopenharmony_ci * This is really, really weird shit - write() and writev() here
6662306a36Sopenharmony_ci * have completely unrelated semantics.  Sucky userland ABI,
6762306a36Sopenharmony_ci * film at 11.
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_cistatic const struct file_operations qib_file_ops = {
7062306a36Sopenharmony_ci	.owner = THIS_MODULE,
7162306a36Sopenharmony_ci	.write = qib_write,
7262306a36Sopenharmony_ci	.write_iter = qib_write_iter,
7362306a36Sopenharmony_ci	.open = qib_open,
7462306a36Sopenharmony_ci	.release = qib_close,
7562306a36Sopenharmony_ci	.poll = qib_poll,
7662306a36Sopenharmony_ci	.mmap = qib_mmapf,
7762306a36Sopenharmony_ci	.llseek = noop_llseek,
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/*
8162306a36Sopenharmony_ci * Convert kernel virtual addresses to physical addresses so they don't
8262306a36Sopenharmony_ci * potentially conflict with the chip addresses used as mmap offsets.
8362306a36Sopenharmony_ci * It doesn't really matter what mmap offset we use as long as we can
8462306a36Sopenharmony_ci * interpret it correctly.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_cistatic u64 cvt_kvaddr(void *p)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct page *page;
8962306a36Sopenharmony_ci	u64 paddr = 0;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	page = vmalloc_to_page(p);
9262306a36Sopenharmony_ci	if (page)
9362306a36Sopenharmony_ci		paddr = page_to_pfn(page) << PAGE_SHIFT;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return paddr;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic int qib_get_base_info(struct file *fp, void __user *ubase,
9962306a36Sopenharmony_ci			     size_t ubase_size)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct qib_ctxtdata *rcd = ctxt_fp(fp);
10262306a36Sopenharmony_ci	int ret = 0;
10362306a36Sopenharmony_ci	struct qib_base_info *kinfo = NULL;
10462306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
10562306a36Sopenharmony_ci	struct qib_pportdata *ppd = rcd->ppd;
10662306a36Sopenharmony_ci	unsigned subctxt_cnt;
10762306a36Sopenharmony_ci	int shared, master;
10862306a36Sopenharmony_ci	size_t sz;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	subctxt_cnt = rcd->subctxt_cnt;
11162306a36Sopenharmony_ci	if (!subctxt_cnt) {
11262306a36Sopenharmony_ci		shared = 0;
11362306a36Sopenharmony_ci		master = 0;
11462306a36Sopenharmony_ci		subctxt_cnt = 1;
11562306a36Sopenharmony_ci	} else {
11662306a36Sopenharmony_ci		shared = 1;
11762306a36Sopenharmony_ci		master = !subctxt_fp(fp);
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	sz = sizeof(*kinfo);
12162306a36Sopenharmony_ci	/* If context sharing is not requested, allow the old size structure */
12262306a36Sopenharmony_ci	if (!shared)
12362306a36Sopenharmony_ci		sz -= 7 * sizeof(u64);
12462306a36Sopenharmony_ci	if (ubase_size < sz) {
12562306a36Sopenharmony_ci		ret = -EINVAL;
12662306a36Sopenharmony_ci		goto bail;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	kinfo = kzalloc(sizeof(*kinfo), GFP_KERNEL);
13062306a36Sopenharmony_ci	if (kinfo == NULL) {
13162306a36Sopenharmony_ci		ret = -ENOMEM;
13262306a36Sopenharmony_ci		goto bail;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	ret = dd->f_get_base_info(rcd, kinfo);
13662306a36Sopenharmony_ci	if (ret < 0)
13762306a36Sopenharmony_ci		goto bail;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	kinfo->spi_rcvhdr_cnt = dd->rcvhdrcnt;
14062306a36Sopenharmony_ci	kinfo->spi_rcvhdrent_size = dd->rcvhdrentsize;
14162306a36Sopenharmony_ci	kinfo->spi_tidegrcnt = rcd->rcvegrcnt;
14262306a36Sopenharmony_ci	kinfo->spi_rcv_egrbufsize = dd->rcvegrbufsize;
14362306a36Sopenharmony_ci	/*
14462306a36Sopenharmony_ci	 * have to mmap whole thing
14562306a36Sopenharmony_ci	 */
14662306a36Sopenharmony_ci	kinfo->spi_rcv_egrbuftotlen =
14762306a36Sopenharmony_ci		rcd->rcvegrbuf_chunks * rcd->rcvegrbuf_size;
14862306a36Sopenharmony_ci	kinfo->spi_rcv_egrperchunk = rcd->rcvegrbufs_perchunk;
14962306a36Sopenharmony_ci	kinfo->spi_rcv_egrchunksize = kinfo->spi_rcv_egrbuftotlen /
15062306a36Sopenharmony_ci		rcd->rcvegrbuf_chunks;
15162306a36Sopenharmony_ci	kinfo->spi_tidcnt = dd->rcvtidcnt / subctxt_cnt;
15262306a36Sopenharmony_ci	if (master)
15362306a36Sopenharmony_ci		kinfo->spi_tidcnt += dd->rcvtidcnt % subctxt_cnt;
15462306a36Sopenharmony_ci	/*
15562306a36Sopenharmony_ci	 * for this use, may be cfgctxts summed over all chips that
15662306a36Sopenharmony_ci	 * are configured and present
15762306a36Sopenharmony_ci	 */
15862306a36Sopenharmony_ci	kinfo->spi_nctxts = dd->cfgctxts;
15962306a36Sopenharmony_ci	/* unit (chip/board) our context is on */
16062306a36Sopenharmony_ci	kinfo->spi_unit = dd->unit;
16162306a36Sopenharmony_ci	kinfo->spi_port = ppd->port;
16262306a36Sopenharmony_ci	/* for now, only a single page */
16362306a36Sopenharmony_ci	kinfo->spi_tid_maxsize = PAGE_SIZE;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/*
16662306a36Sopenharmony_ci	 * Doing this per context, and based on the skip value, etc.  This has
16762306a36Sopenharmony_ci	 * to be the actual buffer size, since the protocol code treats it
16862306a36Sopenharmony_ci	 * as an array.
16962306a36Sopenharmony_ci	 *
17062306a36Sopenharmony_ci	 * These have to be set to user addresses in the user code via mmap.
17162306a36Sopenharmony_ci	 * These values are used on return to user code for the mmap target
17262306a36Sopenharmony_ci	 * addresses only.  For 32 bit, same 44 bit address problem, so use
17362306a36Sopenharmony_ci	 * the physical address, not virtual.  Before 2.6.11, using the
17462306a36Sopenharmony_ci	 * page_address() macro worked, but in 2.6.11, even that returns the
17562306a36Sopenharmony_ci	 * full 64 bit address (upper bits all 1's).  So far, using the
17662306a36Sopenharmony_ci	 * physical addresses (or chip offsets, for chip mapping) works, but
17762306a36Sopenharmony_ci	 * no doubt some future kernel release will change that, and we'll be
17862306a36Sopenharmony_ci	 * on to yet another method of dealing with this.
17962306a36Sopenharmony_ci	 * Normally only one of rcvhdr_tailaddr or rhf_offset is useful
18062306a36Sopenharmony_ci	 * since the chips with non-zero rhf_offset don't normally
18162306a36Sopenharmony_ci	 * enable tail register updates to host memory, but for testing,
18262306a36Sopenharmony_ci	 * both can be enabled and used.
18362306a36Sopenharmony_ci	 */
18462306a36Sopenharmony_ci	kinfo->spi_rcvhdr_base = (u64) rcd->rcvhdrq_phys;
18562306a36Sopenharmony_ci	kinfo->spi_rcvhdr_tailaddr = (u64) rcd->rcvhdrqtailaddr_phys;
18662306a36Sopenharmony_ci	kinfo->spi_rhf_offset = dd->rhf_offset;
18762306a36Sopenharmony_ci	kinfo->spi_rcv_egrbufs = (u64) rcd->rcvegr_phys;
18862306a36Sopenharmony_ci	kinfo->spi_pioavailaddr = (u64) dd->pioavailregs_phys;
18962306a36Sopenharmony_ci	/* setup per-unit (not port) status area for user programs */
19062306a36Sopenharmony_ci	kinfo->spi_status = (u64) kinfo->spi_pioavailaddr +
19162306a36Sopenharmony_ci		(char *) ppd->statusp -
19262306a36Sopenharmony_ci		(char *) dd->pioavailregs_dma;
19362306a36Sopenharmony_ci	kinfo->spi_uregbase = (u64) dd->uregbase + dd->ureg_align * rcd->ctxt;
19462306a36Sopenharmony_ci	if (!shared) {
19562306a36Sopenharmony_ci		kinfo->spi_piocnt = rcd->piocnt;
19662306a36Sopenharmony_ci		kinfo->spi_piobufbase = (u64) rcd->piobufs;
19762306a36Sopenharmony_ci		kinfo->spi_sendbuf_status = cvt_kvaddr(rcd->user_event_mask);
19862306a36Sopenharmony_ci	} else if (master) {
19962306a36Sopenharmony_ci		kinfo->spi_piocnt = (rcd->piocnt / subctxt_cnt) +
20062306a36Sopenharmony_ci				    (rcd->piocnt % subctxt_cnt);
20162306a36Sopenharmony_ci		/* Master's PIO buffers are after all the slave's */
20262306a36Sopenharmony_ci		kinfo->spi_piobufbase = (u64) rcd->piobufs +
20362306a36Sopenharmony_ci			dd->palign *
20462306a36Sopenharmony_ci			(rcd->piocnt - kinfo->spi_piocnt);
20562306a36Sopenharmony_ci	} else {
20662306a36Sopenharmony_ci		unsigned slave = subctxt_fp(fp) - 1;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci		kinfo->spi_piocnt = rcd->piocnt / subctxt_cnt;
20962306a36Sopenharmony_ci		kinfo->spi_piobufbase = (u64) rcd->piobufs +
21062306a36Sopenharmony_ci			dd->palign * kinfo->spi_piocnt * slave;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (shared) {
21462306a36Sopenharmony_ci		kinfo->spi_sendbuf_status =
21562306a36Sopenharmony_ci			cvt_kvaddr(&rcd->user_event_mask[subctxt_fp(fp)]);
21662306a36Sopenharmony_ci		/* only spi_subctxt_* fields should be set in this block! */
21762306a36Sopenharmony_ci		kinfo->spi_subctxt_uregbase = cvt_kvaddr(rcd->subctxt_uregbase);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		kinfo->spi_subctxt_rcvegrbuf =
22062306a36Sopenharmony_ci			cvt_kvaddr(rcd->subctxt_rcvegrbuf);
22162306a36Sopenharmony_ci		kinfo->spi_subctxt_rcvhdr_base =
22262306a36Sopenharmony_ci			cvt_kvaddr(rcd->subctxt_rcvhdr_base);
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/*
22662306a36Sopenharmony_ci	 * All user buffers are 2KB buffers.  If we ever support
22762306a36Sopenharmony_ci	 * giving 4KB buffers to user processes, this will need some
22862306a36Sopenharmony_ci	 * work.  Can't use piobufbase directly, because it has
22962306a36Sopenharmony_ci	 * both 2K and 4K buffer base values.
23062306a36Sopenharmony_ci	 */
23162306a36Sopenharmony_ci	kinfo->spi_pioindex = (kinfo->spi_piobufbase - dd->pio2k_bufbase) /
23262306a36Sopenharmony_ci		dd->palign;
23362306a36Sopenharmony_ci	kinfo->spi_pioalign = dd->palign;
23462306a36Sopenharmony_ci	kinfo->spi_qpair = QIB_KD_QP;
23562306a36Sopenharmony_ci	/*
23662306a36Sopenharmony_ci	 * user mode PIO buffers are always 2KB, even when 4KB can
23762306a36Sopenharmony_ci	 * be received, and sent via the kernel; this is ibmaxlen
23862306a36Sopenharmony_ci	 * for 2K MTU.
23962306a36Sopenharmony_ci	 */
24062306a36Sopenharmony_ci	kinfo->spi_piosize = dd->piosize2k - 2 * sizeof(u32);
24162306a36Sopenharmony_ci	kinfo->spi_mtu = ppd->ibmaxlen; /* maxlen, not ibmtu */
24262306a36Sopenharmony_ci	kinfo->spi_ctxt = rcd->ctxt;
24362306a36Sopenharmony_ci	kinfo->spi_subctxt = subctxt_fp(fp);
24462306a36Sopenharmony_ci	kinfo->spi_sw_version = QIB_KERN_SWVERSION;
24562306a36Sopenharmony_ci	kinfo->spi_sw_version |= 1U << 31; /* QLogic-built, not kernel.org */
24662306a36Sopenharmony_ci	kinfo->spi_hw_version = dd->revision;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (master)
24962306a36Sopenharmony_ci		kinfo->spi_runtime_flags |= QIB_RUNTIME_MASTER;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	sz = (ubase_size < sizeof(*kinfo)) ? ubase_size : sizeof(*kinfo);
25262306a36Sopenharmony_ci	if (copy_to_user(ubase, kinfo, sz))
25362306a36Sopenharmony_ci		ret = -EFAULT;
25462306a36Sopenharmony_cibail:
25562306a36Sopenharmony_ci	kfree(kinfo);
25662306a36Sopenharmony_ci	return ret;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/**
26062306a36Sopenharmony_ci * qib_tid_update - update a context TID
26162306a36Sopenharmony_ci * @rcd: the context
26262306a36Sopenharmony_ci * @fp: the qib device file
26362306a36Sopenharmony_ci * @ti: the TID information
26462306a36Sopenharmony_ci *
26562306a36Sopenharmony_ci * The new implementation as of Oct 2004 is that the driver assigns
26662306a36Sopenharmony_ci * the tid and returns it to the caller.   To reduce search time, we
26762306a36Sopenharmony_ci * keep a cursor for each context, walking the shadow tid array to find
26862306a36Sopenharmony_ci * one that's not in use.
26962306a36Sopenharmony_ci *
27062306a36Sopenharmony_ci * For now, if we can't allocate the full list, we fail, although
27162306a36Sopenharmony_ci * in the long run, we'll allocate as many as we can, and the
27262306a36Sopenharmony_ci * caller will deal with that by trying the remaining pages later.
27362306a36Sopenharmony_ci * That means that when we fail, we have to mark the tids as not in
27462306a36Sopenharmony_ci * use again, in our shadow copy.
27562306a36Sopenharmony_ci *
27662306a36Sopenharmony_ci * It's up to the caller to free the tids when they are done.
27762306a36Sopenharmony_ci * We'll unlock the pages as they free them.
27862306a36Sopenharmony_ci *
27962306a36Sopenharmony_ci * Also, right now we are locking one page at a time, but since
28062306a36Sopenharmony_ci * the intended use of this routine is for a single group of
28162306a36Sopenharmony_ci * virtually contiguous pages, that should change to improve
28262306a36Sopenharmony_ci * performance.
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_cistatic int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp,
28562306a36Sopenharmony_ci			  const struct qib_tid_info *ti)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	int ret = 0, ntids;
28862306a36Sopenharmony_ci	u32 tid, ctxttid, cnt, i, tidcnt, tidoff;
28962306a36Sopenharmony_ci	u16 *tidlist;
29062306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
29162306a36Sopenharmony_ci	u64 physaddr;
29262306a36Sopenharmony_ci	unsigned long vaddr;
29362306a36Sopenharmony_ci	u64 __iomem *tidbase;
29462306a36Sopenharmony_ci	unsigned long tidmap[8];
29562306a36Sopenharmony_ci	struct page **pagep = NULL;
29662306a36Sopenharmony_ci	unsigned subctxt = subctxt_fp(fp);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (!dd->pageshadow) {
29962306a36Sopenharmony_ci		ret = -ENOMEM;
30062306a36Sopenharmony_ci		goto done;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	cnt = ti->tidcnt;
30462306a36Sopenharmony_ci	if (!cnt) {
30562306a36Sopenharmony_ci		ret = -EFAULT;
30662306a36Sopenharmony_ci		goto done;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci	ctxttid = rcd->ctxt * dd->rcvtidcnt;
30962306a36Sopenharmony_ci	if (!rcd->subctxt_cnt) {
31062306a36Sopenharmony_ci		tidcnt = dd->rcvtidcnt;
31162306a36Sopenharmony_ci		tid = rcd->tidcursor;
31262306a36Sopenharmony_ci		tidoff = 0;
31362306a36Sopenharmony_ci	} else if (!subctxt) {
31462306a36Sopenharmony_ci		tidcnt = (dd->rcvtidcnt / rcd->subctxt_cnt) +
31562306a36Sopenharmony_ci			 (dd->rcvtidcnt % rcd->subctxt_cnt);
31662306a36Sopenharmony_ci		tidoff = dd->rcvtidcnt - tidcnt;
31762306a36Sopenharmony_ci		ctxttid += tidoff;
31862306a36Sopenharmony_ci		tid = tidcursor_fp(fp);
31962306a36Sopenharmony_ci	} else {
32062306a36Sopenharmony_ci		tidcnt = dd->rcvtidcnt / rcd->subctxt_cnt;
32162306a36Sopenharmony_ci		tidoff = tidcnt * (subctxt - 1);
32262306a36Sopenharmony_ci		ctxttid += tidoff;
32362306a36Sopenharmony_ci		tid = tidcursor_fp(fp);
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci	if (cnt > tidcnt) {
32662306a36Sopenharmony_ci		/* make sure it all fits in tid_pg_list */
32762306a36Sopenharmony_ci		qib_devinfo(dd->pcidev,
32862306a36Sopenharmony_ci			"Process tried to allocate %u TIDs, only trying max (%u)\n",
32962306a36Sopenharmony_ci			cnt, tidcnt);
33062306a36Sopenharmony_ci		cnt = tidcnt;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci	pagep = (struct page **) rcd->tid_pg_list;
33362306a36Sopenharmony_ci	tidlist = (u16 *) &pagep[dd->rcvtidcnt];
33462306a36Sopenharmony_ci	pagep += tidoff;
33562306a36Sopenharmony_ci	tidlist += tidoff;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	memset(tidmap, 0, sizeof(tidmap));
33862306a36Sopenharmony_ci	/* before decrement; chip actual # */
33962306a36Sopenharmony_ci	ntids = tidcnt;
34062306a36Sopenharmony_ci	tidbase = (u64 __iomem *) (((char __iomem *) dd->kregbase) +
34162306a36Sopenharmony_ci				   dd->rcvtidbase +
34262306a36Sopenharmony_ci				   ctxttid * sizeof(*tidbase));
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/* virtual address of first page in transfer */
34562306a36Sopenharmony_ci	vaddr = ti->tidvaddr;
34662306a36Sopenharmony_ci	if (!access_ok((void __user *) vaddr,
34762306a36Sopenharmony_ci		       cnt * PAGE_SIZE)) {
34862306a36Sopenharmony_ci		ret = -EFAULT;
34962306a36Sopenharmony_ci		goto done;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci	ret = qib_get_user_pages(vaddr, cnt, pagep);
35262306a36Sopenharmony_ci	if (ret) {
35362306a36Sopenharmony_ci		/*
35462306a36Sopenharmony_ci		 * if (ret == -EBUSY)
35562306a36Sopenharmony_ci		 * We can't continue because the pagep array won't be
35662306a36Sopenharmony_ci		 * initialized. This should never happen,
35762306a36Sopenharmony_ci		 * unless perhaps the user has mpin'ed the pages
35862306a36Sopenharmony_ci		 * themselves.
35962306a36Sopenharmony_ci		 */
36062306a36Sopenharmony_ci		qib_devinfo(
36162306a36Sopenharmony_ci			dd->pcidev,
36262306a36Sopenharmony_ci			"Failed to lock addr %p, %u pages: errno %d\n",
36362306a36Sopenharmony_ci			(void *) vaddr, cnt, -ret);
36462306a36Sopenharmony_ci		goto done;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci	for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) {
36762306a36Sopenharmony_ci		dma_addr_t daddr;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci		for (; ntids--; tid++) {
37062306a36Sopenharmony_ci			if (tid == tidcnt)
37162306a36Sopenharmony_ci				tid = 0;
37262306a36Sopenharmony_ci			if (!dd->pageshadow[ctxttid + tid])
37362306a36Sopenharmony_ci				break;
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci		if (ntids < 0) {
37662306a36Sopenharmony_ci			/*
37762306a36Sopenharmony_ci			 * Oops, wrapped all the way through their TIDs,
37862306a36Sopenharmony_ci			 * and didn't have enough free; see comments at
37962306a36Sopenharmony_ci			 * start of routine
38062306a36Sopenharmony_ci			 */
38162306a36Sopenharmony_ci			i--;    /* last tidlist[i] not filled in */
38262306a36Sopenharmony_ci			ret = -ENOMEM;
38362306a36Sopenharmony_ci			break;
38462306a36Sopenharmony_ci		}
38562306a36Sopenharmony_ci		ret = qib_map_page(dd->pcidev, pagep[i], &daddr);
38662306a36Sopenharmony_ci		if (ret)
38762306a36Sopenharmony_ci			break;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		tidlist[i] = tid + tidoff;
39062306a36Sopenharmony_ci		/* we "know" system pages and TID pages are same size */
39162306a36Sopenharmony_ci		dd->pageshadow[ctxttid + tid] = pagep[i];
39262306a36Sopenharmony_ci		dd->physshadow[ctxttid + tid] = daddr;
39362306a36Sopenharmony_ci		/*
39462306a36Sopenharmony_ci		 * don't need atomic or it's overhead
39562306a36Sopenharmony_ci		 */
39662306a36Sopenharmony_ci		__set_bit(tid, tidmap);
39762306a36Sopenharmony_ci		physaddr = dd->physshadow[ctxttid + tid];
39862306a36Sopenharmony_ci		/* PERFORMANCE: below should almost certainly be cached */
39962306a36Sopenharmony_ci		dd->f_put_tid(dd, &tidbase[tid],
40062306a36Sopenharmony_ci				  RCVHQ_RCV_TYPE_EXPECTED, physaddr);
40162306a36Sopenharmony_ci		/*
40262306a36Sopenharmony_ci		 * don't check this tid in qib_ctxtshadow, since we
40362306a36Sopenharmony_ci		 * just filled it in; start with the next one.
40462306a36Sopenharmony_ci		 */
40562306a36Sopenharmony_ci		tid++;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (ret) {
40962306a36Sopenharmony_ci		u32 limit;
41062306a36Sopenharmony_cicleanup:
41162306a36Sopenharmony_ci		/* jump here if copy out of updated info failed... */
41262306a36Sopenharmony_ci		/* same code that's in qib_free_tid() */
41362306a36Sopenharmony_ci		limit = sizeof(tidmap) * BITS_PER_BYTE;
41462306a36Sopenharmony_ci		if (limit > tidcnt)
41562306a36Sopenharmony_ci			/* just in case size changes in future */
41662306a36Sopenharmony_ci			limit = tidcnt;
41762306a36Sopenharmony_ci		tid = find_first_bit((const unsigned long *)tidmap, limit);
41862306a36Sopenharmony_ci		for (; tid < limit; tid++) {
41962306a36Sopenharmony_ci			if (!test_bit(tid, tidmap))
42062306a36Sopenharmony_ci				continue;
42162306a36Sopenharmony_ci			if (dd->pageshadow[ctxttid + tid]) {
42262306a36Sopenharmony_ci				dma_addr_t phys;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci				phys = dd->physshadow[ctxttid + tid];
42562306a36Sopenharmony_ci				dd->physshadow[ctxttid + tid] = dd->tidinvalid;
42662306a36Sopenharmony_ci				/* PERFORMANCE: below should almost certainly
42762306a36Sopenharmony_ci				 * be cached
42862306a36Sopenharmony_ci				 */
42962306a36Sopenharmony_ci				dd->f_put_tid(dd, &tidbase[tid],
43062306a36Sopenharmony_ci					      RCVHQ_RCV_TYPE_EXPECTED,
43162306a36Sopenharmony_ci					      dd->tidinvalid);
43262306a36Sopenharmony_ci				dma_unmap_page(&dd->pcidev->dev, phys,
43362306a36Sopenharmony_ci					       PAGE_SIZE, DMA_FROM_DEVICE);
43462306a36Sopenharmony_ci				dd->pageshadow[ctxttid + tid] = NULL;
43562306a36Sopenharmony_ci			}
43662306a36Sopenharmony_ci		}
43762306a36Sopenharmony_ci		qib_release_user_pages(pagep, cnt);
43862306a36Sopenharmony_ci	} else {
43962306a36Sopenharmony_ci		/*
44062306a36Sopenharmony_ci		 * Copy the updated array, with qib_tid's filled in, back
44162306a36Sopenharmony_ci		 * to user.  Since we did the copy in already, this "should
44262306a36Sopenharmony_ci		 * never fail" If it does, we have to clean up...
44362306a36Sopenharmony_ci		 */
44462306a36Sopenharmony_ci		if (copy_to_user((void __user *)
44562306a36Sopenharmony_ci				 (unsigned long) ti->tidlist,
44662306a36Sopenharmony_ci				 tidlist, cnt * sizeof(*tidlist))) {
44762306a36Sopenharmony_ci			ret = -EFAULT;
44862306a36Sopenharmony_ci			goto cleanup;
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci		if (copy_to_user(u64_to_user_ptr(ti->tidmap),
45162306a36Sopenharmony_ci				 tidmap, sizeof(tidmap))) {
45262306a36Sopenharmony_ci			ret = -EFAULT;
45362306a36Sopenharmony_ci			goto cleanup;
45462306a36Sopenharmony_ci		}
45562306a36Sopenharmony_ci		if (tid == tidcnt)
45662306a36Sopenharmony_ci			tid = 0;
45762306a36Sopenharmony_ci		if (!rcd->subctxt_cnt)
45862306a36Sopenharmony_ci			rcd->tidcursor = tid;
45962306a36Sopenharmony_ci		else
46062306a36Sopenharmony_ci			tidcursor_fp(fp) = tid;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cidone:
46462306a36Sopenharmony_ci	return ret;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci/**
46862306a36Sopenharmony_ci * qib_tid_free - free a context TID
46962306a36Sopenharmony_ci * @rcd: the context
47062306a36Sopenharmony_ci * @subctxt: the subcontext
47162306a36Sopenharmony_ci * @ti: the TID info
47262306a36Sopenharmony_ci *
47362306a36Sopenharmony_ci * right now we are unlocking one page at a time, but since
47462306a36Sopenharmony_ci * the intended use of this routine is for a single group of
47562306a36Sopenharmony_ci * virtually contiguous pages, that should change to improve
47662306a36Sopenharmony_ci * performance.  We check that the TID is in range for this context
47762306a36Sopenharmony_ci * but otherwise don't check validity; if user has an error and
47862306a36Sopenharmony_ci * frees the wrong tid, it's only their own data that can thereby
47962306a36Sopenharmony_ci * be corrupted.  We do check that the TID was in use, for sanity
48062306a36Sopenharmony_ci * We always use our idea of the saved address, not the address that
48162306a36Sopenharmony_ci * they pass in to us.
48262306a36Sopenharmony_ci */
48362306a36Sopenharmony_cistatic int qib_tid_free(struct qib_ctxtdata *rcd, unsigned subctxt,
48462306a36Sopenharmony_ci			const struct qib_tid_info *ti)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	int ret = 0;
48762306a36Sopenharmony_ci	u32 tid, ctxttid, limit, tidcnt;
48862306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
48962306a36Sopenharmony_ci	u64 __iomem *tidbase;
49062306a36Sopenharmony_ci	unsigned long tidmap[8];
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	if (!dd->pageshadow) {
49362306a36Sopenharmony_ci		ret = -ENOMEM;
49462306a36Sopenharmony_ci		goto done;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (copy_from_user(tidmap, u64_to_user_ptr(ti->tidmap),
49862306a36Sopenharmony_ci			   sizeof(tidmap))) {
49962306a36Sopenharmony_ci		ret = -EFAULT;
50062306a36Sopenharmony_ci		goto done;
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	ctxttid = rcd->ctxt * dd->rcvtidcnt;
50462306a36Sopenharmony_ci	if (!rcd->subctxt_cnt)
50562306a36Sopenharmony_ci		tidcnt = dd->rcvtidcnt;
50662306a36Sopenharmony_ci	else if (!subctxt) {
50762306a36Sopenharmony_ci		tidcnt = (dd->rcvtidcnt / rcd->subctxt_cnt) +
50862306a36Sopenharmony_ci			 (dd->rcvtidcnt % rcd->subctxt_cnt);
50962306a36Sopenharmony_ci		ctxttid += dd->rcvtidcnt - tidcnt;
51062306a36Sopenharmony_ci	} else {
51162306a36Sopenharmony_ci		tidcnt = dd->rcvtidcnt / rcd->subctxt_cnt;
51262306a36Sopenharmony_ci		ctxttid += tidcnt * (subctxt - 1);
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci	tidbase = (u64 __iomem *) ((char __iomem *)(dd->kregbase) +
51562306a36Sopenharmony_ci				   dd->rcvtidbase +
51662306a36Sopenharmony_ci				   ctxttid * sizeof(*tidbase));
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	limit = sizeof(tidmap) * BITS_PER_BYTE;
51962306a36Sopenharmony_ci	if (limit > tidcnt)
52062306a36Sopenharmony_ci		/* just in case size changes in future */
52162306a36Sopenharmony_ci		limit = tidcnt;
52262306a36Sopenharmony_ci	tid = find_first_bit(tidmap, limit);
52362306a36Sopenharmony_ci	for (; tid < limit; tid++) {
52462306a36Sopenharmony_ci		/*
52562306a36Sopenharmony_ci		 * small optimization; if we detect a run of 3 or so without
52662306a36Sopenharmony_ci		 * any set, use find_first_bit again.  That's mainly to
52762306a36Sopenharmony_ci		 * accelerate the case where we wrapped, so we have some at
52862306a36Sopenharmony_ci		 * the beginning, and some at the end, and a big gap
52962306a36Sopenharmony_ci		 * in the middle.
53062306a36Sopenharmony_ci		 */
53162306a36Sopenharmony_ci		if (!test_bit(tid, tidmap))
53262306a36Sopenharmony_ci			continue;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci		if (dd->pageshadow[ctxttid + tid]) {
53562306a36Sopenharmony_ci			struct page *p;
53662306a36Sopenharmony_ci			dma_addr_t phys;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci			p = dd->pageshadow[ctxttid + tid];
53962306a36Sopenharmony_ci			dd->pageshadow[ctxttid + tid] = NULL;
54062306a36Sopenharmony_ci			phys = dd->physshadow[ctxttid + tid];
54162306a36Sopenharmony_ci			dd->physshadow[ctxttid + tid] = dd->tidinvalid;
54262306a36Sopenharmony_ci			/* PERFORMANCE: below should almost certainly be
54362306a36Sopenharmony_ci			 * cached
54462306a36Sopenharmony_ci			 */
54562306a36Sopenharmony_ci			dd->f_put_tid(dd, &tidbase[tid],
54662306a36Sopenharmony_ci				      RCVHQ_RCV_TYPE_EXPECTED, dd->tidinvalid);
54762306a36Sopenharmony_ci			dma_unmap_page(&dd->pcidev->dev, phys, PAGE_SIZE,
54862306a36Sopenharmony_ci				       DMA_FROM_DEVICE);
54962306a36Sopenharmony_ci			qib_release_user_pages(&p, 1);
55062306a36Sopenharmony_ci		}
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_cidone:
55362306a36Sopenharmony_ci	return ret;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci/**
55762306a36Sopenharmony_ci * qib_set_part_key - set a partition key
55862306a36Sopenharmony_ci * @rcd: the context
55962306a36Sopenharmony_ci * @key: the key
56062306a36Sopenharmony_ci *
56162306a36Sopenharmony_ci * We can have up to 4 active at a time (other than the default, which is
56262306a36Sopenharmony_ci * always allowed).  This is somewhat tricky, since multiple contexts may set
56362306a36Sopenharmony_ci * the same key, so we reference count them, and clean up at exit.  All 4
56462306a36Sopenharmony_ci * partition keys are packed into a single qlogic_ib register.  It's an
56562306a36Sopenharmony_ci * error for a process to set the same pkey multiple times.  We provide no
56662306a36Sopenharmony_ci * mechanism to de-allocate a pkey at this time, we may eventually need to
56762306a36Sopenharmony_ci * do that.  I've used the atomic operations, and no locking, and only make
56862306a36Sopenharmony_ci * a single pass through what's available.  This should be more than
56962306a36Sopenharmony_ci * adequate for some time. I'll think about spinlocks or the like if and as
57062306a36Sopenharmony_ci * it's necessary.
57162306a36Sopenharmony_ci */
57262306a36Sopenharmony_cistatic int qib_set_part_key(struct qib_ctxtdata *rcd, u16 key)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	struct qib_pportdata *ppd = rcd->ppd;
57562306a36Sopenharmony_ci	int i, pidx = -1;
57662306a36Sopenharmony_ci	bool any = false;
57762306a36Sopenharmony_ci	u16 lkey = key & 0x7FFF;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	if (lkey == (QIB_DEFAULT_P_KEY & 0x7FFF))
58062306a36Sopenharmony_ci		/* nothing to do; this key always valid */
58162306a36Sopenharmony_ci		return 0;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	if (!lkey)
58462306a36Sopenharmony_ci		return -EINVAL;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	/*
58762306a36Sopenharmony_ci	 * Set the full membership bit, because it has to be
58862306a36Sopenharmony_ci	 * set in the register or the packet, and it seems
58962306a36Sopenharmony_ci	 * cleaner to set in the register than to force all
59062306a36Sopenharmony_ci	 * callers to set it.
59162306a36Sopenharmony_ci	 */
59262306a36Sopenharmony_ci	key |= 0x8000;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rcd->pkeys); i++) {
59562306a36Sopenharmony_ci		if (!rcd->pkeys[i] && pidx == -1)
59662306a36Sopenharmony_ci			pidx = i;
59762306a36Sopenharmony_ci		if (rcd->pkeys[i] == key)
59862306a36Sopenharmony_ci			return -EEXIST;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci	if (pidx == -1)
60162306a36Sopenharmony_ci		return -EBUSY;
60262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) {
60362306a36Sopenharmony_ci		if (!ppd->pkeys[i]) {
60462306a36Sopenharmony_ci			any = true;
60562306a36Sopenharmony_ci			continue;
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci		if (ppd->pkeys[i] == key) {
60862306a36Sopenharmony_ci			atomic_t *pkrefs = &ppd->pkeyrefs[i];
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci			if (atomic_inc_return(pkrefs) > 1) {
61162306a36Sopenharmony_ci				rcd->pkeys[pidx] = key;
61262306a36Sopenharmony_ci				return 0;
61362306a36Sopenharmony_ci			}
61462306a36Sopenharmony_ci			/*
61562306a36Sopenharmony_ci			 * lost race, decrement count, catch below
61662306a36Sopenharmony_ci			 */
61762306a36Sopenharmony_ci			atomic_dec(pkrefs);
61862306a36Sopenharmony_ci			any = true;
61962306a36Sopenharmony_ci		}
62062306a36Sopenharmony_ci		if ((ppd->pkeys[i] & 0x7FFF) == lkey)
62162306a36Sopenharmony_ci			/*
62262306a36Sopenharmony_ci			 * It makes no sense to have both the limited and
62362306a36Sopenharmony_ci			 * full membership PKEY set at the same time since
62462306a36Sopenharmony_ci			 * the unlimited one will disable the limited one.
62562306a36Sopenharmony_ci			 */
62662306a36Sopenharmony_ci			return -EEXIST;
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci	if (!any)
62962306a36Sopenharmony_ci		return -EBUSY;
63062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) {
63162306a36Sopenharmony_ci		if (!ppd->pkeys[i] &&
63262306a36Sopenharmony_ci		    atomic_inc_return(&ppd->pkeyrefs[i]) == 1) {
63362306a36Sopenharmony_ci			rcd->pkeys[pidx] = key;
63462306a36Sopenharmony_ci			ppd->pkeys[i] = key;
63562306a36Sopenharmony_ci			(void) ppd->dd->f_set_ib_cfg(ppd, QIB_IB_CFG_PKEYS, 0);
63662306a36Sopenharmony_ci			return 0;
63762306a36Sopenharmony_ci		}
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci	return -EBUSY;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci/**
64362306a36Sopenharmony_ci * qib_manage_rcvq - manage a context's receive queue
64462306a36Sopenharmony_ci * @rcd: the context
64562306a36Sopenharmony_ci * @subctxt: the subcontext
64662306a36Sopenharmony_ci * @start_stop: action to carry out
64762306a36Sopenharmony_ci *
64862306a36Sopenharmony_ci * start_stop == 0 disables receive on the context, for use in queue
64962306a36Sopenharmony_ci * overflow conditions.  start_stop==1 re-enables, to be used to
65062306a36Sopenharmony_ci * re-init the software copy of the head register
65162306a36Sopenharmony_ci */
65262306a36Sopenharmony_cistatic int qib_manage_rcvq(struct qib_ctxtdata *rcd, unsigned subctxt,
65362306a36Sopenharmony_ci			   int start_stop)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
65662306a36Sopenharmony_ci	unsigned int rcvctrl_op;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (subctxt)
65962306a36Sopenharmony_ci		goto bail;
66062306a36Sopenharmony_ci	/* atomically clear receive enable ctxt. */
66162306a36Sopenharmony_ci	if (start_stop) {
66262306a36Sopenharmony_ci		/*
66362306a36Sopenharmony_ci		 * On enable, force in-memory copy of the tail register to
66462306a36Sopenharmony_ci		 * 0, so that protocol code doesn't have to worry about
66562306a36Sopenharmony_ci		 * whether or not the chip has yet updated the in-memory
66662306a36Sopenharmony_ci		 * copy or not on return from the system call. The chip
66762306a36Sopenharmony_ci		 * always resets it's tail register back to 0 on a
66862306a36Sopenharmony_ci		 * transition from disabled to enabled.
66962306a36Sopenharmony_ci		 */
67062306a36Sopenharmony_ci		if (rcd->rcvhdrtail_kvaddr)
67162306a36Sopenharmony_ci			qib_clear_rcvhdrtail(rcd);
67262306a36Sopenharmony_ci		rcvctrl_op = QIB_RCVCTRL_CTXT_ENB;
67362306a36Sopenharmony_ci	} else
67462306a36Sopenharmony_ci		rcvctrl_op = QIB_RCVCTRL_CTXT_DIS;
67562306a36Sopenharmony_ci	dd->f_rcvctrl(rcd->ppd, rcvctrl_op, rcd->ctxt);
67662306a36Sopenharmony_ci	/* always; new head should be equal to new tail; see above */
67762306a36Sopenharmony_cibail:
67862306a36Sopenharmony_ci	return 0;
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic void qib_clean_part_key(struct qib_ctxtdata *rcd,
68262306a36Sopenharmony_ci			       struct qib_devdata *dd)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	int i, j, pchanged = 0;
68562306a36Sopenharmony_ci	struct qib_pportdata *ppd = rcd->ppd;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rcd->pkeys); i++) {
68862306a36Sopenharmony_ci		if (!rcd->pkeys[i])
68962306a36Sopenharmony_ci			continue;
69062306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(ppd->pkeys); j++) {
69162306a36Sopenharmony_ci			/* check for match independent of the global bit */
69262306a36Sopenharmony_ci			if ((ppd->pkeys[j] & 0x7fff) !=
69362306a36Sopenharmony_ci			    (rcd->pkeys[i] & 0x7fff))
69462306a36Sopenharmony_ci				continue;
69562306a36Sopenharmony_ci			if (atomic_dec_and_test(&ppd->pkeyrefs[j])) {
69662306a36Sopenharmony_ci				ppd->pkeys[j] = 0;
69762306a36Sopenharmony_ci				pchanged++;
69862306a36Sopenharmony_ci			}
69962306a36Sopenharmony_ci			break;
70062306a36Sopenharmony_ci		}
70162306a36Sopenharmony_ci		rcd->pkeys[i] = 0;
70262306a36Sopenharmony_ci	}
70362306a36Sopenharmony_ci	if (pchanged)
70462306a36Sopenharmony_ci		(void) ppd->dd->f_set_ib_cfg(ppd, QIB_IB_CFG_PKEYS, 0);
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci/* common code for the mappings on dma_alloc_coherent mem */
70862306a36Sopenharmony_cistatic int qib_mmap_mem(struct vm_area_struct *vma, struct qib_ctxtdata *rcd,
70962306a36Sopenharmony_ci			unsigned len, void *kvaddr, u32 write_ok, char *what)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
71262306a36Sopenharmony_ci	unsigned long pfn;
71362306a36Sopenharmony_ci	int ret;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if ((vma->vm_end - vma->vm_start) > len) {
71662306a36Sopenharmony_ci		qib_devinfo(dd->pcidev,
71762306a36Sopenharmony_ci			 "FAIL on %s: len %lx > %x\n", what,
71862306a36Sopenharmony_ci			 vma->vm_end - vma->vm_start, len);
71962306a36Sopenharmony_ci		ret = -EFAULT;
72062306a36Sopenharmony_ci		goto bail;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	/*
72462306a36Sopenharmony_ci	 * shared context user code requires rcvhdrq mapped r/w, others
72562306a36Sopenharmony_ci	 * only allowed readonly mapping.
72662306a36Sopenharmony_ci	 */
72762306a36Sopenharmony_ci	if (!write_ok) {
72862306a36Sopenharmony_ci		if (vma->vm_flags & VM_WRITE) {
72962306a36Sopenharmony_ci			qib_devinfo(dd->pcidev,
73062306a36Sopenharmony_ci				 "%s must be mapped readonly\n", what);
73162306a36Sopenharmony_ci			ret = -EPERM;
73262306a36Sopenharmony_ci			goto bail;
73362306a36Sopenharmony_ci		}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		/* don't allow them to later change with mprotect */
73662306a36Sopenharmony_ci		vm_flags_clear(vma, VM_MAYWRITE);
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	pfn = virt_to_phys(kvaddr) >> PAGE_SHIFT;
74062306a36Sopenharmony_ci	ret = remap_pfn_range(vma, vma->vm_start, pfn,
74162306a36Sopenharmony_ci			      len, vma->vm_page_prot);
74262306a36Sopenharmony_ci	if (ret)
74362306a36Sopenharmony_ci		qib_devinfo(dd->pcidev,
74462306a36Sopenharmony_ci			"%s ctxt%u mmap of %lx, %x bytes failed: %d\n",
74562306a36Sopenharmony_ci			what, rcd->ctxt, pfn, len, ret);
74662306a36Sopenharmony_cibail:
74762306a36Sopenharmony_ci	return ret;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic int mmap_ureg(struct vm_area_struct *vma, struct qib_devdata *dd,
75162306a36Sopenharmony_ci		     u64 ureg)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	unsigned long phys;
75462306a36Sopenharmony_ci	unsigned long sz;
75562306a36Sopenharmony_ci	int ret;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/*
75862306a36Sopenharmony_ci	 * This is real hardware, so use io_remap.  This is the mechanism
75962306a36Sopenharmony_ci	 * for the user process to update the head registers for their ctxt
76062306a36Sopenharmony_ci	 * in the chip.
76162306a36Sopenharmony_ci	 */
76262306a36Sopenharmony_ci	sz = dd->flags & QIB_HAS_HDRSUPP ? 2 * PAGE_SIZE : PAGE_SIZE;
76362306a36Sopenharmony_ci	if ((vma->vm_end - vma->vm_start) > sz) {
76462306a36Sopenharmony_ci		qib_devinfo(dd->pcidev,
76562306a36Sopenharmony_ci			"FAIL mmap userreg: reqlen %lx > PAGE\n",
76662306a36Sopenharmony_ci			vma->vm_end - vma->vm_start);
76762306a36Sopenharmony_ci		ret = -EFAULT;
76862306a36Sopenharmony_ci	} else {
76962306a36Sopenharmony_ci		phys = dd->physaddr + ureg;
77062306a36Sopenharmony_ci		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND);
77362306a36Sopenharmony_ci		ret = io_remap_pfn_range(vma, vma->vm_start,
77462306a36Sopenharmony_ci					 phys >> PAGE_SHIFT,
77562306a36Sopenharmony_ci					 vma->vm_end - vma->vm_start,
77662306a36Sopenharmony_ci					 vma->vm_page_prot);
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci	return ret;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic int mmap_piobufs(struct vm_area_struct *vma,
78262306a36Sopenharmony_ci			struct qib_devdata *dd,
78362306a36Sopenharmony_ci			struct qib_ctxtdata *rcd,
78462306a36Sopenharmony_ci			unsigned piobufs, unsigned piocnt)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	unsigned long phys;
78762306a36Sopenharmony_ci	int ret;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	/*
79062306a36Sopenharmony_ci	 * When we map the PIO buffers in the chip, we want to map them as
79162306a36Sopenharmony_ci	 * writeonly, no read possible; unfortunately, x86 doesn't allow
79262306a36Sopenharmony_ci	 * for this in hardware, but we still prevent users from asking
79362306a36Sopenharmony_ci	 * for it.
79462306a36Sopenharmony_ci	 */
79562306a36Sopenharmony_ci	if ((vma->vm_end - vma->vm_start) > (piocnt * dd->palign)) {
79662306a36Sopenharmony_ci		qib_devinfo(dd->pcidev,
79762306a36Sopenharmony_ci			"FAIL mmap piobufs: reqlen %lx > PAGE\n",
79862306a36Sopenharmony_ci			 vma->vm_end - vma->vm_start);
79962306a36Sopenharmony_ci		ret = -EINVAL;
80062306a36Sopenharmony_ci		goto bail;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	phys = dd->physaddr + piobufs;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci#if defined(__powerpc__)
80662306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
80762306a36Sopenharmony_ci#endif
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	/*
81062306a36Sopenharmony_ci	 * don't allow them to later change to readable with mprotect (for when
81162306a36Sopenharmony_ci	 * not initially mapped readable, as is normally the case)
81262306a36Sopenharmony_ci	 */
81362306a36Sopenharmony_ci	vm_flags_mod(vma, VM_DONTCOPY | VM_DONTEXPAND, VM_MAYREAD);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	/* We used PAT if wc_cookie == 0 */
81662306a36Sopenharmony_ci	if (!dd->wc_cookie)
81762306a36Sopenharmony_ci		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	ret = io_remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT,
82062306a36Sopenharmony_ci				 vma->vm_end - vma->vm_start,
82162306a36Sopenharmony_ci				 vma->vm_page_prot);
82262306a36Sopenharmony_cibail:
82362306a36Sopenharmony_ci	return ret;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic int mmap_rcvegrbufs(struct vm_area_struct *vma,
82762306a36Sopenharmony_ci			   struct qib_ctxtdata *rcd)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
83062306a36Sopenharmony_ci	unsigned long start, size;
83162306a36Sopenharmony_ci	size_t total_size, i;
83262306a36Sopenharmony_ci	unsigned long pfn;
83362306a36Sopenharmony_ci	int ret;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	size = rcd->rcvegrbuf_size;
83662306a36Sopenharmony_ci	total_size = rcd->rcvegrbuf_chunks * size;
83762306a36Sopenharmony_ci	if ((vma->vm_end - vma->vm_start) > total_size) {
83862306a36Sopenharmony_ci		qib_devinfo(dd->pcidev,
83962306a36Sopenharmony_ci			"FAIL on egr bufs: reqlen %lx > actual %lx\n",
84062306a36Sopenharmony_ci			 vma->vm_end - vma->vm_start,
84162306a36Sopenharmony_ci			 (unsigned long) total_size);
84262306a36Sopenharmony_ci		ret = -EINVAL;
84362306a36Sopenharmony_ci		goto bail;
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	if (vma->vm_flags & VM_WRITE) {
84762306a36Sopenharmony_ci		qib_devinfo(dd->pcidev,
84862306a36Sopenharmony_ci			"Can't map eager buffers as writable (flags=%lx)\n",
84962306a36Sopenharmony_ci			vma->vm_flags);
85062306a36Sopenharmony_ci		ret = -EPERM;
85162306a36Sopenharmony_ci		goto bail;
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci	/* don't allow them to later change to writable with mprotect */
85462306a36Sopenharmony_ci	vm_flags_clear(vma, VM_MAYWRITE);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	start = vma->vm_start;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	for (i = 0; i < rcd->rcvegrbuf_chunks; i++, start += size) {
85962306a36Sopenharmony_ci		pfn = virt_to_phys(rcd->rcvegrbuf[i]) >> PAGE_SHIFT;
86062306a36Sopenharmony_ci		ret = remap_pfn_range(vma, start, pfn, size,
86162306a36Sopenharmony_ci				      vma->vm_page_prot);
86262306a36Sopenharmony_ci		if (ret < 0)
86362306a36Sopenharmony_ci			goto bail;
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci	ret = 0;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cibail:
86862306a36Sopenharmony_ci	return ret;
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci/*
87262306a36Sopenharmony_ci * qib_file_vma_fault - handle a VMA page fault.
87362306a36Sopenharmony_ci */
87462306a36Sopenharmony_cistatic vm_fault_t qib_file_vma_fault(struct vm_fault *vmf)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	struct page *page;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT));
87962306a36Sopenharmony_ci	if (!page)
88062306a36Sopenharmony_ci		return VM_FAULT_SIGBUS;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	get_page(page);
88362306a36Sopenharmony_ci	vmf->page = page;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return 0;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic const struct vm_operations_struct qib_file_vm_ops = {
88962306a36Sopenharmony_ci	.fault = qib_file_vma_fault,
89062306a36Sopenharmony_ci};
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_cistatic int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
89362306a36Sopenharmony_ci		       struct qib_ctxtdata *rcd, unsigned subctxt)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
89662306a36Sopenharmony_ci	unsigned subctxt_cnt;
89762306a36Sopenharmony_ci	unsigned long len;
89862306a36Sopenharmony_ci	void *addr;
89962306a36Sopenharmony_ci	size_t size;
90062306a36Sopenharmony_ci	int ret = 0;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	subctxt_cnt = rcd->subctxt_cnt;
90362306a36Sopenharmony_ci	size = rcd->rcvegrbuf_chunks * rcd->rcvegrbuf_size;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	/*
90662306a36Sopenharmony_ci	 * Each process has all the subctxt uregbase, rcvhdrq, and
90762306a36Sopenharmony_ci	 * rcvegrbufs mmapped - as an array for all the processes,
90862306a36Sopenharmony_ci	 * and also separately for this process.
90962306a36Sopenharmony_ci	 */
91062306a36Sopenharmony_ci	if (pgaddr == cvt_kvaddr(rcd->subctxt_uregbase)) {
91162306a36Sopenharmony_ci		addr = rcd->subctxt_uregbase;
91262306a36Sopenharmony_ci		size = PAGE_SIZE * subctxt_cnt;
91362306a36Sopenharmony_ci	} else if (pgaddr == cvt_kvaddr(rcd->subctxt_rcvhdr_base)) {
91462306a36Sopenharmony_ci		addr = rcd->subctxt_rcvhdr_base;
91562306a36Sopenharmony_ci		size = rcd->rcvhdrq_size * subctxt_cnt;
91662306a36Sopenharmony_ci	} else if (pgaddr == cvt_kvaddr(rcd->subctxt_rcvegrbuf)) {
91762306a36Sopenharmony_ci		addr = rcd->subctxt_rcvegrbuf;
91862306a36Sopenharmony_ci		size *= subctxt_cnt;
91962306a36Sopenharmony_ci	} else if (pgaddr == cvt_kvaddr(rcd->subctxt_uregbase +
92062306a36Sopenharmony_ci					PAGE_SIZE * subctxt)) {
92162306a36Sopenharmony_ci		addr = rcd->subctxt_uregbase + PAGE_SIZE * subctxt;
92262306a36Sopenharmony_ci		size = PAGE_SIZE;
92362306a36Sopenharmony_ci	} else if (pgaddr == cvt_kvaddr(rcd->subctxt_rcvhdr_base +
92462306a36Sopenharmony_ci					rcd->rcvhdrq_size * subctxt)) {
92562306a36Sopenharmony_ci		addr = rcd->subctxt_rcvhdr_base +
92662306a36Sopenharmony_ci			rcd->rcvhdrq_size * subctxt;
92762306a36Sopenharmony_ci		size = rcd->rcvhdrq_size;
92862306a36Sopenharmony_ci	} else if (pgaddr == cvt_kvaddr(&rcd->user_event_mask[subctxt])) {
92962306a36Sopenharmony_ci		addr = rcd->user_event_mask;
93062306a36Sopenharmony_ci		size = PAGE_SIZE;
93162306a36Sopenharmony_ci	} else if (pgaddr == cvt_kvaddr(rcd->subctxt_rcvegrbuf +
93262306a36Sopenharmony_ci					size * subctxt)) {
93362306a36Sopenharmony_ci		addr = rcd->subctxt_rcvegrbuf + size * subctxt;
93462306a36Sopenharmony_ci		/* rcvegrbufs are read-only on the slave */
93562306a36Sopenharmony_ci		if (vma->vm_flags & VM_WRITE) {
93662306a36Sopenharmony_ci			qib_devinfo(dd->pcidev,
93762306a36Sopenharmony_ci				 "Can't map eager buffers as writable (flags=%lx)\n",
93862306a36Sopenharmony_ci				 vma->vm_flags);
93962306a36Sopenharmony_ci			ret = -EPERM;
94062306a36Sopenharmony_ci			goto bail;
94162306a36Sopenharmony_ci		}
94262306a36Sopenharmony_ci		/*
94362306a36Sopenharmony_ci		 * Don't allow permission to later change to writable
94462306a36Sopenharmony_ci		 * with mprotect.
94562306a36Sopenharmony_ci		 */
94662306a36Sopenharmony_ci		vm_flags_clear(vma, VM_MAYWRITE);
94762306a36Sopenharmony_ci	} else
94862306a36Sopenharmony_ci		goto bail;
94962306a36Sopenharmony_ci	len = vma->vm_end - vma->vm_start;
95062306a36Sopenharmony_ci	if (len > size) {
95162306a36Sopenharmony_ci		ret = -EINVAL;
95262306a36Sopenharmony_ci		goto bail;
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
95662306a36Sopenharmony_ci	vma->vm_ops = &qib_file_vm_ops;
95762306a36Sopenharmony_ci	vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
95862306a36Sopenharmony_ci	ret = 1;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_cibail:
96162306a36Sopenharmony_ci	return ret;
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci/**
96562306a36Sopenharmony_ci * qib_mmapf - mmap various structures into user space
96662306a36Sopenharmony_ci * @fp: the file pointer
96762306a36Sopenharmony_ci * @vma: the VM area
96862306a36Sopenharmony_ci *
96962306a36Sopenharmony_ci * We use this to have a shared buffer between the kernel and the user code
97062306a36Sopenharmony_ci * for the rcvhdr queue, egr buffers, and the per-context user regs and pio
97162306a36Sopenharmony_ci * buffers in the chip.  We have the open and close entries so we can bump
97262306a36Sopenharmony_ci * the ref count and keep the driver from being unloaded while still mapped.
97362306a36Sopenharmony_ci */
97462306a36Sopenharmony_cistatic int qib_mmapf(struct file *fp, struct vm_area_struct *vma)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	struct qib_ctxtdata *rcd;
97762306a36Sopenharmony_ci	struct qib_devdata *dd;
97862306a36Sopenharmony_ci	u64 pgaddr, ureg;
97962306a36Sopenharmony_ci	unsigned piobufs, piocnt;
98062306a36Sopenharmony_ci	int ret, match = 1;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	rcd = ctxt_fp(fp);
98362306a36Sopenharmony_ci	if (!rcd || !(vma->vm_flags & VM_SHARED)) {
98462306a36Sopenharmony_ci		ret = -EINVAL;
98562306a36Sopenharmony_ci		goto bail;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci	dd = rcd->dd;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	/*
99062306a36Sopenharmony_ci	 * This is the qib_do_user_init() code, mapping the shared buffers
99162306a36Sopenharmony_ci	 * and per-context user registers into the user process. The address
99262306a36Sopenharmony_ci	 * referred to by vm_pgoff is the file offset passed via mmap().
99362306a36Sopenharmony_ci	 * For shared contexts, this is the kernel vmalloc() address of the
99462306a36Sopenharmony_ci	 * pages to share with the master.
99562306a36Sopenharmony_ci	 * For non-shared or master ctxts, this is a physical address.
99662306a36Sopenharmony_ci	 * We only do one mmap for each space mapped.
99762306a36Sopenharmony_ci	 */
99862306a36Sopenharmony_ci	pgaddr = vma->vm_pgoff << PAGE_SHIFT;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	/*
100162306a36Sopenharmony_ci	 * Check for 0 in case one of the allocations failed, but user
100262306a36Sopenharmony_ci	 * called mmap anyway.
100362306a36Sopenharmony_ci	 */
100462306a36Sopenharmony_ci	if (!pgaddr)  {
100562306a36Sopenharmony_ci		ret = -EINVAL;
100662306a36Sopenharmony_ci		goto bail;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	/*
101062306a36Sopenharmony_ci	 * Physical addresses must fit in 40 bits for our hardware.
101162306a36Sopenharmony_ci	 * Check for kernel virtual addresses first, anything else must
101262306a36Sopenharmony_ci	 * match a HW or memory address.
101362306a36Sopenharmony_ci	 */
101462306a36Sopenharmony_ci	ret = mmap_kvaddr(vma, pgaddr, rcd, subctxt_fp(fp));
101562306a36Sopenharmony_ci	if (ret) {
101662306a36Sopenharmony_ci		if (ret > 0)
101762306a36Sopenharmony_ci			ret = 0;
101862306a36Sopenharmony_ci		goto bail;
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	ureg = dd->uregbase + dd->ureg_align * rcd->ctxt;
102262306a36Sopenharmony_ci	if (!rcd->subctxt_cnt) {
102362306a36Sopenharmony_ci		/* ctxt is not shared */
102462306a36Sopenharmony_ci		piocnt = rcd->piocnt;
102562306a36Sopenharmony_ci		piobufs = rcd->piobufs;
102662306a36Sopenharmony_ci	} else if (!subctxt_fp(fp)) {
102762306a36Sopenharmony_ci		/* caller is the master */
102862306a36Sopenharmony_ci		piocnt = (rcd->piocnt / rcd->subctxt_cnt) +
102962306a36Sopenharmony_ci			 (rcd->piocnt % rcd->subctxt_cnt);
103062306a36Sopenharmony_ci		piobufs = rcd->piobufs +
103162306a36Sopenharmony_ci			dd->palign * (rcd->piocnt - piocnt);
103262306a36Sopenharmony_ci	} else {
103362306a36Sopenharmony_ci		unsigned slave = subctxt_fp(fp) - 1;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci		/* caller is a slave */
103662306a36Sopenharmony_ci		piocnt = rcd->piocnt / rcd->subctxt_cnt;
103762306a36Sopenharmony_ci		piobufs = rcd->piobufs + dd->palign * piocnt * slave;
103862306a36Sopenharmony_ci	}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if (pgaddr == ureg)
104162306a36Sopenharmony_ci		ret = mmap_ureg(vma, dd, ureg);
104262306a36Sopenharmony_ci	else if (pgaddr == piobufs)
104362306a36Sopenharmony_ci		ret = mmap_piobufs(vma, dd, rcd, piobufs, piocnt);
104462306a36Sopenharmony_ci	else if (pgaddr == dd->pioavailregs_phys)
104562306a36Sopenharmony_ci		/* in-memory copy of pioavail registers */
104662306a36Sopenharmony_ci		ret = qib_mmap_mem(vma, rcd, PAGE_SIZE,
104762306a36Sopenharmony_ci				   (void *) dd->pioavailregs_dma, 0,
104862306a36Sopenharmony_ci				   "pioavail registers");
104962306a36Sopenharmony_ci	else if (pgaddr == rcd->rcvegr_phys)
105062306a36Sopenharmony_ci		ret = mmap_rcvegrbufs(vma, rcd);
105162306a36Sopenharmony_ci	else if (pgaddr == (u64) rcd->rcvhdrq_phys)
105262306a36Sopenharmony_ci		/*
105362306a36Sopenharmony_ci		 * The rcvhdrq itself; multiple pages, contiguous
105462306a36Sopenharmony_ci		 * from an i/o perspective.  Shared contexts need
105562306a36Sopenharmony_ci		 * to map r/w, so we allow writing.
105662306a36Sopenharmony_ci		 */
105762306a36Sopenharmony_ci		ret = qib_mmap_mem(vma, rcd, rcd->rcvhdrq_size,
105862306a36Sopenharmony_ci				   rcd->rcvhdrq, 1, "rcvhdrq");
105962306a36Sopenharmony_ci	else if (pgaddr == (u64) rcd->rcvhdrqtailaddr_phys)
106062306a36Sopenharmony_ci		/* in-memory copy of rcvhdrq tail register */
106162306a36Sopenharmony_ci		ret = qib_mmap_mem(vma, rcd, PAGE_SIZE,
106262306a36Sopenharmony_ci				   rcd->rcvhdrtail_kvaddr, 0,
106362306a36Sopenharmony_ci				   "rcvhdrq tail");
106462306a36Sopenharmony_ci	else
106562306a36Sopenharmony_ci		match = 0;
106662306a36Sopenharmony_ci	if (!match)
106762306a36Sopenharmony_ci		ret = -EINVAL;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	vma->vm_private_data = NULL;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	if (ret < 0)
107262306a36Sopenharmony_ci		qib_devinfo(dd->pcidev,
107362306a36Sopenharmony_ci			 "mmap Failure %d: off %llx len %lx\n",
107462306a36Sopenharmony_ci			 -ret, (unsigned long long)pgaddr,
107562306a36Sopenharmony_ci			 vma->vm_end - vma->vm_start);
107662306a36Sopenharmony_cibail:
107762306a36Sopenharmony_ci	return ret;
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic __poll_t qib_poll_urgent(struct qib_ctxtdata *rcd,
108162306a36Sopenharmony_ci				    struct file *fp,
108262306a36Sopenharmony_ci				    struct poll_table_struct *pt)
108362306a36Sopenharmony_ci{
108462306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
108562306a36Sopenharmony_ci	__poll_t pollflag;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	poll_wait(fp, &rcd->wait, pt);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	spin_lock_irq(&dd->uctxt_lock);
109062306a36Sopenharmony_ci	if (rcd->urgent != rcd->urgent_poll) {
109162306a36Sopenharmony_ci		pollflag = EPOLLIN | EPOLLRDNORM;
109262306a36Sopenharmony_ci		rcd->urgent_poll = rcd->urgent;
109362306a36Sopenharmony_ci	} else {
109462306a36Sopenharmony_ci		pollflag = 0;
109562306a36Sopenharmony_ci		set_bit(QIB_CTXT_WAITING_URG, &rcd->flag);
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci	spin_unlock_irq(&dd->uctxt_lock);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	return pollflag;
110062306a36Sopenharmony_ci}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_cistatic __poll_t qib_poll_next(struct qib_ctxtdata *rcd,
110362306a36Sopenharmony_ci				  struct file *fp,
110462306a36Sopenharmony_ci				  struct poll_table_struct *pt)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
110762306a36Sopenharmony_ci	__poll_t pollflag;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	poll_wait(fp, &rcd->wait, pt);
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	spin_lock_irq(&dd->uctxt_lock);
111262306a36Sopenharmony_ci	if (dd->f_hdrqempty(rcd)) {
111362306a36Sopenharmony_ci		set_bit(QIB_CTXT_WAITING_RCV, &rcd->flag);
111462306a36Sopenharmony_ci		dd->f_rcvctrl(rcd->ppd, QIB_RCVCTRL_INTRAVAIL_ENB, rcd->ctxt);
111562306a36Sopenharmony_ci		pollflag = 0;
111662306a36Sopenharmony_ci	} else
111762306a36Sopenharmony_ci		pollflag = EPOLLIN | EPOLLRDNORM;
111862306a36Sopenharmony_ci	spin_unlock_irq(&dd->uctxt_lock);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	return pollflag;
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_cistatic __poll_t qib_poll(struct file *fp, struct poll_table_struct *pt)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci	struct qib_ctxtdata *rcd;
112662306a36Sopenharmony_ci	__poll_t pollflag;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	rcd = ctxt_fp(fp);
112962306a36Sopenharmony_ci	if (!rcd)
113062306a36Sopenharmony_ci		pollflag = EPOLLERR;
113162306a36Sopenharmony_ci	else if (rcd->poll_type == QIB_POLL_TYPE_URGENT)
113262306a36Sopenharmony_ci		pollflag = qib_poll_urgent(rcd, fp, pt);
113362306a36Sopenharmony_ci	else  if (rcd->poll_type == QIB_POLL_TYPE_ANYRCV)
113462306a36Sopenharmony_ci		pollflag = qib_poll_next(rcd, fp, pt);
113562306a36Sopenharmony_ci	else /* invalid */
113662306a36Sopenharmony_ci		pollflag = EPOLLERR;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return pollflag;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic void assign_ctxt_affinity(struct file *fp, struct qib_devdata *dd)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	struct qib_filedata *fd = fp->private_data;
114462306a36Sopenharmony_ci	const unsigned int weight = current->nr_cpus_allowed;
114562306a36Sopenharmony_ci	const struct cpumask *local_mask = cpumask_of_pcibus(dd->pcidev->bus);
114662306a36Sopenharmony_ci	int local_cpu;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	/*
114962306a36Sopenharmony_ci	 * If process has NOT already set it's affinity, select and
115062306a36Sopenharmony_ci	 * reserve a processor for it on the local NUMA node.
115162306a36Sopenharmony_ci	 */
115262306a36Sopenharmony_ci	if ((weight >= qib_cpulist_count) &&
115362306a36Sopenharmony_ci		(cpumask_weight(local_mask) <= qib_cpulist_count)) {
115462306a36Sopenharmony_ci		for_each_cpu(local_cpu, local_mask)
115562306a36Sopenharmony_ci			if (!test_and_set_bit(local_cpu, qib_cpulist)) {
115662306a36Sopenharmony_ci				fd->rec_cpu_num = local_cpu;
115762306a36Sopenharmony_ci				return;
115862306a36Sopenharmony_ci			}
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	/*
116262306a36Sopenharmony_ci	 * If process has NOT already set it's affinity, select and
116362306a36Sopenharmony_ci	 * reserve a processor for it, as a rendevous for all
116462306a36Sopenharmony_ci	 * users of the driver.  If they don't actually later
116562306a36Sopenharmony_ci	 * set affinity to this cpu, or set it to some other cpu,
116662306a36Sopenharmony_ci	 * it just means that sooner or later we don't recommend
116762306a36Sopenharmony_ci	 * a cpu, and let the scheduler do it's best.
116862306a36Sopenharmony_ci	 */
116962306a36Sopenharmony_ci	if (weight >= qib_cpulist_count) {
117062306a36Sopenharmony_ci		int cpu;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci		cpu = find_first_zero_bit(qib_cpulist,
117362306a36Sopenharmony_ci					  qib_cpulist_count);
117462306a36Sopenharmony_ci		if (cpu == qib_cpulist_count)
117562306a36Sopenharmony_ci			qib_dev_err(dd,
117662306a36Sopenharmony_ci			"no cpus avail for affinity PID %u\n",
117762306a36Sopenharmony_ci			current->pid);
117862306a36Sopenharmony_ci		else {
117962306a36Sopenharmony_ci			__set_bit(cpu, qib_cpulist);
118062306a36Sopenharmony_ci			fd->rec_cpu_num = cpu;
118162306a36Sopenharmony_ci		}
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci/*
118662306a36Sopenharmony_ci * Check that userland and driver are compatible for subcontexts.
118762306a36Sopenharmony_ci */
118862306a36Sopenharmony_cistatic int qib_compatible_subctxts(int user_swmajor, int user_swminor)
118962306a36Sopenharmony_ci{
119062306a36Sopenharmony_ci	/* this code is written long-hand for clarity */
119162306a36Sopenharmony_ci	if (QIB_USER_SWMAJOR != user_swmajor) {
119262306a36Sopenharmony_ci		/* no promise of compatibility if major mismatch */
119362306a36Sopenharmony_ci		return 0;
119462306a36Sopenharmony_ci	}
119562306a36Sopenharmony_ci	if (QIB_USER_SWMAJOR == 1) {
119662306a36Sopenharmony_ci		switch (QIB_USER_SWMINOR) {
119762306a36Sopenharmony_ci		case 0:
119862306a36Sopenharmony_ci		case 1:
119962306a36Sopenharmony_ci		case 2:
120062306a36Sopenharmony_ci			/* no subctxt implementation so cannot be compatible */
120162306a36Sopenharmony_ci			return 0;
120262306a36Sopenharmony_ci		case 3:
120362306a36Sopenharmony_ci			/* 3 is only compatible with itself */
120462306a36Sopenharmony_ci			return user_swminor == 3;
120562306a36Sopenharmony_ci		default:
120662306a36Sopenharmony_ci			/* >= 4 are compatible (or are expected to be) */
120762306a36Sopenharmony_ci			return user_swminor <= QIB_USER_SWMINOR;
120862306a36Sopenharmony_ci		}
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci	/* make no promises yet for future major versions */
121162306a36Sopenharmony_ci	return 0;
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_cistatic int init_subctxts(struct qib_devdata *dd,
121562306a36Sopenharmony_ci			 struct qib_ctxtdata *rcd,
121662306a36Sopenharmony_ci			 const struct qib_user_info *uinfo)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	int ret = 0;
121962306a36Sopenharmony_ci	unsigned num_subctxts;
122062306a36Sopenharmony_ci	size_t size;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	/*
122362306a36Sopenharmony_ci	 * If the user is requesting zero subctxts,
122462306a36Sopenharmony_ci	 * skip the subctxt allocation.
122562306a36Sopenharmony_ci	 */
122662306a36Sopenharmony_ci	if (uinfo->spu_subctxt_cnt <= 0)
122762306a36Sopenharmony_ci		goto bail;
122862306a36Sopenharmony_ci	num_subctxts = uinfo->spu_subctxt_cnt;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	/* Check for subctxt compatibility */
123162306a36Sopenharmony_ci	if (!qib_compatible_subctxts(uinfo->spu_userversion >> 16,
123262306a36Sopenharmony_ci		uinfo->spu_userversion & 0xffff)) {
123362306a36Sopenharmony_ci		qib_devinfo(dd->pcidev,
123462306a36Sopenharmony_ci			 "Mismatched user version (%d.%d) and driver version (%d.%d) while context sharing. Ensure that driver and library are from the same release.\n",
123562306a36Sopenharmony_ci			 (int) (uinfo->spu_userversion >> 16),
123662306a36Sopenharmony_ci			 (int) (uinfo->spu_userversion & 0xffff),
123762306a36Sopenharmony_ci			 QIB_USER_SWMAJOR, QIB_USER_SWMINOR);
123862306a36Sopenharmony_ci		goto bail;
123962306a36Sopenharmony_ci	}
124062306a36Sopenharmony_ci	if (num_subctxts > QLOGIC_IB_MAX_SUBCTXT) {
124162306a36Sopenharmony_ci		ret = -EINVAL;
124262306a36Sopenharmony_ci		goto bail;
124362306a36Sopenharmony_ci	}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	rcd->subctxt_uregbase = vmalloc_user(PAGE_SIZE * num_subctxts);
124662306a36Sopenharmony_ci	if (!rcd->subctxt_uregbase) {
124762306a36Sopenharmony_ci		ret = -ENOMEM;
124862306a36Sopenharmony_ci		goto bail;
124962306a36Sopenharmony_ci	}
125062306a36Sopenharmony_ci	/* Note: rcd->rcvhdrq_size isn't initialized yet. */
125162306a36Sopenharmony_ci	size = ALIGN(dd->rcvhdrcnt * dd->rcvhdrentsize *
125262306a36Sopenharmony_ci		     sizeof(u32), PAGE_SIZE) * num_subctxts;
125362306a36Sopenharmony_ci	rcd->subctxt_rcvhdr_base = vmalloc_user(size);
125462306a36Sopenharmony_ci	if (!rcd->subctxt_rcvhdr_base) {
125562306a36Sopenharmony_ci		ret = -ENOMEM;
125662306a36Sopenharmony_ci		goto bail_ureg;
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	rcd->subctxt_rcvegrbuf = vmalloc_user(rcd->rcvegrbuf_chunks *
126062306a36Sopenharmony_ci					      rcd->rcvegrbuf_size *
126162306a36Sopenharmony_ci					      num_subctxts);
126262306a36Sopenharmony_ci	if (!rcd->subctxt_rcvegrbuf) {
126362306a36Sopenharmony_ci		ret = -ENOMEM;
126462306a36Sopenharmony_ci		goto bail_rhdr;
126562306a36Sopenharmony_ci	}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	rcd->subctxt_cnt = uinfo->spu_subctxt_cnt;
126862306a36Sopenharmony_ci	rcd->subctxt_id = uinfo->spu_subctxt_id;
126962306a36Sopenharmony_ci	rcd->active_slaves = 1;
127062306a36Sopenharmony_ci	rcd->redirect_seq_cnt = 1;
127162306a36Sopenharmony_ci	set_bit(QIB_CTXT_MASTER_UNINIT, &rcd->flag);
127262306a36Sopenharmony_ci	goto bail;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cibail_rhdr:
127562306a36Sopenharmony_ci	vfree(rcd->subctxt_rcvhdr_base);
127662306a36Sopenharmony_cibail_ureg:
127762306a36Sopenharmony_ci	vfree(rcd->subctxt_uregbase);
127862306a36Sopenharmony_ci	rcd->subctxt_uregbase = NULL;
127962306a36Sopenharmony_cibail:
128062306a36Sopenharmony_ci	return ret;
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic int setup_ctxt(struct qib_pportdata *ppd, int ctxt,
128462306a36Sopenharmony_ci		      struct file *fp, const struct qib_user_info *uinfo)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	struct qib_filedata *fd = fp->private_data;
128762306a36Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
128862306a36Sopenharmony_ci	struct qib_ctxtdata *rcd;
128962306a36Sopenharmony_ci	void *ptmp = NULL;
129062306a36Sopenharmony_ci	int ret;
129162306a36Sopenharmony_ci	int numa_id;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	assign_ctxt_affinity(fp, dd);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	numa_id = qib_numa_aware ? ((fd->rec_cpu_num != -1) ?
129662306a36Sopenharmony_ci		cpu_to_node(fd->rec_cpu_num) :
129762306a36Sopenharmony_ci		numa_node_id()) : dd->assigned_node_id;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	rcd = qib_create_ctxtdata(ppd, ctxt, numa_id);
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	/*
130262306a36Sopenharmony_ci	 * Allocate memory for use in qib_tid_update() at open to
130362306a36Sopenharmony_ci	 * reduce cost of expected send setup per message segment
130462306a36Sopenharmony_ci	 */
130562306a36Sopenharmony_ci	if (rcd)
130662306a36Sopenharmony_ci		ptmp = kmalloc(dd->rcvtidcnt * sizeof(u16) +
130762306a36Sopenharmony_ci			       dd->rcvtidcnt * sizeof(struct page **),
130862306a36Sopenharmony_ci			       GFP_KERNEL);
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	if (!rcd || !ptmp) {
131162306a36Sopenharmony_ci		qib_dev_err(dd,
131262306a36Sopenharmony_ci			"Unable to allocate ctxtdata memory, failing open\n");
131362306a36Sopenharmony_ci		ret = -ENOMEM;
131462306a36Sopenharmony_ci		goto bailerr;
131562306a36Sopenharmony_ci	}
131662306a36Sopenharmony_ci	rcd->userversion = uinfo->spu_userversion;
131762306a36Sopenharmony_ci	ret = init_subctxts(dd, rcd, uinfo);
131862306a36Sopenharmony_ci	if (ret)
131962306a36Sopenharmony_ci		goto bailerr;
132062306a36Sopenharmony_ci	rcd->tid_pg_list = ptmp;
132162306a36Sopenharmony_ci	rcd->pid = current->pid;
132262306a36Sopenharmony_ci	init_waitqueue_head(&dd->rcd[ctxt]->wait);
132362306a36Sopenharmony_ci	get_task_comm(rcd->comm, current);
132462306a36Sopenharmony_ci	ctxt_fp(fp) = rcd;
132562306a36Sopenharmony_ci	qib_stats.sps_ctxts++;
132662306a36Sopenharmony_ci	dd->freectxts--;
132762306a36Sopenharmony_ci	ret = 0;
132862306a36Sopenharmony_ci	goto bail;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_cibailerr:
133162306a36Sopenharmony_ci	if (fd->rec_cpu_num != -1)
133262306a36Sopenharmony_ci		__clear_bit(fd->rec_cpu_num, qib_cpulist);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	dd->rcd[ctxt] = NULL;
133562306a36Sopenharmony_ci	kfree(rcd);
133662306a36Sopenharmony_ci	kfree(ptmp);
133762306a36Sopenharmony_cibail:
133862306a36Sopenharmony_ci	return ret;
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cistatic inline int usable(struct qib_pportdata *ppd)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	struct qib_devdata *dd = ppd->dd;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	return dd && (dd->flags & QIB_PRESENT) && dd->kregbase && ppd->lid &&
134662306a36Sopenharmony_ci		(ppd->lflags & QIBL_LINKACTIVE);
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci/*
135062306a36Sopenharmony_ci * Select a context on the given device, either using a requested port
135162306a36Sopenharmony_ci * or the port based on the context number.
135262306a36Sopenharmony_ci */
135362306a36Sopenharmony_cistatic int choose_port_ctxt(struct file *fp, struct qib_devdata *dd, u32 port,
135462306a36Sopenharmony_ci			    const struct qib_user_info *uinfo)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	struct qib_pportdata *ppd = NULL;
135762306a36Sopenharmony_ci	int ret, ctxt;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	if (port) {
136062306a36Sopenharmony_ci		if (!usable(dd->pport + port - 1)) {
136162306a36Sopenharmony_ci			ret = -ENETDOWN;
136262306a36Sopenharmony_ci			goto done;
136362306a36Sopenharmony_ci		} else
136462306a36Sopenharmony_ci			ppd = dd->pport + port - 1;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci	for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts && dd->rcd[ctxt];
136762306a36Sopenharmony_ci	     ctxt++)
136862306a36Sopenharmony_ci		;
136962306a36Sopenharmony_ci	if (ctxt == dd->cfgctxts) {
137062306a36Sopenharmony_ci		ret = -EBUSY;
137162306a36Sopenharmony_ci		goto done;
137262306a36Sopenharmony_ci	}
137362306a36Sopenharmony_ci	if (!ppd) {
137462306a36Sopenharmony_ci		u32 pidx = ctxt % dd->num_pports;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci		if (usable(dd->pport + pidx))
137762306a36Sopenharmony_ci			ppd = dd->pport + pidx;
137862306a36Sopenharmony_ci		else {
137962306a36Sopenharmony_ci			for (pidx = 0; pidx < dd->num_pports && !ppd;
138062306a36Sopenharmony_ci			     pidx++)
138162306a36Sopenharmony_ci				if (usable(dd->pport + pidx))
138262306a36Sopenharmony_ci					ppd = dd->pport + pidx;
138362306a36Sopenharmony_ci		}
138462306a36Sopenharmony_ci	}
138562306a36Sopenharmony_ci	ret = ppd ? setup_ctxt(ppd, ctxt, fp, uinfo) : -ENETDOWN;
138662306a36Sopenharmony_cidone:
138762306a36Sopenharmony_ci	return ret;
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic int find_free_ctxt(int unit, struct file *fp,
139162306a36Sopenharmony_ci			  const struct qib_user_info *uinfo)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	struct qib_devdata *dd = qib_lookup(unit);
139462306a36Sopenharmony_ci	int ret;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if (!dd || (uinfo->spu_port && uinfo->spu_port > dd->num_pports))
139762306a36Sopenharmony_ci		ret = -ENODEV;
139862306a36Sopenharmony_ci	else
139962306a36Sopenharmony_ci		ret = choose_port_ctxt(fp, dd, uinfo->spu_port, uinfo);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	return ret;
140262306a36Sopenharmony_ci}
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_cistatic int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo,
140562306a36Sopenharmony_ci		      unsigned alg)
140662306a36Sopenharmony_ci{
140762306a36Sopenharmony_ci	struct qib_devdata *udd = NULL;
140862306a36Sopenharmony_ci	int ret = 0, devmax, npresent, nup, ndev, dusable = 0, i;
140962306a36Sopenharmony_ci	u32 port = uinfo->spu_port, ctxt;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	devmax = qib_count_units(&npresent, &nup);
141262306a36Sopenharmony_ci	if (!npresent) {
141362306a36Sopenharmony_ci		ret = -ENXIO;
141462306a36Sopenharmony_ci		goto done;
141562306a36Sopenharmony_ci	}
141662306a36Sopenharmony_ci	if (nup == 0) {
141762306a36Sopenharmony_ci		ret = -ENETDOWN;
141862306a36Sopenharmony_ci		goto done;
141962306a36Sopenharmony_ci	}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	if (alg == QIB_PORT_ALG_ACROSS) {
142262306a36Sopenharmony_ci		unsigned inuse = ~0U;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci		/* find device (with ACTIVE ports) with fewest ctxts in use */
142562306a36Sopenharmony_ci		for (ndev = 0; ndev < devmax; ndev++) {
142662306a36Sopenharmony_ci			struct qib_devdata *dd = qib_lookup(ndev);
142762306a36Sopenharmony_ci			unsigned cused = 0, cfree = 0, pusable = 0;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci			if (!dd)
143062306a36Sopenharmony_ci				continue;
143162306a36Sopenharmony_ci			if (port && port <= dd->num_pports &&
143262306a36Sopenharmony_ci			    usable(dd->pport + port - 1))
143362306a36Sopenharmony_ci				pusable = 1;
143462306a36Sopenharmony_ci			else
143562306a36Sopenharmony_ci				for (i = 0; i < dd->num_pports; i++)
143662306a36Sopenharmony_ci					if (usable(dd->pport + i))
143762306a36Sopenharmony_ci						pusable++;
143862306a36Sopenharmony_ci			if (!pusable)
143962306a36Sopenharmony_ci				continue;
144062306a36Sopenharmony_ci			for (ctxt = dd->first_user_ctxt; ctxt < dd->cfgctxts;
144162306a36Sopenharmony_ci			     ctxt++)
144262306a36Sopenharmony_ci				if (dd->rcd[ctxt])
144362306a36Sopenharmony_ci					cused++;
144462306a36Sopenharmony_ci				else
144562306a36Sopenharmony_ci					cfree++;
144662306a36Sopenharmony_ci			if (cfree && cused < inuse) {
144762306a36Sopenharmony_ci				udd = dd;
144862306a36Sopenharmony_ci				inuse = cused;
144962306a36Sopenharmony_ci			}
145062306a36Sopenharmony_ci		}
145162306a36Sopenharmony_ci		if (udd) {
145262306a36Sopenharmony_ci			ret = choose_port_ctxt(fp, udd, port, uinfo);
145362306a36Sopenharmony_ci			goto done;
145462306a36Sopenharmony_ci		}
145562306a36Sopenharmony_ci	} else {
145662306a36Sopenharmony_ci		for (ndev = 0; ndev < devmax; ndev++) {
145762306a36Sopenharmony_ci			struct qib_devdata *dd = qib_lookup(ndev);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci			if (dd) {
146062306a36Sopenharmony_ci				ret = choose_port_ctxt(fp, dd, port, uinfo);
146162306a36Sopenharmony_ci				if (!ret)
146262306a36Sopenharmony_ci					goto done;
146362306a36Sopenharmony_ci				if (ret == -EBUSY)
146462306a36Sopenharmony_ci					dusable++;
146562306a36Sopenharmony_ci			}
146662306a36Sopenharmony_ci		}
146762306a36Sopenharmony_ci	}
146862306a36Sopenharmony_ci	ret = dusable ? -EBUSY : -ENETDOWN;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_cidone:
147162306a36Sopenharmony_ci	return ret;
147262306a36Sopenharmony_ci}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic int find_shared_ctxt(struct file *fp,
147562306a36Sopenharmony_ci			    const struct qib_user_info *uinfo)
147662306a36Sopenharmony_ci{
147762306a36Sopenharmony_ci	int devmax, ndev, i;
147862306a36Sopenharmony_ci	int ret = 0;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	devmax = qib_count_units(NULL, NULL);
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	for (ndev = 0; ndev < devmax; ndev++) {
148362306a36Sopenharmony_ci		struct qib_devdata *dd = qib_lookup(ndev);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci		/* device portion of usable() */
148662306a36Sopenharmony_ci		if (!(dd && (dd->flags & QIB_PRESENT) && dd->kregbase))
148762306a36Sopenharmony_ci			continue;
148862306a36Sopenharmony_ci		for (i = dd->first_user_ctxt; i < dd->cfgctxts; i++) {
148962306a36Sopenharmony_ci			struct qib_ctxtdata *rcd = dd->rcd[i];
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci			/* Skip ctxts which are not yet open */
149262306a36Sopenharmony_ci			if (!rcd || !rcd->cnt)
149362306a36Sopenharmony_ci				continue;
149462306a36Sopenharmony_ci			/* Skip ctxt if it doesn't match the requested one */
149562306a36Sopenharmony_ci			if (rcd->subctxt_id != uinfo->spu_subctxt_id)
149662306a36Sopenharmony_ci				continue;
149762306a36Sopenharmony_ci			/* Verify the sharing process matches the master */
149862306a36Sopenharmony_ci			if (rcd->subctxt_cnt != uinfo->spu_subctxt_cnt ||
149962306a36Sopenharmony_ci			    rcd->userversion != uinfo->spu_userversion ||
150062306a36Sopenharmony_ci			    rcd->cnt >= rcd->subctxt_cnt) {
150162306a36Sopenharmony_ci				ret = -EINVAL;
150262306a36Sopenharmony_ci				goto done;
150362306a36Sopenharmony_ci			}
150462306a36Sopenharmony_ci			ctxt_fp(fp) = rcd;
150562306a36Sopenharmony_ci			subctxt_fp(fp) = rcd->cnt++;
150662306a36Sopenharmony_ci			rcd->subpid[subctxt_fp(fp)] = current->pid;
150762306a36Sopenharmony_ci			tidcursor_fp(fp) = 0;
150862306a36Sopenharmony_ci			rcd->active_slaves |= 1 << subctxt_fp(fp);
150962306a36Sopenharmony_ci			ret = 1;
151062306a36Sopenharmony_ci			goto done;
151162306a36Sopenharmony_ci		}
151262306a36Sopenharmony_ci	}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_cidone:
151562306a36Sopenharmony_ci	return ret;
151662306a36Sopenharmony_ci}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_cistatic int qib_open(struct inode *in, struct file *fp)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	/* The real work is performed later in qib_assign_ctxt() */
152162306a36Sopenharmony_ci	fp->private_data = kzalloc(sizeof(struct qib_filedata), GFP_KERNEL);
152262306a36Sopenharmony_ci	if (fp->private_data) /* no cpu affinity by default */
152362306a36Sopenharmony_ci		((struct qib_filedata *)fp->private_data)->rec_cpu_num = -1;
152462306a36Sopenharmony_ci	return fp->private_data ? 0 : -ENOMEM;
152562306a36Sopenharmony_ci}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_cistatic int find_hca(unsigned int cpu, int *unit)
152862306a36Sopenharmony_ci{
152962306a36Sopenharmony_ci	int ret = 0, devmax, npresent, nup, ndev;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	*unit = -1;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	devmax = qib_count_units(&npresent, &nup);
153462306a36Sopenharmony_ci	if (!npresent) {
153562306a36Sopenharmony_ci		ret = -ENXIO;
153662306a36Sopenharmony_ci		goto done;
153762306a36Sopenharmony_ci	}
153862306a36Sopenharmony_ci	if (!nup) {
153962306a36Sopenharmony_ci		ret = -ENETDOWN;
154062306a36Sopenharmony_ci		goto done;
154162306a36Sopenharmony_ci	}
154262306a36Sopenharmony_ci	for (ndev = 0; ndev < devmax; ndev++) {
154362306a36Sopenharmony_ci		struct qib_devdata *dd = qib_lookup(ndev);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci		if (dd) {
154662306a36Sopenharmony_ci			if (pcibus_to_node(dd->pcidev->bus) < 0) {
154762306a36Sopenharmony_ci				ret = -EINVAL;
154862306a36Sopenharmony_ci				goto done;
154962306a36Sopenharmony_ci			}
155062306a36Sopenharmony_ci			if (cpu_to_node(cpu) ==
155162306a36Sopenharmony_ci				pcibus_to_node(dd->pcidev->bus)) {
155262306a36Sopenharmony_ci				*unit = ndev;
155362306a36Sopenharmony_ci				goto done;
155462306a36Sopenharmony_ci			}
155562306a36Sopenharmony_ci		}
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_cidone:
155862306a36Sopenharmony_ci	return ret;
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_cistatic int do_qib_user_sdma_queue_create(struct file *fp)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	struct qib_filedata *fd = fp->private_data;
156462306a36Sopenharmony_ci	struct qib_ctxtdata *rcd = fd->rcd;
156562306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	if (dd->flags & QIB_HAS_SEND_DMA) {
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci		fd->pq = qib_user_sdma_queue_create(&dd->pcidev->dev,
157062306a36Sopenharmony_ci						    dd->unit,
157162306a36Sopenharmony_ci						    rcd->ctxt,
157262306a36Sopenharmony_ci						    fd->subctxt);
157362306a36Sopenharmony_ci		if (!fd->pq)
157462306a36Sopenharmony_ci			return -ENOMEM;
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	return 0;
157862306a36Sopenharmony_ci}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci/*
158162306a36Sopenharmony_ci * Get ctxt early, so can set affinity prior to memory allocation.
158262306a36Sopenharmony_ci */
158362306a36Sopenharmony_cistatic int qib_assign_ctxt(struct file *fp, const struct qib_user_info *uinfo)
158462306a36Sopenharmony_ci{
158562306a36Sopenharmony_ci	int ret;
158662306a36Sopenharmony_ci	int i_minor;
158762306a36Sopenharmony_ci	unsigned swmajor, swminor, alg = QIB_PORT_ALG_ACROSS;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	/* Check to be sure we haven't already initialized this file */
159062306a36Sopenharmony_ci	if (ctxt_fp(fp)) {
159162306a36Sopenharmony_ci		ret = -EINVAL;
159262306a36Sopenharmony_ci		goto done;
159362306a36Sopenharmony_ci	}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	/* for now, if major version is different, bail */
159662306a36Sopenharmony_ci	swmajor = uinfo->spu_userversion >> 16;
159762306a36Sopenharmony_ci	if (swmajor != QIB_USER_SWMAJOR) {
159862306a36Sopenharmony_ci		ret = -ENODEV;
159962306a36Sopenharmony_ci		goto done;
160062306a36Sopenharmony_ci	}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	swminor = uinfo->spu_userversion & 0xffff;
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	if (swminor >= 11 && uinfo->spu_port_alg < QIB_PORT_ALG_COUNT)
160562306a36Sopenharmony_ci		alg = uinfo->spu_port_alg;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	mutex_lock(&qib_mutex);
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	if (qib_compatible_subctxts(swmajor, swminor) &&
161062306a36Sopenharmony_ci	    uinfo->spu_subctxt_cnt) {
161162306a36Sopenharmony_ci		ret = find_shared_ctxt(fp, uinfo);
161262306a36Sopenharmony_ci		if (ret > 0) {
161362306a36Sopenharmony_ci			ret = do_qib_user_sdma_queue_create(fp);
161462306a36Sopenharmony_ci			if (!ret)
161562306a36Sopenharmony_ci				assign_ctxt_affinity(fp, (ctxt_fp(fp))->dd);
161662306a36Sopenharmony_ci			goto done_ok;
161762306a36Sopenharmony_ci		}
161862306a36Sopenharmony_ci	}
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	i_minor = iminor(file_inode(fp)) - QIB_USER_MINOR_BASE;
162162306a36Sopenharmony_ci	if (i_minor)
162262306a36Sopenharmony_ci		ret = find_free_ctxt(i_minor - 1, fp, uinfo);
162362306a36Sopenharmony_ci	else {
162462306a36Sopenharmony_ci		int unit;
162562306a36Sopenharmony_ci		const unsigned int cpu = cpumask_first(current->cpus_ptr);
162662306a36Sopenharmony_ci		const unsigned int weight = current->nr_cpus_allowed;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci		if (weight == 1 && !test_bit(cpu, qib_cpulist))
162962306a36Sopenharmony_ci			if (!find_hca(cpu, &unit) && unit >= 0)
163062306a36Sopenharmony_ci				if (!find_free_ctxt(unit, fp, uinfo)) {
163162306a36Sopenharmony_ci					ret = 0;
163262306a36Sopenharmony_ci					goto done_chk_sdma;
163362306a36Sopenharmony_ci				}
163462306a36Sopenharmony_ci		ret = get_a_ctxt(fp, uinfo, alg);
163562306a36Sopenharmony_ci	}
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_cidone_chk_sdma:
163862306a36Sopenharmony_ci	if (!ret)
163962306a36Sopenharmony_ci		ret = do_qib_user_sdma_queue_create(fp);
164062306a36Sopenharmony_cidone_ok:
164162306a36Sopenharmony_ci	mutex_unlock(&qib_mutex);
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_cidone:
164462306a36Sopenharmony_ci	return ret;
164562306a36Sopenharmony_ci}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_cistatic int qib_do_user_init(struct file *fp,
164962306a36Sopenharmony_ci			    const struct qib_user_info *uinfo)
165062306a36Sopenharmony_ci{
165162306a36Sopenharmony_ci	int ret;
165262306a36Sopenharmony_ci	struct qib_ctxtdata *rcd = ctxt_fp(fp);
165362306a36Sopenharmony_ci	struct qib_devdata *dd;
165462306a36Sopenharmony_ci	unsigned uctxt;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	/* Subctxts don't need to initialize anything since master did it. */
165762306a36Sopenharmony_ci	if (subctxt_fp(fp)) {
165862306a36Sopenharmony_ci		ret = wait_event_interruptible(rcd->wait,
165962306a36Sopenharmony_ci			!test_bit(QIB_CTXT_MASTER_UNINIT, &rcd->flag));
166062306a36Sopenharmony_ci		goto bail;
166162306a36Sopenharmony_ci	}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	dd = rcd->dd;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	/* some ctxts may get extra buffers, calculate that here */
166662306a36Sopenharmony_ci	uctxt = rcd->ctxt - dd->first_user_ctxt;
166762306a36Sopenharmony_ci	if (uctxt < dd->ctxts_extrabuf) {
166862306a36Sopenharmony_ci		rcd->piocnt = dd->pbufsctxt + 1;
166962306a36Sopenharmony_ci		rcd->pio_base = rcd->piocnt * uctxt;
167062306a36Sopenharmony_ci	} else {
167162306a36Sopenharmony_ci		rcd->piocnt = dd->pbufsctxt;
167262306a36Sopenharmony_ci		rcd->pio_base = rcd->piocnt * uctxt +
167362306a36Sopenharmony_ci			dd->ctxts_extrabuf;
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	/*
167762306a36Sopenharmony_ci	 * All user buffers are 2KB buffers.  If we ever support
167862306a36Sopenharmony_ci	 * giving 4KB buffers to user processes, this will need some
167962306a36Sopenharmony_ci	 * work.  Can't use piobufbase directly, because it has
168062306a36Sopenharmony_ci	 * both 2K and 4K buffer base values.  So check and handle.
168162306a36Sopenharmony_ci	 */
168262306a36Sopenharmony_ci	if ((rcd->pio_base + rcd->piocnt) > dd->piobcnt2k) {
168362306a36Sopenharmony_ci		if (rcd->pio_base >= dd->piobcnt2k) {
168462306a36Sopenharmony_ci			qib_dev_err(dd,
168562306a36Sopenharmony_ci				    "%u:ctxt%u: no 2KB buffers available\n",
168662306a36Sopenharmony_ci				    dd->unit, rcd->ctxt);
168762306a36Sopenharmony_ci			ret = -ENOBUFS;
168862306a36Sopenharmony_ci			goto bail;
168962306a36Sopenharmony_ci		}
169062306a36Sopenharmony_ci		rcd->piocnt = dd->piobcnt2k - rcd->pio_base;
169162306a36Sopenharmony_ci		qib_dev_err(dd, "Ctxt%u: would use 4KB bufs, using %u\n",
169262306a36Sopenharmony_ci			    rcd->ctxt, rcd->piocnt);
169362306a36Sopenharmony_ci	}
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	rcd->piobufs = dd->pio2k_bufbase + rcd->pio_base * dd->palign;
169662306a36Sopenharmony_ci	qib_chg_pioavailkernel(dd, rcd->pio_base, rcd->piocnt,
169762306a36Sopenharmony_ci			       TXCHK_CHG_TYPE_USER, rcd);
169862306a36Sopenharmony_ci	/*
169962306a36Sopenharmony_ci	 * try to ensure that processes start up with consistent avail update
170062306a36Sopenharmony_ci	 * for their own range, at least.   If system very quiet, it might
170162306a36Sopenharmony_ci	 * have the in-memory copy out of date at startup for this range of
170262306a36Sopenharmony_ci	 * buffers, when a context gets re-used.  Do after the chg_pioavail
170362306a36Sopenharmony_ci	 * and before the rest of setup, so it's "almost certain" the dma
170462306a36Sopenharmony_ci	 * will have occurred (can't 100% guarantee, but should be many
170562306a36Sopenharmony_ci	 * decimals of 9s, with this ordering), given how much else happens
170662306a36Sopenharmony_ci	 * after this.
170762306a36Sopenharmony_ci	 */
170862306a36Sopenharmony_ci	dd->f_sendctrl(dd->pport, QIB_SENDCTRL_AVAIL_BLIP);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	/*
171162306a36Sopenharmony_ci	 * Now allocate the rcvhdr Q and eager TIDs; skip the TID
171262306a36Sopenharmony_ci	 * array for time being.  If rcd->ctxt > chip-supported,
171362306a36Sopenharmony_ci	 * we need to do extra stuff here to handle by handling overflow
171462306a36Sopenharmony_ci	 * through ctxt 0, someday
171562306a36Sopenharmony_ci	 */
171662306a36Sopenharmony_ci	ret = qib_create_rcvhdrq(dd, rcd);
171762306a36Sopenharmony_ci	if (!ret)
171862306a36Sopenharmony_ci		ret = qib_setup_eagerbufs(rcd);
171962306a36Sopenharmony_ci	if (ret)
172062306a36Sopenharmony_ci		goto bail_pio;
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	rcd->tidcursor = 0; /* start at beginning after open */
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	/* initialize poll variables... */
172562306a36Sopenharmony_ci	rcd->urgent = 0;
172662306a36Sopenharmony_ci	rcd->urgent_poll = 0;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	/*
172962306a36Sopenharmony_ci	 * Now enable the ctxt for receive.
173062306a36Sopenharmony_ci	 * For chips that are set to DMA the tail register to memory
173162306a36Sopenharmony_ci	 * when they change (and when the update bit transitions from
173262306a36Sopenharmony_ci	 * 0 to 1.  So for those chips, we turn it off and then back on.
173362306a36Sopenharmony_ci	 * This will (very briefly) affect any other open ctxts, but the
173462306a36Sopenharmony_ci	 * duration is very short, and therefore isn't an issue.  We
173562306a36Sopenharmony_ci	 * explicitly set the in-memory tail copy to 0 beforehand, so we
173662306a36Sopenharmony_ci	 * don't have to wait to be sure the DMA update has happened
173762306a36Sopenharmony_ci	 * (chip resets head/tail to 0 on transition to enable).
173862306a36Sopenharmony_ci	 */
173962306a36Sopenharmony_ci	if (rcd->rcvhdrtail_kvaddr)
174062306a36Sopenharmony_ci		qib_clear_rcvhdrtail(rcd);
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	dd->f_rcvctrl(rcd->ppd, QIB_RCVCTRL_CTXT_ENB | QIB_RCVCTRL_TIDFLOW_ENB,
174362306a36Sopenharmony_ci		      rcd->ctxt);
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	/* Notify any waiting slaves */
174662306a36Sopenharmony_ci	if (rcd->subctxt_cnt) {
174762306a36Sopenharmony_ci		clear_bit(QIB_CTXT_MASTER_UNINIT, &rcd->flag);
174862306a36Sopenharmony_ci		wake_up(&rcd->wait);
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci	return 0;
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_cibail_pio:
175362306a36Sopenharmony_ci	qib_chg_pioavailkernel(dd, rcd->pio_base, rcd->piocnt,
175462306a36Sopenharmony_ci			       TXCHK_CHG_TYPE_KERN, rcd);
175562306a36Sopenharmony_cibail:
175662306a36Sopenharmony_ci	return ret;
175762306a36Sopenharmony_ci}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci/**
176062306a36Sopenharmony_ci * unlock_expected_tids - unlock any expected TID entries context still had
176162306a36Sopenharmony_ci * in use
176262306a36Sopenharmony_ci * @rcd: ctxt
176362306a36Sopenharmony_ci *
176462306a36Sopenharmony_ci * We don't actually update the chip here, because we do a bulk update
176562306a36Sopenharmony_ci * below, using f_clear_tids.
176662306a36Sopenharmony_ci */
176762306a36Sopenharmony_cistatic void unlock_expected_tids(struct qib_ctxtdata *rcd)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	struct qib_devdata *dd = rcd->dd;
177062306a36Sopenharmony_ci	int ctxt_tidbase = rcd->ctxt * dd->rcvtidcnt;
177162306a36Sopenharmony_ci	int i, maxtid = ctxt_tidbase + dd->rcvtidcnt;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	for (i = ctxt_tidbase; i < maxtid; i++) {
177462306a36Sopenharmony_ci		struct page *p = dd->pageshadow[i];
177562306a36Sopenharmony_ci		dma_addr_t phys;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci		if (!p)
177862306a36Sopenharmony_ci			continue;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci		phys = dd->physshadow[i];
178162306a36Sopenharmony_ci		dd->physshadow[i] = dd->tidinvalid;
178262306a36Sopenharmony_ci		dd->pageshadow[i] = NULL;
178362306a36Sopenharmony_ci		dma_unmap_page(&dd->pcidev->dev, phys, PAGE_SIZE,
178462306a36Sopenharmony_ci			       DMA_FROM_DEVICE);
178562306a36Sopenharmony_ci		qib_release_user_pages(&p, 1);
178662306a36Sopenharmony_ci	}
178762306a36Sopenharmony_ci}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_cistatic int qib_close(struct inode *in, struct file *fp)
179062306a36Sopenharmony_ci{
179162306a36Sopenharmony_ci	struct qib_filedata *fd;
179262306a36Sopenharmony_ci	struct qib_ctxtdata *rcd;
179362306a36Sopenharmony_ci	struct qib_devdata *dd;
179462306a36Sopenharmony_ci	unsigned long flags;
179562306a36Sopenharmony_ci	unsigned ctxt;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	mutex_lock(&qib_mutex);
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	fd = fp->private_data;
180062306a36Sopenharmony_ci	fp->private_data = NULL;
180162306a36Sopenharmony_ci	rcd = fd->rcd;
180262306a36Sopenharmony_ci	if (!rcd) {
180362306a36Sopenharmony_ci		mutex_unlock(&qib_mutex);
180462306a36Sopenharmony_ci		goto bail;
180562306a36Sopenharmony_ci	}
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	dd = rcd->dd;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	/* ensure all pio buffer writes in progress are flushed */
181062306a36Sopenharmony_ci	qib_flush_wc();
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	/* drain user sdma queue */
181362306a36Sopenharmony_ci	if (fd->pq) {
181462306a36Sopenharmony_ci		qib_user_sdma_queue_drain(rcd->ppd, fd->pq);
181562306a36Sopenharmony_ci		qib_user_sdma_queue_destroy(fd->pq);
181662306a36Sopenharmony_ci	}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	if (fd->rec_cpu_num != -1)
181962306a36Sopenharmony_ci		__clear_bit(fd->rec_cpu_num, qib_cpulist);
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	if (--rcd->cnt) {
182262306a36Sopenharmony_ci		/*
182362306a36Sopenharmony_ci		 * XXX If the master closes the context before the slave(s),
182462306a36Sopenharmony_ci		 * revoke the mmap for the eager receive queue so
182562306a36Sopenharmony_ci		 * the slave(s) don't wait for receive data forever.
182662306a36Sopenharmony_ci		 */
182762306a36Sopenharmony_ci		rcd->active_slaves &= ~(1 << fd->subctxt);
182862306a36Sopenharmony_ci		rcd->subpid[fd->subctxt] = 0;
182962306a36Sopenharmony_ci		mutex_unlock(&qib_mutex);
183062306a36Sopenharmony_ci		goto bail;
183162306a36Sopenharmony_ci	}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	/* early; no interrupt users after this */
183462306a36Sopenharmony_ci	spin_lock_irqsave(&dd->uctxt_lock, flags);
183562306a36Sopenharmony_ci	ctxt = rcd->ctxt;
183662306a36Sopenharmony_ci	dd->rcd[ctxt] = NULL;
183762306a36Sopenharmony_ci	rcd->pid = 0;
183862306a36Sopenharmony_ci	spin_unlock_irqrestore(&dd->uctxt_lock, flags);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	if (rcd->rcvwait_to || rcd->piowait_to ||
184162306a36Sopenharmony_ci	    rcd->rcvnowait || rcd->pionowait) {
184262306a36Sopenharmony_ci		rcd->rcvwait_to = 0;
184362306a36Sopenharmony_ci		rcd->piowait_to = 0;
184462306a36Sopenharmony_ci		rcd->rcvnowait = 0;
184562306a36Sopenharmony_ci		rcd->pionowait = 0;
184662306a36Sopenharmony_ci	}
184762306a36Sopenharmony_ci	if (rcd->flag)
184862306a36Sopenharmony_ci		rcd->flag = 0;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	if (dd->kregbase) {
185162306a36Sopenharmony_ci		/* atomically clear receive enable ctxt and intr avail. */
185262306a36Sopenharmony_ci		dd->f_rcvctrl(rcd->ppd, QIB_RCVCTRL_CTXT_DIS |
185362306a36Sopenharmony_ci				  QIB_RCVCTRL_INTRAVAIL_DIS, ctxt);
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci		/* clean up the pkeys for this ctxt user */
185662306a36Sopenharmony_ci		qib_clean_part_key(rcd, dd);
185762306a36Sopenharmony_ci		qib_disarm_piobufs(dd, rcd->pio_base, rcd->piocnt);
185862306a36Sopenharmony_ci		qib_chg_pioavailkernel(dd, rcd->pio_base,
185962306a36Sopenharmony_ci				       rcd->piocnt, TXCHK_CHG_TYPE_KERN, NULL);
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci		dd->f_clear_tids(dd, rcd);
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci		if (dd->pageshadow)
186462306a36Sopenharmony_ci			unlock_expected_tids(rcd);
186562306a36Sopenharmony_ci		qib_stats.sps_ctxts--;
186662306a36Sopenharmony_ci		dd->freectxts++;
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	mutex_unlock(&qib_mutex);
187062306a36Sopenharmony_ci	qib_free_ctxtdata(dd, rcd); /* after releasing the mutex */
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_cibail:
187362306a36Sopenharmony_ci	kfree(fd);
187462306a36Sopenharmony_ci	return 0;
187562306a36Sopenharmony_ci}
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_cistatic int qib_ctxt_info(struct file *fp, struct qib_ctxt_info __user *uinfo)
187862306a36Sopenharmony_ci{
187962306a36Sopenharmony_ci	struct qib_ctxt_info info;
188062306a36Sopenharmony_ci	int ret;
188162306a36Sopenharmony_ci	size_t sz;
188262306a36Sopenharmony_ci	struct qib_ctxtdata *rcd = ctxt_fp(fp);
188362306a36Sopenharmony_ci	struct qib_filedata *fd;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	fd = fp->private_data;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	info.num_active = qib_count_active_units();
188862306a36Sopenharmony_ci	info.unit = rcd->dd->unit;
188962306a36Sopenharmony_ci	info.port = rcd->ppd->port;
189062306a36Sopenharmony_ci	info.ctxt = rcd->ctxt;
189162306a36Sopenharmony_ci	info.subctxt =  subctxt_fp(fp);
189262306a36Sopenharmony_ci	/* Number of user ctxts available for this device. */
189362306a36Sopenharmony_ci	info.num_ctxts = rcd->dd->cfgctxts - rcd->dd->first_user_ctxt;
189462306a36Sopenharmony_ci	info.num_subctxts = rcd->subctxt_cnt;
189562306a36Sopenharmony_ci	info.rec_cpu = fd->rec_cpu_num;
189662306a36Sopenharmony_ci	sz = sizeof(info);
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	if (copy_to_user(uinfo, &info, sz)) {
189962306a36Sopenharmony_ci		ret = -EFAULT;
190062306a36Sopenharmony_ci		goto bail;
190162306a36Sopenharmony_ci	}
190262306a36Sopenharmony_ci	ret = 0;
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_cibail:
190562306a36Sopenharmony_ci	return ret;
190662306a36Sopenharmony_ci}
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_cistatic int qib_sdma_get_inflight(struct qib_user_sdma_queue *pq,
190962306a36Sopenharmony_ci				 u32 __user *inflightp)
191062306a36Sopenharmony_ci{
191162306a36Sopenharmony_ci	const u32 val = qib_user_sdma_inflight_counter(pq);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (put_user(val, inflightp))
191462306a36Sopenharmony_ci		return -EFAULT;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	return 0;
191762306a36Sopenharmony_ci}
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_cistatic int qib_sdma_get_complete(struct qib_pportdata *ppd,
192062306a36Sopenharmony_ci				 struct qib_user_sdma_queue *pq,
192162306a36Sopenharmony_ci				 u32 __user *completep)
192262306a36Sopenharmony_ci{
192362306a36Sopenharmony_ci	u32 val;
192462306a36Sopenharmony_ci	int err;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	if (!pq)
192762306a36Sopenharmony_ci		return -EINVAL;
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	err = qib_user_sdma_make_progress(ppd, pq);
193062306a36Sopenharmony_ci	if (err < 0)
193162306a36Sopenharmony_ci		return err;
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	val = qib_user_sdma_complete_counter(pq);
193462306a36Sopenharmony_ci	if (put_user(val, completep))
193562306a36Sopenharmony_ci		return -EFAULT;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	return 0;
193862306a36Sopenharmony_ci}
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_cistatic int disarm_req_delay(struct qib_ctxtdata *rcd)
194162306a36Sopenharmony_ci{
194262306a36Sopenharmony_ci	int ret = 0;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	if (!usable(rcd->ppd)) {
194562306a36Sopenharmony_ci		int i;
194662306a36Sopenharmony_ci		/*
194762306a36Sopenharmony_ci		 * if link is down, or otherwise not usable, delay
194862306a36Sopenharmony_ci		 * the caller up to 30 seconds, so we don't thrash
194962306a36Sopenharmony_ci		 * in trying to get the chip back to ACTIVE, and
195062306a36Sopenharmony_ci		 * set flag so they make the call again.
195162306a36Sopenharmony_ci		 */
195262306a36Sopenharmony_ci		if (rcd->user_event_mask) {
195362306a36Sopenharmony_ci			/*
195462306a36Sopenharmony_ci			 * subctxt_cnt is 0 if not shared, so do base
195562306a36Sopenharmony_ci			 * separately, first, then remaining subctxt, if any
195662306a36Sopenharmony_ci			 */
195762306a36Sopenharmony_ci			set_bit(_QIB_EVENT_DISARM_BUFS_BIT,
195862306a36Sopenharmony_ci				&rcd->user_event_mask[0]);
195962306a36Sopenharmony_ci			for (i = 1; i < rcd->subctxt_cnt; i++)
196062306a36Sopenharmony_ci				set_bit(_QIB_EVENT_DISARM_BUFS_BIT,
196162306a36Sopenharmony_ci					&rcd->user_event_mask[i]);
196262306a36Sopenharmony_ci		}
196362306a36Sopenharmony_ci		for (i = 0; !usable(rcd->ppd) && i < 300; i++)
196462306a36Sopenharmony_ci			msleep(100);
196562306a36Sopenharmony_ci		ret = -ENETDOWN;
196662306a36Sopenharmony_ci	}
196762306a36Sopenharmony_ci	return ret;
196862306a36Sopenharmony_ci}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci/*
197162306a36Sopenharmony_ci * Find all user contexts in use, and set the specified bit in their
197262306a36Sopenharmony_ci * event mask.
197362306a36Sopenharmony_ci * See also find_ctxt() for a similar use, that is specific to send buffers.
197462306a36Sopenharmony_ci */
197562306a36Sopenharmony_ciint qib_set_uevent_bits(struct qib_pportdata *ppd, const int evtbit)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	struct qib_ctxtdata *rcd;
197862306a36Sopenharmony_ci	unsigned ctxt;
197962306a36Sopenharmony_ci	int ret = 0;
198062306a36Sopenharmony_ci	unsigned long flags;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	spin_lock_irqsave(&ppd->dd->uctxt_lock, flags);
198362306a36Sopenharmony_ci	for (ctxt = ppd->dd->first_user_ctxt; ctxt < ppd->dd->cfgctxts;
198462306a36Sopenharmony_ci	     ctxt++) {
198562306a36Sopenharmony_ci		rcd = ppd->dd->rcd[ctxt];
198662306a36Sopenharmony_ci		if (!rcd)
198762306a36Sopenharmony_ci			continue;
198862306a36Sopenharmony_ci		if (rcd->user_event_mask) {
198962306a36Sopenharmony_ci			int i;
199062306a36Sopenharmony_ci			/*
199162306a36Sopenharmony_ci			 * subctxt_cnt is 0 if not shared, so do base
199262306a36Sopenharmony_ci			 * separately, first, then remaining subctxt, if any
199362306a36Sopenharmony_ci			 */
199462306a36Sopenharmony_ci			set_bit(evtbit, &rcd->user_event_mask[0]);
199562306a36Sopenharmony_ci			for (i = 1; i < rcd->subctxt_cnt; i++)
199662306a36Sopenharmony_ci				set_bit(evtbit, &rcd->user_event_mask[i]);
199762306a36Sopenharmony_ci		}
199862306a36Sopenharmony_ci		ret = 1;
199962306a36Sopenharmony_ci		break;
200062306a36Sopenharmony_ci	}
200162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ppd->dd->uctxt_lock, flags);
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	return ret;
200462306a36Sopenharmony_ci}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci/*
200762306a36Sopenharmony_ci * clear the event notifier events for this context.
200862306a36Sopenharmony_ci * For the DISARM_BUFS case, we also take action (this obsoletes
200962306a36Sopenharmony_ci * the older QIB_CMD_DISARM_BUFS, but we keep it for backwards
201062306a36Sopenharmony_ci * compatibility.
201162306a36Sopenharmony_ci * Other bits don't currently require actions, just atomically clear.
201262306a36Sopenharmony_ci * User process then performs actions appropriate to bit having been
201362306a36Sopenharmony_ci * set, if desired, and checks again in future.
201462306a36Sopenharmony_ci */
201562306a36Sopenharmony_cistatic int qib_user_event_ack(struct qib_ctxtdata *rcd, int subctxt,
201662306a36Sopenharmony_ci			      unsigned long events)
201762306a36Sopenharmony_ci{
201862306a36Sopenharmony_ci	int ret = 0, i;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	for (i = 0; i <= _QIB_MAX_EVENT_BIT; i++) {
202162306a36Sopenharmony_ci		if (!test_bit(i, &events))
202262306a36Sopenharmony_ci			continue;
202362306a36Sopenharmony_ci		if (i == _QIB_EVENT_DISARM_BUFS_BIT) {
202462306a36Sopenharmony_ci			(void)qib_disarm_piobufs_ifneeded(rcd);
202562306a36Sopenharmony_ci			ret = disarm_req_delay(rcd);
202662306a36Sopenharmony_ci		} else
202762306a36Sopenharmony_ci			clear_bit(i, &rcd->user_event_mask[subctxt]);
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci	return ret;
203062306a36Sopenharmony_ci}
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_cistatic ssize_t qib_write(struct file *fp, const char __user *data,
203362306a36Sopenharmony_ci			 size_t count, loff_t *off)
203462306a36Sopenharmony_ci{
203562306a36Sopenharmony_ci	const struct qib_cmd __user *ucmd;
203662306a36Sopenharmony_ci	struct qib_ctxtdata *rcd;
203762306a36Sopenharmony_ci	const void __user *src;
203862306a36Sopenharmony_ci	size_t consumed, copy = 0;
203962306a36Sopenharmony_ci	struct qib_cmd cmd;
204062306a36Sopenharmony_ci	ssize_t ret = 0;
204162306a36Sopenharmony_ci	void *dest;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	if (!ib_safe_file_access(fp)) {
204462306a36Sopenharmony_ci		pr_err_once("qib_write: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n",
204562306a36Sopenharmony_ci			    task_tgid_vnr(current), current->comm);
204662306a36Sopenharmony_ci		return -EACCES;
204762306a36Sopenharmony_ci	}
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	if (count < sizeof(cmd.type)) {
205062306a36Sopenharmony_ci		ret = -EINVAL;
205162306a36Sopenharmony_ci		goto bail;
205262306a36Sopenharmony_ci	}
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	ucmd = (const struct qib_cmd __user *) data;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	if (copy_from_user(&cmd.type, &ucmd->type, sizeof(cmd.type))) {
205762306a36Sopenharmony_ci		ret = -EFAULT;
205862306a36Sopenharmony_ci		goto bail;
205962306a36Sopenharmony_ci	}
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	consumed = sizeof(cmd.type);
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	switch (cmd.type) {
206462306a36Sopenharmony_ci	case QIB_CMD_ASSIGN_CTXT:
206562306a36Sopenharmony_ci	case QIB_CMD_USER_INIT:
206662306a36Sopenharmony_ci		copy = sizeof(cmd.cmd.user_info);
206762306a36Sopenharmony_ci		dest = &cmd.cmd.user_info;
206862306a36Sopenharmony_ci		src = &ucmd->cmd.user_info;
206962306a36Sopenharmony_ci		break;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	case QIB_CMD_RECV_CTRL:
207262306a36Sopenharmony_ci		copy = sizeof(cmd.cmd.recv_ctrl);
207362306a36Sopenharmony_ci		dest = &cmd.cmd.recv_ctrl;
207462306a36Sopenharmony_ci		src = &ucmd->cmd.recv_ctrl;
207562306a36Sopenharmony_ci		break;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	case QIB_CMD_CTXT_INFO:
207862306a36Sopenharmony_ci		copy = sizeof(cmd.cmd.ctxt_info);
207962306a36Sopenharmony_ci		dest = &cmd.cmd.ctxt_info;
208062306a36Sopenharmony_ci		src = &ucmd->cmd.ctxt_info;
208162306a36Sopenharmony_ci		break;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	case QIB_CMD_TID_UPDATE:
208462306a36Sopenharmony_ci	case QIB_CMD_TID_FREE:
208562306a36Sopenharmony_ci		copy = sizeof(cmd.cmd.tid_info);
208662306a36Sopenharmony_ci		dest = &cmd.cmd.tid_info;
208762306a36Sopenharmony_ci		src = &ucmd->cmd.tid_info;
208862306a36Sopenharmony_ci		break;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	case QIB_CMD_SET_PART_KEY:
209162306a36Sopenharmony_ci		copy = sizeof(cmd.cmd.part_key);
209262306a36Sopenharmony_ci		dest = &cmd.cmd.part_key;
209362306a36Sopenharmony_ci		src = &ucmd->cmd.part_key;
209462306a36Sopenharmony_ci		break;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	case QIB_CMD_DISARM_BUFS:
209762306a36Sopenharmony_ci	case QIB_CMD_PIOAVAILUPD: /* force an update of PIOAvail reg */
209862306a36Sopenharmony_ci		copy = 0;
209962306a36Sopenharmony_ci		src = NULL;
210062306a36Sopenharmony_ci		dest = NULL;
210162306a36Sopenharmony_ci		break;
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	case QIB_CMD_POLL_TYPE:
210462306a36Sopenharmony_ci		copy = sizeof(cmd.cmd.poll_type);
210562306a36Sopenharmony_ci		dest = &cmd.cmd.poll_type;
210662306a36Sopenharmony_ci		src = &ucmd->cmd.poll_type;
210762306a36Sopenharmony_ci		break;
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	case QIB_CMD_ARMLAUNCH_CTRL:
211062306a36Sopenharmony_ci		copy = sizeof(cmd.cmd.armlaunch_ctrl);
211162306a36Sopenharmony_ci		dest = &cmd.cmd.armlaunch_ctrl;
211262306a36Sopenharmony_ci		src = &ucmd->cmd.armlaunch_ctrl;
211362306a36Sopenharmony_ci		break;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	case QIB_CMD_SDMA_INFLIGHT:
211662306a36Sopenharmony_ci		copy = sizeof(cmd.cmd.sdma_inflight);
211762306a36Sopenharmony_ci		dest = &cmd.cmd.sdma_inflight;
211862306a36Sopenharmony_ci		src = &ucmd->cmd.sdma_inflight;
211962306a36Sopenharmony_ci		break;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	case QIB_CMD_SDMA_COMPLETE:
212262306a36Sopenharmony_ci		copy = sizeof(cmd.cmd.sdma_complete);
212362306a36Sopenharmony_ci		dest = &cmd.cmd.sdma_complete;
212462306a36Sopenharmony_ci		src = &ucmd->cmd.sdma_complete;
212562306a36Sopenharmony_ci		break;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	case QIB_CMD_ACK_EVENT:
212862306a36Sopenharmony_ci		copy = sizeof(cmd.cmd.event_mask);
212962306a36Sopenharmony_ci		dest = &cmd.cmd.event_mask;
213062306a36Sopenharmony_ci		src = &ucmd->cmd.event_mask;
213162306a36Sopenharmony_ci		break;
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	default:
213462306a36Sopenharmony_ci		ret = -EINVAL;
213562306a36Sopenharmony_ci		goto bail;
213662306a36Sopenharmony_ci	}
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	if (copy) {
213962306a36Sopenharmony_ci		if ((count - consumed) < copy) {
214062306a36Sopenharmony_ci			ret = -EINVAL;
214162306a36Sopenharmony_ci			goto bail;
214262306a36Sopenharmony_ci		}
214362306a36Sopenharmony_ci		if (copy_from_user(dest, src, copy)) {
214462306a36Sopenharmony_ci			ret = -EFAULT;
214562306a36Sopenharmony_ci			goto bail;
214662306a36Sopenharmony_ci		}
214762306a36Sopenharmony_ci		consumed += copy;
214862306a36Sopenharmony_ci	}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	rcd = ctxt_fp(fp);
215162306a36Sopenharmony_ci	if (!rcd && cmd.type != QIB_CMD_ASSIGN_CTXT) {
215262306a36Sopenharmony_ci		ret = -EINVAL;
215362306a36Sopenharmony_ci		goto bail;
215462306a36Sopenharmony_ci	}
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	switch (cmd.type) {
215762306a36Sopenharmony_ci	case QIB_CMD_ASSIGN_CTXT:
215862306a36Sopenharmony_ci		if (rcd) {
215962306a36Sopenharmony_ci			ret = -EINVAL;
216062306a36Sopenharmony_ci			goto bail;
216162306a36Sopenharmony_ci		}
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci		ret = qib_assign_ctxt(fp, &cmd.cmd.user_info);
216462306a36Sopenharmony_ci		if (ret)
216562306a36Sopenharmony_ci			goto bail;
216662306a36Sopenharmony_ci		break;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	case QIB_CMD_USER_INIT:
216962306a36Sopenharmony_ci		ret = qib_do_user_init(fp, &cmd.cmd.user_info);
217062306a36Sopenharmony_ci		if (ret)
217162306a36Sopenharmony_ci			goto bail;
217262306a36Sopenharmony_ci		ret = qib_get_base_info(fp, u64_to_user_ptr(
217362306a36Sopenharmony_ci					  cmd.cmd.user_info.spu_base_info),
217462306a36Sopenharmony_ci					cmd.cmd.user_info.spu_base_info_size);
217562306a36Sopenharmony_ci		break;
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	case QIB_CMD_RECV_CTRL:
217862306a36Sopenharmony_ci		ret = qib_manage_rcvq(rcd, subctxt_fp(fp), cmd.cmd.recv_ctrl);
217962306a36Sopenharmony_ci		break;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	case QIB_CMD_CTXT_INFO:
218262306a36Sopenharmony_ci		ret = qib_ctxt_info(fp, (struct qib_ctxt_info __user *)
218362306a36Sopenharmony_ci				    (unsigned long) cmd.cmd.ctxt_info);
218462306a36Sopenharmony_ci		break;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	case QIB_CMD_TID_UPDATE:
218762306a36Sopenharmony_ci		ret = qib_tid_update(rcd, fp, &cmd.cmd.tid_info);
218862306a36Sopenharmony_ci		break;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	case QIB_CMD_TID_FREE:
219162306a36Sopenharmony_ci		ret = qib_tid_free(rcd, subctxt_fp(fp), &cmd.cmd.tid_info);
219262306a36Sopenharmony_ci		break;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	case QIB_CMD_SET_PART_KEY:
219562306a36Sopenharmony_ci		ret = qib_set_part_key(rcd, cmd.cmd.part_key);
219662306a36Sopenharmony_ci		break;
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	case QIB_CMD_DISARM_BUFS:
219962306a36Sopenharmony_ci		(void)qib_disarm_piobufs_ifneeded(rcd);
220062306a36Sopenharmony_ci		ret = disarm_req_delay(rcd);
220162306a36Sopenharmony_ci		break;
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	case QIB_CMD_PIOAVAILUPD:
220462306a36Sopenharmony_ci		qib_force_pio_avail_update(rcd->dd);
220562306a36Sopenharmony_ci		break;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	case QIB_CMD_POLL_TYPE:
220862306a36Sopenharmony_ci		rcd->poll_type = cmd.cmd.poll_type;
220962306a36Sopenharmony_ci		break;
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	case QIB_CMD_ARMLAUNCH_CTRL:
221262306a36Sopenharmony_ci		rcd->dd->f_set_armlaunch(rcd->dd, cmd.cmd.armlaunch_ctrl);
221362306a36Sopenharmony_ci		break;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	case QIB_CMD_SDMA_INFLIGHT:
221662306a36Sopenharmony_ci		ret = qib_sdma_get_inflight(user_sdma_queue_fp(fp),
221762306a36Sopenharmony_ci					    (u32 __user *) (unsigned long)
221862306a36Sopenharmony_ci					    cmd.cmd.sdma_inflight);
221962306a36Sopenharmony_ci		break;
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	case QIB_CMD_SDMA_COMPLETE:
222262306a36Sopenharmony_ci		ret = qib_sdma_get_complete(rcd->ppd,
222362306a36Sopenharmony_ci					    user_sdma_queue_fp(fp),
222462306a36Sopenharmony_ci					    (u32 __user *) (unsigned long)
222562306a36Sopenharmony_ci					    cmd.cmd.sdma_complete);
222662306a36Sopenharmony_ci		break;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	case QIB_CMD_ACK_EVENT:
222962306a36Sopenharmony_ci		ret = qib_user_event_ack(rcd, subctxt_fp(fp),
223062306a36Sopenharmony_ci					 cmd.cmd.event_mask);
223162306a36Sopenharmony_ci		break;
223262306a36Sopenharmony_ci	}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	if (ret >= 0)
223562306a36Sopenharmony_ci		ret = consumed;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_cibail:
223862306a36Sopenharmony_ci	return ret;
223962306a36Sopenharmony_ci}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_cistatic ssize_t qib_write_iter(struct kiocb *iocb, struct iov_iter *from)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	struct qib_filedata *fp = iocb->ki_filp->private_data;
224462306a36Sopenharmony_ci	struct qib_ctxtdata *rcd = ctxt_fp(iocb->ki_filp);
224562306a36Sopenharmony_ci	struct qib_user_sdma_queue *pq = fp->pq;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	if (!from->user_backed || !from->nr_segs || !pq)
224862306a36Sopenharmony_ci		return -EINVAL;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	return qib_user_sdma_writev(rcd, pq, iter_iov(from), from->nr_segs);
225162306a36Sopenharmony_ci}
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_cistatic const struct class qib_class = {
225462306a36Sopenharmony_ci	.name = "ipath",
225562306a36Sopenharmony_ci};
225662306a36Sopenharmony_cistatic dev_t qib_dev;
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ciint qib_cdev_init(int minor, const char *name,
225962306a36Sopenharmony_ci		  const struct file_operations *fops,
226062306a36Sopenharmony_ci		  struct cdev **cdevp, struct device **devp)
226162306a36Sopenharmony_ci{
226262306a36Sopenharmony_ci	const dev_t dev = MKDEV(MAJOR(qib_dev), minor);
226362306a36Sopenharmony_ci	struct cdev *cdev;
226462306a36Sopenharmony_ci	struct device *device = NULL;
226562306a36Sopenharmony_ci	int ret;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	cdev = cdev_alloc();
226862306a36Sopenharmony_ci	if (!cdev) {
226962306a36Sopenharmony_ci		pr_err("Could not allocate cdev for minor %d, %s\n",
227062306a36Sopenharmony_ci		       minor, name);
227162306a36Sopenharmony_ci		ret = -ENOMEM;
227262306a36Sopenharmony_ci		goto done;
227362306a36Sopenharmony_ci	}
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	cdev->owner = THIS_MODULE;
227662306a36Sopenharmony_ci	cdev->ops = fops;
227762306a36Sopenharmony_ci	kobject_set_name(&cdev->kobj, name);
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	ret = cdev_add(cdev, dev, 1);
228062306a36Sopenharmony_ci	if (ret < 0) {
228162306a36Sopenharmony_ci		pr_err("Could not add cdev for minor %d, %s (err %d)\n",
228262306a36Sopenharmony_ci		       minor, name, -ret);
228362306a36Sopenharmony_ci		goto err_cdev;
228462306a36Sopenharmony_ci	}
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	device = device_create(&qib_class, NULL, dev, NULL, "%s", name);
228762306a36Sopenharmony_ci	if (!IS_ERR(device))
228862306a36Sopenharmony_ci		goto done;
228962306a36Sopenharmony_ci	ret = PTR_ERR(device);
229062306a36Sopenharmony_ci	device = NULL;
229162306a36Sopenharmony_ci	pr_err("Could not create device for minor %d, %s (err %d)\n",
229262306a36Sopenharmony_ci	       minor, name, -ret);
229362306a36Sopenharmony_cierr_cdev:
229462306a36Sopenharmony_ci	cdev_del(cdev);
229562306a36Sopenharmony_ci	cdev = NULL;
229662306a36Sopenharmony_cidone:
229762306a36Sopenharmony_ci	*cdevp = cdev;
229862306a36Sopenharmony_ci	*devp = device;
229962306a36Sopenharmony_ci	return ret;
230062306a36Sopenharmony_ci}
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_civoid qib_cdev_cleanup(struct cdev **cdevp, struct device **devp)
230362306a36Sopenharmony_ci{
230462306a36Sopenharmony_ci	struct device *device = *devp;
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	if (device) {
230762306a36Sopenharmony_ci		device_unregister(device);
230862306a36Sopenharmony_ci		*devp = NULL;
230962306a36Sopenharmony_ci	}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	if (*cdevp) {
231262306a36Sopenharmony_ci		cdev_del(*cdevp);
231362306a36Sopenharmony_ci		*cdevp = NULL;
231462306a36Sopenharmony_ci	}
231562306a36Sopenharmony_ci}
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_cistatic struct cdev *wildcard_cdev;
231862306a36Sopenharmony_cistatic struct device *wildcard_device;
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ciint __init qib_dev_init(void)
232162306a36Sopenharmony_ci{
232262306a36Sopenharmony_ci	int ret;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	ret = alloc_chrdev_region(&qib_dev, 0, QIB_NMINORS, QIB_DRV_NAME);
232562306a36Sopenharmony_ci	if (ret < 0) {
232662306a36Sopenharmony_ci		pr_err("Could not allocate chrdev region (err %d)\n", -ret);
232762306a36Sopenharmony_ci		goto done;
232862306a36Sopenharmony_ci	}
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	ret = class_register(&qib_class);
233162306a36Sopenharmony_ci	if (ret) {
233262306a36Sopenharmony_ci		pr_err("Could not create device class (err %d)\n", -ret);
233362306a36Sopenharmony_ci		unregister_chrdev_region(qib_dev, QIB_NMINORS);
233462306a36Sopenharmony_ci	}
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_cidone:
233762306a36Sopenharmony_ci	return ret;
233862306a36Sopenharmony_ci}
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_civoid qib_dev_cleanup(void)
234162306a36Sopenharmony_ci{
234262306a36Sopenharmony_ci	if (class_is_registered(&qib_class))
234362306a36Sopenharmony_ci		class_unregister(&qib_class);
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	unregister_chrdev_region(qib_dev, QIB_NMINORS);
234662306a36Sopenharmony_ci}
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_cistatic atomic_t user_count = ATOMIC_INIT(0);
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_cistatic void qib_user_remove(struct qib_devdata *dd)
235162306a36Sopenharmony_ci{
235262306a36Sopenharmony_ci	if (atomic_dec_return(&user_count) == 0)
235362306a36Sopenharmony_ci		qib_cdev_cleanup(&wildcard_cdev, &wildcard_device);
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	qib_cdev_cleanup(&dd->user_cdev, &dd->user_device);
235662306a36Sopenharmony_ci}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_cistatic int qib_user_add(struct qib_devdata *dd)
235962306a36Sopenharmony_ci{
236062306a36Sopenharmony_ci	char name[10];
236162306a36Sopenharmony_ci	int ret;
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	if (atomic_inc_return(&user_count) == 1) {
236462306a36Sopenharmony_ci		ret = qib_cdev_init(0, "ipath", &qib_file_ops,
236562306a36Sopenharmony_ci				    &wildcard_cdev, &wildcard_device);
236662306a36Sopenharmony_ci		if (ret)
236762306a36Sopenharmony_ci			goto done;
236862306a36Sopenharmony_ci	}
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	snprintf(name, sizeof(name), "ipath%d", dd->unit);
237162306a36Sopenharmony_ci	ret = qib_cdev_init(dd->unit + 1, name, &qib_file_ops,
237262306a36Sopenharmony_ci			    &dd->user_cdev, &dd->user_device);
237362306a36Sopenharmony_ci	if (ret)
237462306a36Sopenharmony_ci		qib_user_remove(dd);
237562306a36Sopenharmony_cidone:
237662306a36Sopenharmony_ci	return ret;
237762306a36Sopenharmony_ci}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci/*
238062306a36Sopenharmony_ci * Create per-unit files in /dev
238162306a36Sopenharmony_ci */
238262306a36Sopenharmony_ciint qib_device_create(struct qib_devdata *dd)
238362306a36Sopenharmony_ci{
238462306a36Sopenharmony_ci	int r, ret;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	r = qib_user_add(dd);
238762306a36Sopenharmony_ci	ret = qib_diag_add(dd);
238862306a36Sopenharmony_ci	if (r && !ret)
238962306a36Sopenharmony_ci		ret = r;
239062306a36Sopenharmony_ci	return ret;
239162306a36Sopenharmony_ci}
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci/*
239462306a36Sopenharmony_ci * Remove per-unit files in /dev
239562306a36Sopenharmony_ci * void, core kernel returns no errors for this stuff
239662306a36Sopenharmony_ci */
239762306a36Sopenharmony_civoid qib_device_remove(struct qib_devdata *dd)
239862306a36Sopenharmony_ci{
239962306a36Sopenharmony_ci	qib_user_remove(dd);
240062306a36Sopenharmony_ci	qib_diag_remove(dd);
240162306a36Sopenharmony_ci}
2402