Commit | Line | Data |
---|---|---|
fab97220 HS |
1 | /* |
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | |
3 | * | |
4 | * adress vector functions | |
5 | * | |
6 | * Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com> | |
7 | * Khadija Souissi <souissik@de.ibm.com> | |
8 | * Reinhard Ernst <rernst@de.ibm.com> | |
9 | * Christoph Raisch <raisch@de.ibm.com> | |
10 | * | |
11 | * Copyright (c) 2005 IBM Corporation | |
12 | * | |
13 | * All rights reserved. | |
14 | * | |
15 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | |
16 | * BSD. | |
17 | * | |
18 | * OpenIB BSD License | |
19 | * | |
20 | * Redistribution and use in source and binary forms, with or without | |
21 | * modification, are permitted provided that the following conditions are met: | |
22 | * | |
23 | * Redistributions of source code must retain the above copyright notice, this | |
24 | * list of conditions and the following disclaimer. | |
25 | * | |
26 | * Redistributions in binary form must reproduce the above copyright notice, | |
27 | * this list of conditions and the following disclaimer in the documentation | |
28 | * and/or other materials | |
29 | * provided with the distribution. | |
30 | * | |
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
32 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
33 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
34 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
35 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
36 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
37 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | |
38 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | |
39 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
41 | * POSSIBILITY OF SUCH DAMAGE. | |
42 | */ | |
43 | ||
44 | ||
45 | #include <asm/current.h> | |
46 | ||
47 | #include "ehca_tools.h" | |
48 | #include "ehca_iverbs.h" | |
49 | #include "hcp_if.h" | |
50 | ||
51 | static struct kmem_cache *av_cache; | |
52 | ||
53 | struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) | |
54 | { | |
55 | int ret; | |
56 | struct ehca_av *av; | |
57 | struct ehca_shca *shca = container_of(pd->device, struct ehca_shca, | |
58 | ib_device); | |
59 | ||
e94b1766 | 60 | av = kmem_cache_alloc(av_cache, GFP_KERNEL); |
fab97220 HS |
61 | if (!av) { |
62 | ehca_err(pd->device, "Out of memory pd=%p ah_attr=%p", | |
63 | pd, ah_attr); | |
64 | return ERR_PTR(-ENOMEM); | |
65 | } | |
66 | ||
67 | av->av.sl = ah_attr->sl; | |
68 | av->av.dlid = ah_attr->dlid; | |
69 | av->av.slid_path_bits = ah_attr->src_path_bits; | |
70 | ||
71 | if (ehca_static_rate < 0) { | |
72 | int ah_mult = ib_rate_to_mult(ah_attr->static_rate); | |
73 | int ehca_mult = | |
74 | ib_rate_to_mult(shca->sport[ah_attr->port_num].rate ); | |
75 | ||
76 | if (ah_mult >= ehca_mult) | |
77 | av->av.ipd = 0; | |
78 | else | |
79 | av->av.ipd = (ah_mult > 0) ? | |
80 | ((ehca_mult - 1) / ah_mult) : 0; | |
81 | } else | |
2b94397a | 82 | av->av.ipd = ehca_static_rate; |
fab97220 HS |
83 | |
84 | av->av.lnh = ah_attr->ah_flags; | |
85 | av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6); | |
86 | av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_TCLASS_MASK, | |
87 | ah_attr->grh.traffic_class); | |
88 | av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK, | |
89 | ah_attr->grh.flow_label); | |
90 | av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK, | |
91 | ah_attr->grh.hop_limit); | |
92 | av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1B); | |
93 | /* set sgid in grh.word_1 */ | |
94 | if (ah_attr->ah_flags & IB_AH_GRH) { | |
95 | int rc; | |
96 | struct ib_port_attr port_attr; | |
97 | union ib_gid gid; | |
98 | memset(&port_attr, 0, sizeof(port_attr)); | |
99 | rc = ehca_query_port(pd->device, ah_attr->port_num, | |
100 | &port_attr); | |
101 | if (rc) { /* invalid port number */ | |
102 | ret = -EINVAL; | |
103 | ehca_err(pd->device, "Invalid port number " | |
104 | "ehca_query_port() returned %x " | |
105 | "pd=%p ah_attr=%p", rc, pd, ah_attr); | |
106 | goto create_ah_exit1; | |
107 | } | |
108 | memset(&gid, 0, sizeof(gid)); | |
109 | rc = ehca_query_gid(pd->device, | |
110 | ah_attr->port_num, | |
111 | ah_attr->grh.sgid_index, &gid); | |
112 | if (rc) { | |
113 | ret = -EINVAL; | |
114 | ehca_err(pd->device, "Failed to retrieve sgid " | |
115 | "ehca_query_gid() returned %x " | |
116 | "pd=%p ah_attr=%p", rc, pd, ah_attr); | |
117 | goto create_ah_exit1; | |
118 | } | |
119 | memcpy(&av->av.grh.word_1, &gid, sizeof(gid)); | |
120 | } | |
91f13aa3 | 121 | av->av.pmtu = shca->max_mtu; |
fab97220 HS |
122 | |
123 | /* dgid comes in grh.word_3 */ | |
124 | memcpy(&av->av.grh.word_3, &ah_attr->grh.dgid, | |
125 | sizeof(ah_attr->grh.dgid)); | |
126 | ||
127 | return &av->ib_ah; | |
128 | ||
129 | create_ah_exit1: | |
130 | kmem_cache_free(av_cache, av); | |
131 | ||
132 | return ERR_PTR(ret); | |
133 | } | |
134 | ||
135 | int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) | |
136 | { | |
137 | struct ehca_av *av; | |
138 | struct ehca_ud_av new_ehca_av; | |
139 | struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd); | |
91f13aa3 JF |
140 | struct ehca_shca *shca = container_of(ah->pd->device, struct ehca_shca, |
141 | ib_device); | |
fab97220 HS |
142 | u32 cur_pid = current->tgid; |
143 | ||
144 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | |
145 | my_pd->ownpid != cur_pid) { | |
146 | ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x", | |
147 | cur_pid, my_pd->ownpid); | |
148 | return -EINVAL; | |
149 | } | |
150 | ||
151 | memset(&new_ehca_av, 0, sizeof(new_ehca_av)); | |
152 | new_ehca_av.sl = ah_attr->sl; | |
153 | new_ehca_av.dlid = ah_attr->dlid; | |
154 | new_ehca_av.slid_path_bits = ah_attr->src_path_bits; | |
155 | new_ehca_av.ipd = ah_attr->static_rate; | |
156 | new_ehca_av.lnh = EHCA_BMASK_SET(GRH_FLAG_MASK, | |
157 | (ah_attr->ah_flags & IB_AH_GRH) > 0); | |
158 | new_ehca_av.grh.word_0 = EHCA_BMASK_SET(GRH_TCLASS_MASK, | |
159 | ah_attr->grh.traffic_class); | |
160 | new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK, | |
161 | ah_attr->grh.flow_label); | |
162 | new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK, | |
163 | ah_attr->grh.hop_limit); | |
164 | new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1b); | |
165 | ||
166 | /* set sgid in grh.word_1 */ | |
167 | if (ah_attr->ah_flags & IB_AH_GRH) { | |
168 | int rc; | |
169 | struct ib_port_attr port_attr; | |
170 | union ib_gid gid; | |
171 | memset(&port_attr, 0, sizeof(port_attr)); | |
172 | rc = ehca_query_port(ah->device, ah_attr->port_num, | |
173 | &port_attr); | |
174 | if (rc) { /* invalid port number */ | |
175 | ehca_err(ah->device, "Invalid port number " | |
176 | "ehca_query_port() returned %x " | |
177 | "ah=%p ah_attr=%p port_num=%x", | |
178 | rc, ah, ah_attr, ah_attr->port_num); | |
179 | return -EINVAL; | |
180 | } | |
181 | memset(&gid, 0, sizeof(gid)); | |
182 | rc = ehca_query_gid(ah->device, | |
183 | ah_attr->port_num, | |
184 | ah_attr->grh.sgid_index, &gid); | |
185 | if (rc) { | |
186 | ehca_err(ah->device, "Failed to retrieve sgid " | |
187 | "ehca_query_gid() returned %x " | |
188 | "ah=%p ah_attr=%p port_num=%x " | |
189 | "sgid_index=%x", | |
190 | rc, ah, ah_attr, ah_attr->port_num, | |
191 | ah_attr->grh.sgid_index); | |
192 | return -EINVAL; | |
193 | } | |
194 | memcpy(&new_ehca_av.grh.word_1, &gid, sizeof(gid)); | |
195 | } | |
196 | ||
91f13aa3 | 197 | new_ehca_av.pmtu = shca->max_mtu; |
fab97220 HS |
198 | |
199 | memcpy(&new_ehca_av.grh.word_3, &ah_attr->grh.dgid, | |
200 | sizeof(ah_attr->grh.dgid)); | |
201 | ||
202 | av = container_of(ah, struct ehca_av, ib_ah); | |
203 | av->av = new_ehca_av; | |
204 | ||
205 | return 0; | |
206 | } | |
207 | ||
208 | int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) | |
209 | { | |
210 | struct ehca_av *av = container_of(ah, struct ehca_av, ib_ah); | |
211 | struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd); | |
212 | u32 cur_pid = current->tgid; | |
213 | ||
214 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | |
215 | my_pd->ownpid != cur_pid) { | |
216 | ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x", | |
217 | cur_pid, my_pd->ownpid); | |
218 | return -EINVAL; | |
219 | } | |
220 | ||
221 | memcpy(&ah_attr->grh.dgid, &av->av.grh.word_3, | |
222 | sizeof(ah_attr->grh.dgid)); | |
223 | ah_attr->sl = av->av.sl; | |
224 | ||
225 | ah_attr->dlid = av->av.dlid; | |
226 | ||
227 | ah_attr->src_path_bits = av->av.slid_path_bits; | |
228 | ah_attr->static_rate = av->av.ipd; | |
229 | ah_attr->ah_flags = EHCA_BMASK_GET(GRH_FLAG_MASK, av->av.lnh); | |
230 | ah_attr->grh.traffic_class = EHCA_BMASK_GET(GRH_TCLASS_MASK, | |
231 | av->av.grh.word_0); | |
232 | ah_attr->grh.hop_limit = EHCA_BMASK_GET(GRH_HOPLIMIT_MASK, | |
233 | av->av.grh.word_0); | |
234 | ah_attr->grh.flow_label = EHCA_BMASK_GET(GRH_FLOWLABEL_MASK, | |
235 | av->av.grh.word_0); | |
236 | ||
237 | return 0; | |
238 | } | |
239 | ||
240 | int ehca_destroy_ah(struct ib_ah *ah) | |
241 | { | |
242 | struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd); | |
243 | u32 cur_pid = current->tgid; | |
244 | ||
245 | if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && | |
246 | my_pd->ownpid != cur_pid) { | |
247 | ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x", | |
248 | cur_pid, my_pd->ownpid); | |
249 | return -EINVAL; | |
250 | } | |
251 | ||
252 | kmem_cache_free(av_cache, container_of(ah, struct ehca_av, ib_ah)); | |
253 | ||
254 | return 0; | |
255 | } | |
256 | ||
257 | int ehca_init_av_cache(void) | |
258 | { | |
259 | av_cache = kmem_cache_create("ehca_cache_av", | |
260 | sizeof(struct ehca_av), 0, | |
261 | SLAB_HWCACHE_ALIGN, | |
20c2df83 | 262 | NULL); |
fab97220 HS |
263 | if (!av_cache) |
264 | return -ENOMEM; | |
265 | return 0; | |
266 | } | |
267 | ||
268 | void ehca_cleanup_av_cache(void) | |
269 | { | |
270 | if (av_cache) | |
271 | kmem_cache_destroy(av_cache); | |
272 | } |