Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
  3 *
  4 * This software is available to you under a choice of one of two
  5 * licenses.  You may choose to be licensed under the terms of the GNU
  6 * General Public License (GPL) Version 2, available from the file
  7 * COPYING in the main directory of this source tree, or the
  8 * OpenIB.org BSD license below:
  9 *
 10 *     Redistribution and use in source and binary forms, with or
 11 *     without modification, are permitted provided that the following
 12 *     conditions are met:
 13 *
 14 *      - Redistributions of source code must retain the above
 15 *        copyright notice, this list of conditions and the following
 16 *        disclaimer.
 17 *
 18 *      - Redistributions in binary form must reproduce the above
 19 *        copyright notice, this list of conditions and the following
 20 *        disclaimer in the documentation and/or other materials
 21 *        provided with the distribution.
 22 *
 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 30 * SOFTWARE.
 31 */
 32
 33#include <linux/module.h>
 34#include <linux/vmalloc.h>
 35#include <linux/slab.h>
 36#include <linux/mm.h>
 37#include <linux/errno.h>
 38#include <asm/pgtable.h>
 39
 40#include "ipath_verbs.h"
 41
 42/**
 43 * ipath_release_mmap_info - free mmap info structure
 44 * @ref: a pointer to the kref within struct ipath_mmap_info
 45 */
 46void ipath_release_mmap_info(struct kref *ref)
 47{
 48	struct ipath_mmap_info *ip =
 49		container_of(ref, struct ipath_mmap_info, ref);
 50	struct ipath_ibdev *dev = to_idev(ip->context->device);
 51
 52	spin_lock_irq(&dev->pending_lock);
 53	list_del(&ip->pending_mmaps);
 54	spin_unlock_irq(&dev->pending_lock);
 55
 56	vfree(ip->obj);
 57	kfree(ip);
 58}
 59
 60/*
 61 * open and close keep track of how many times the CQ is mapped,
 62 * to avoid releasing it.
 63 */
 64static void ipath_vma_open(struct vm_area_struct *vma)
 65{
 66	struct ipath_mmap_info *ip = vma->vm_private_data;
 67
 68	kref_get(&ip->ref);
 69}
 70
 71static void ipath_vma_close(struct vm_area_struct *vma)
 72{
 73	struct ipath_mmap_info *ip = vma->vm_private_data;
 74
 75	kref_put(&ip->ref, ipath_release_mmap_info);
 76}
 77
 78static const struct vm_operations_struct ipath_vm_ops = {
 79	.open =     ipath_vma_open,
 80	.close =    ipath_vma_close,
 81};
 82
 83/**
 84 * ipath_mmap - create a new mmap region
 85 * @context: the IB user context of the process making the mmap() call
 86 * @vma: the VMA to be initialized
 87 * Return zero if the mmap is OK. Otherwise, return an errno.
 88 */
 89int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 90{
 91	struct ipath_ibdev *dev = to_idev(context->device);
 92	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 93	unsigned long size = vma->vm_end - vma->vm_start;
 94	struct ipath_mmap_info *ip, *pp;
 95	int ret = -EINVAL;
 96
 97	/*
 98	 * Search the device's list of objects waiting for a mmap call.
 99	 * Normally, this list is very short since a call to create a
100	 * CQ, QP, or SRQ is soon followed by a call to mmap().
101	 */
102	spin_lock_irq(&dev->pending_lock);
103	list_for_each_entry_safe(ip, pp, &dev->pending_mmaps,
104				 pending_mmaps) {
105		/* Only the creator is allowed to mmap the object */
106		if (context != ip->context || (__u64) offset != ip->offset)
107			continue;
108		/* Don't allow a mmap larger than the object. */
109		if (size > ip->size)
110			break;
111
112		list_del_init(&ip->pending_mmaps);
113		spin_unlock_irq(&dev->pending_lock);
114
115		ret = remap_vmalloc_range(vma, ip->obj, 0);
116		if (ret)
117			goto done;
118		vma->vm_ops = &ipath_vm_ops;
119		vma->vm_private_data = ip;
120		ipath_vma_open(vma);
121		goto done;
122	}
123	spin_unlock_irq(&dev->pending_lock);
124done:
125	return ret;
126}
127
128/*
129 * Allocate information for ipath_mmap
130 */
131struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
132					       u32 size,
133					       struct ib_ucontext *context,
134					       void *obj) {
135	struct ipath_mmap_info *ip;
136
137	ip = kmalloc(sizeof *ip, GFP_KERNEL);
138	if (!ip)
139		goto bail;
140
141	size = PAGE_ALIGN(size);
142
143	spin_lock_irq(&dev->mmap_offset_lock);
144	if (dev->mmap_offset == 0)
145		dev->mmap_offset = PAGE_SIZE;
146	ip->offset = dev->mmap_offset;
147	dev->mmap_offset += size;
148	spin_unlock_irq(&dev->mmap_offset_lock);
149
150	INIT_LIST_HEAD(&ip->pending_mmaps);
151	ip->size = size;
152	ip->context = context;
153	ip->obj = obj;
154	kref_init(&ip->ref);
155
156bail:
157	return ip;
158}
159
160void ipath_update_mmap_info(struct ipath_ibdev *dev,
161			    struct ipath_mmap_info *ip,
162			    u32 size, void *obj) {
163	size = PAGE_ALIGN(size);
164
165	spin_lock_irq(&dev->mmap_offset_lock);
166	if (dev->mmap_offset == 0)
167		dev->mmap_offset = PAGE_SIZE;
168	ip->offset = dev->mmap_offset;
169	dev->mmap_offset += size;
170	spin_unlock_irq(&dev->mmap_offset_lock);
171
172	ip->size = size;
173	ip->obj = obj;
174}