]>
Commit | Line | Data |
---|---|---|
e126ba97 EC |
1 | /* |
2 | * Copyright (c) 2013, Mellanox Technologies inc. 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 <rdma/ib_umem.h> | |
35 | #include "mlx5_ib.h" | |
36 | ||
37 | /* @umem: umem object to scan | |
38 | * @addr: ib virtual address requested by the user | |
39 | * @count: number of PAGE_SIZE pages covered by umem | |
40 | * @shift: page shift for the compound pages found in the region | |
41 | * @ncont: number of compund pages | |
42 | * @order: log2 of the number of compound pages | |
43 | */ | |
44 | void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift, | |
45 | int *ncont, int *order) | |
46 | { | |
47 | struct ib_umem_chunk *chunk; | |
48 | unsigned long tmp; | |
49 | unsigned long m; | |
50 | int i, j, k; | |
51 | u64 base = 0; | |
52 | int p = 0; | |
53 | int skip; | |
54 | int mask; | |
55 | u64 len; | |
56 | u64 pfn; | |
57 | ||
58 | addr = addr >> PAGE_SHIFT; | |
59 | tmp = (unsigned long)addr; | |
60 | m = find_first_bit(&tmp, sizeof(tmp)); | |
61 | skip = 1 << m; | |
62 | mask = skip - 1; | |
63 | i = 0; | |
64 | list_for_each_entry(chunk, &umem->chunk_list, list) | |
65 | for (j = 0; j < chunk->nmap; j++) { | |
66 | len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT; | |
67 | pfn = sg_dma_address(&chunk->page_list[j]) >> PAGE_SHIFT; | |
68 | for (k = 0; k < len; k++) { | |
69 | if (!(i & mask)) { | |
70 | tmp = (unsigned long)pfn; | |
71 | m = min(m, find_first_bit(&tmp, sizeof(tmp))); | |
72 | skip = 1 << m; | |
73 | mask = skip - 1; | |
74 | base = pfn; | |
75 | p = 0; | |
76 | } else { | |
77 | if (base + p != pfn) { | |
78 | tmp = (unsigned long)p; | |
79 | m = find_first_bit(&tmp, sizeof(tmp)); | |
80 | skip = 1 << m; | |
81 | mask = skip - 1; | |
82 | base = pfn; | |
83 | p = 0; | |
84 | } | |
85 | } | |
86 | p++; | |
87 | i++; | |
88 | } | |
89 | } | |
90 | ||
91 | if (i) { | |
92 | m = min_t(unsigned long, ilog2(roundup_pow_of_two(i)), m); | |
93 | ||
94 | if (order) | |
95 | *order = ilog2(roundup_pow_of_two(i) >> m); | |
96 | ||
97 | *ncont = DIV_ROUND_UP(i, (1 << m)); | |
98 | } else { | |
99 | m = 0; | |
100 | ||
101 | if (order) | |
102 | *order = 0; | |
103 | ||
104 | *ncont = 0; | |
105 | } | |
106 | *shift = PAGE_SHIFT + m; | |
107 | *count = i; | |
108 | } | |
109 | ||
110 | void mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, | |
111 | int page_shift, __be64 *pas, int umr) | |
112 | { | |
113 | int shift = page_shift - PAGE_SHIFT; | |
114 | int mask = (1 << shift) - 1; | |
115 | struct ib_umem_chunk *chunk; | |
116 | int i, j, k; | |
117 | u64 cur = 0; | |
118 | u64 base; | |
119 | int len; | |
120 | ||
121 | i = 0; | |
122 | list_for_each_entry(chunk, &umem->chunk_list, list) | |
123 | for (j = 0; j < chunk->nmap; j++) { | |
124 | len = sg_dma_len(&chunk->page_list[j]) >> PAGE_SHIFT; | |
125 | base = sg_dma_address(&chunk->page_list[j]); | |
126 | for (k = 0; k < len; k++) { | |
127 | if (!(i & mask)) { | |
128 | cur = base + (k << PAGE_SHIFT); | |
129 | if (umr) | |
130 | cur |= 3; | |
131 | ||
132 | pas[i >> shift] = cpu_to_be64(cur); | |
133 | mlx5_ib_dbg(dev, "pas[%d] 0x%llx\n", | |
134 | i >> shift, be64_to_cpu(pas[i >> shift])); | |
135 | } else | |
136 | mlx5_ib_dbg(dev, "=====> 0x%llx\n", | |
137 | base + (k << PAGE_SHIFT)); | |
138 | i++; | |
139 | } | |
140 | } | |
141 | } | |
142 | ||
143 | int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset) | |
144 | { | |
145 | u64 page_size; | |
146 | u64 page_mask; | |
147 | u64 off_size; | |
148 | u64 off_mask; | |
149 | u64 buf_off; | |
150 | ||
151 | page_size = 1 << page_shift; | |
152 | page_mask = page_size - 1; | |
153 | buf_off = addr & page_mask; | |
154 | off_size = page_size >> 6; | |
155 | off_mask = off_size - 1; | |
156 | ||
157 | if (buf_off & off_mask) | |
158 | return -EINVAL; | |
159 | ||
160 | *offset = buf_off >> ilog2(off_size); | |
161 | return 0; | |
162 | } |