diff options
Diffstat (limited to 'drivers/infiniband/hw/mlx5/mem.c')
-rw-r--r-- | drivers/infiniband/hw/mlx5/mem.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c new file mode 100644 index 000000000000..3a5322870b96 --- /dev/null +++ b/drivers/infiniband/hw/mlx5/mem.c | |||
@@ -0,0 +1,162 @@ | |||
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 | } | ||