• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/infiniband/hw/qib/
1/*
2 * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
3 * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses.  You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 *     Redistribution and use in source and binary forms, with or
12 *     without modification, are permitted provided that the following
13 *     conditions are met:
14 *
15 *      - Redistributions of source code must retain the above
16 *        copyright notice, this list of conditions and the following
17 *        disclaimer.
18 *
19 *      - Redistributions in binary form must reproduce the above
20 *        copyright notice, this list of conditions and the following
21 *        disclaimer in the documentation and/or other materials
22 *        provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 */
33
34#include <linux/mm.h>
35#include <linux/device.h>
36
37#include "qib.h"
38
39static void __qib_release_user_pages(struct page **p, size_t num_pages,
40				     int dirty)
41{
42	size_t i;
43
44	for (i = 0; i < num_pages; i++) {
45		if (dirty)
46			set_page_dirty_lock(p[i]);
47		put_page(p[i]);
48	}
49}
50
51/*
52 * Call with current->mm->mmap_sem held.
53 */
54static int __get_user_pages(unsigned long start_page, size_t num_pages,
55			    struct page **p, struct vm_area_struct **vma)
56{
57	unsigned long lock_limit;
58	size_t got;
59	int ret;
60
61	lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
62
63	if (num_pages > lock_limit && !capable(CAP_IPC_LOCK)) {
64		ret = -ENOMEM;
65		goto bail;
66	}
67
68	for (got = 0; got < num_pages; got += ret) {
69		ret = get_user_pages(current, current->mm,
70				     start_page + got * PAGE_SIZE,
71				     num_pages - got, 1, 1,
72				     p + got, vma);
73		if (ret < 0)
74			goto bail_release;
75	}
76
77	current->mm->locked_vm += num_pages;
78
79	ret = 0;
80	goto bail;
81
82bail_release:
83	__qib_release_user_pages(p, got, 0);
84bail:
85	return ret;
86}
87
88dma_addr_t qib_map_page(struct pci_dev *hwdev, struct page *page,
89			unsigned long offset, size_t size, int direction)
90{
91	dma_addr_t phys;
92
93	phys = pci_map_page(hwdev, page, offset, size, direction);
94
95	if (phys == 0) {
96		pci_unmap_page(hwdev, phys, size, direction);
97		phys = pci_map_page(hwdev, page, offset, size, direction);
98	}
99
100	return phys;
101}
102
103/**
104 * qib_get_user_pages - lock user pages into memory
105 * @start_page: the start page
106 * @num_pages: the number of pages
107 * @p: the output page structures
108 *
109 * This function takes a given start page (page aligned user virtual
110 * address) and pins it and the following specified number of pages.  For
111 * now, num_pages is always 1, but that will probably change at some point
112 * (because caller is doing expected sends on a single virtually contiguous
113 * buffer, so we can do all pages at once).
114 */
115int qib_get_user_pages(unsigned long start_page, size_t num_pages,
116		       struct page **p)
117{
118	int ret;
119
120	down_write(&current->mm->mmap_sem);
121
122	ret = __get_user_pages(start_page, num_pages, p, NULL);
123
124	up_write(&current->mm->mmap_sem);
125
126	return ret;
127}
128
129void qib_release_user_pages(struct page **p, size_t num_pages)
130{
131	if (current->mm) /* during close after signal, mm can be NULL */
132		down_write(&current->mm->mmap_sem);
133
134	__qib_release_user_pages(p, num_pages, 1);
135
136	if (current->mm) {
137		current->mm->locked_vm -= num_pages;
138		up_write(&current->mm->mmap_sem);
139	}
140}
141