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