Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | |
cd4e8fb4 | 3 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. |
1da177e4 LT |
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 | * $Id: mthca_av.c 1349 2004-12-16 21:09:43Z roland $ | |
34 | */ | |
35 | ||
36 | #include <linux/init.h> | |
4e57b681 TS |
37 | #include <linux/string.h> |
38 | #include <linux/slab.h> | |
1da177e4 | 39 | |
a4d61e84 RD |
40 | #include <rdma/ib_verbs.h> |
41 | #include <rdma/ib_cache.h> | |
1da177e4 LT |
42 | |
43 | #include "mthca_dev.h" | |
44 | ||
45 | struct mthca_av { | |
97f52eb4 SH |
46 | __be32 port_pd; |
47 | u8 reserved1; | |
48 | u8 g_slid; | |
49 | __be16 dlid; | |
50 | u8 reserved2; | |
51 | u8 gid_index; | |
52 | u8 msg_sr; | |
53 | u8 hop_limit; | |
54 | __be32 sl_tclass_flowlabel; | |
55 | __be32 dgid[4]; | |
1da177e4 LT |
56 | }; |
57 | ||
58 | int mthca_create_ah(struct mthca_dev *dev, | |
59 | struct mthca_pd *pd, | |
60 | struct ib_ah_attr *ah_attr, | |
61 | struct mthca_ah *ah) | |
62 | { | |
63 | u32 index = -1; | |
64 | struct mthca_av *av = NULL; | |
65 | ||
66 | ah->type = MTHCA_AH_PCI_POOL; | |
67 | ||
d10ddbf6 | 68 | if (mthca_is_memfree(dev)) { |
8df8a34d | 69 | ah->av = kmalloc(sizeof *ah->av, GFP_ATOMIC); |
1da177e4 LT |
70 | if (!ah->av) |
71 | return -ENOMEM; | |
72 | ||
73 | ah->type = MTHCA_AH_KMALLOC; | |
74 | av = ah->av; | |
75 | } else if (!atomic_read(&pd->sqp_count) && | |
76 | !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { | |
77 | index = mthca_alloc(&dev->av_table.alloc); | |
78 | ||
79 | /* fall back to allocate in host memory */ | |
80 | if (index == -1) | |
81 | goto on_hca_fail; | |
82 | ||
8df8a34d | 83 | av = kmalloc(sizeof *av, GFP_ATOMIC); |
1da177e4 LT |
84 | if (!av) |
85 | goto on_hca_fail; | |
86 | ||
87 | ah->type = MTHCA_AH_ON_HCA; | |
88 | ah->avdma = dev->av_table.ddr_av_base + | |
89 | index * MTHCA_AV_SIZE; | |
90 | } | |
91 | ||
92 | on_hca_fail: | |
93 | if (ah->type == MTHCA_AH_PCI_POOL) { | |
94 | ah->av = pci_pool_alloc(dev->av_table.pool, | |
8df8a34d | 95 | SLAB_ATOMIC, &ah->avdma); |
1da177e4 LT |
96 | if (!ah->av) |
97 | return -ENOMEM; | |
98 | ||
99 | av = ah->av; | |
100 | } | |
101 | ||
102 | ah->key = pd->ntmr.ibmr.lkey; | |
103 | ||
104 | memset(av, 0, MTHCA_AV_SIZE); | |
105 | ||
106 | av->port_pd = cpu_to_be32(pd->pd_num | (ah_attr->port_num << 24)); | |
107 | av->g_slid = ah_attr->src_path_bits; | |
108 | av->dlid = cpu_to_be16(ah_attr->dlid); | |
109 | av->msg_sr = (3 << 4) | /* 2K message */ | |
110 | ah_attr->static_rate; | |
111 | av->sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); | |
112 | if (ah_attr->ah_flags & IB_AH_GRH) { | |
113 | av->g_slid |= 0x80; | |
114 | av->gid_index = (ah_attr->port_num - 1) * dev->limits.gid_table_len + | |
115 | ah_attr->grh.sgid_index; | |
116 | av->hop_limit = ah_attr->grh.hop_limit; | |
117 | av->sl_tclass_flowlabel |= | |
118 | cpu_to_be32((ah_attr->grh.traffic_class << 20) | | |
119 | ah_attr->grh.flow_label); | |
120 | memcpy(av->dgid, ah_attr->grh.dgid.raw, 16); | |
121 | } else { | |
122 | /* Arbel workaround -- low byte of GID must be 2 */ | |
123 | av->dgid[3] = cpu_to_be32(2); | |
124 | } | |
125 | ||
126 | if (0) { | |
127 | int j; | |
128 | ||
129 | mthca_dbg(dev, "Created UDAV at %p/%08lx:\n", | |
130 | av, (unsigned long) ah->avdma); | |
131 | for (j = 0; j < 8; ++j) | |
132 | printk(KERN_DEBUG " [%2x] %08x\n", | |
97f52eb4 | 133 | j * 4, be32_to_cpu(((__be32 *) av)[j])); |
1da177e4 LT |
134 | } |
135 | ||
136 | if (ah->type == MTHCA_AH_ON_HCA) { | |
137 | memcpy_toio(dev->av_table.av_map + index * MTHCA_AV_SIZE, | |
138 | av, MTHCA_AV_SIZE); | |
139 | kfree(av); | |
140 | } | |
141 | ||
142 | return 0; | |
143 | } | |
144 | ||
145 | int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah) | |
146 | { | |
147 | switch (ah->type) { | |
148 | case MTHCA_AH_ON_HCA: | |
149 | mthca_free(&dev->av_table.alloc, | |
2fa5e2eb | 150 | (ah->avdma - dev->av_table.ddr_av_base) / |
1da177e4 LT |
151 | MTHCA_AV_SIZE); |
152 | break; | |
153 | ||
154 | case MTHCA_AH_PCI_POOL: | |
155 | pci_pool_free(dev->av_table.pool, ah->av, ah->avdma); | |
156 | break; | |
157 | ||
158 | case MTHCA_AH_KMALLOC: | |
159 | kfree(ah->av); | |
160 | break; | |
161 | } | |
162 | ||
163 | return 0; | |
164 | } | |
165 | ||
9eacee2a MT |
166 | int mthca_ah_grh_present(struct mthca_ah *ah) |
167 | { | |
168 | return !!(ah->av->g_slid & 0x80); | |
169 | } | |
170 | ||
1da177e4 LT |
171 | int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah, |
172 | struct ib_ud_header *header) | |
173 | { | |
174 | if (ah->type == MTHCA_AH_ON_HCA) | |
175 | return -EINVAL; | |
176 | ||
177 | header->lrh.service_level = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28; | |
178 | header->lrh.destination_lid = ah->av->dlid; | |
97f52eb4 | 179 | header->lrh.source_lid = cpu_to_be16(ah->av->g_slid & 0x7f); |
9eacee2a | 180 | if (mthca_ah_grh_present(ah)) { |
1da177e4 LT |
181 | header->grh.traffic_class = |
182 | (be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff; | |
183 | header->grh.flow_label = | |
184 | ah->av->sl_tclass_flowlabel & cpu_to_be32(0xfffff); | |
185 | ib_get_cached_gid(&dev->ib_dev, | |
186 | be32_to_cpu(ah->av->port_pd) >> 24, | |
f9e61929 | 187 | ah->av->gid_index % dev->limits.gid_table_len, |
1da177e4 LT |
188 | &header->grh.source_gid); |
189 | memcpy(header->grh.destination_gid.raw, | |
190 | ah->av->dgid, 16); | |
1da177e4 LT |
191 | } |
192 | ||
193 | return 0; | |
194 | } | |
195 | ||
1d89b1ae JM |
196 | int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr) |
197 | { | |
198 | struct mthca_ah *ah = to_mah(ibah); | |
199 | struct mthca_dev *dev = to_mdev(ibah->device); | |
200 | ||
201 | /* Only implement for MAD and memfree ah for now. */ | |
202 | if (ah->type == MTHCA_AH_ON_HCA) | |
203 | return -ENOSYS; | |
204 | ||
205 | memset(attr, 0, sizeof *attr); | |
206 | attr->dlid = be16_to_cpu(ah->av->dlid); | |
207 | attr->sl = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28; | |
208 | attr->static_rate = ah->av->msg_sr & 0x7; | |
209 | attr->src_path_bits = ah->av->g_slid & 0x7F; | |
210 | attr->port_num = be32_to_cpu(ah->av->port_pd) >> 24; | |
211 | attr->ah_flags = mthca_ah_grh_present(ah) ? IB_AH_GRH : 0; | |
212 | ||
213 | if (attr->ah_flags) { | |
214 | attr->grh.traffic_class = | |
215 | be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20; | |
216 | attr->grh.flow_label = | |
217 | be32_to_cpu(ah->av->sl_tclass_flowlabel) & 0xfffff; | |
218 | attr->grh.hop_limit = ah->av->hop_limit; | |
219 | attr->grh.sgid_index = ah->av->gid_index & | |
220 | (dev->limits.gid_table_len - 1); | |
221 | memcpy(attr->grh.dgid.raw, ah->av->dgid, 16); | |
222 | } | |
223 | ||
224 | return 0; | |
225 | } | |
226 | ||
1da177e4 LT |
227 | int __devinit mthca_init_av_table(struct mthca_dev *dev) |
228 | { | |
229 | int err; | |
230 | ||
d10ddbf6 | 231 | if (mthca_is_memfree(dev)) |
1da177e4 LT |
232 | return 0; |
233 | ||
234 | err = mthca_alloc_init(&dev->av_table.alloc, | |
235 | dev->av_table.num_ddr_avs, | |
236 | dev->av_table.num_ddr_avs - 1, | |
237 | 0); | |
238 | if (err) | |
239 | return err; | |
240 | ||
241 | dev->av_table.pool = pci_pool_create("mthca_av", dev->pdev, | |
242 | MTHCA_AV_SIZE, | |
243 | MTHCA_AV_SIZE, 0); | |
244 | if (!dev->av_table.pool) | |
245 | goto out_free_alloc; | |
246 | ||
247 | if (!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { | |
248 | dev->av_table.av_map = ioremap(pci_resource_start(dev->pdev, 4) + | |
249 | dev->av_table.ddr_av_base - | |
250 | dev->ddr_start, | |
251 | dev->av_table.num_ddr_avs * | |
252 | MTHCA_AV_SIZE); | |
253 | if (!dev->av_table.av_map) | |
254 | goto out_free_pool; | |
255 | } else | |
256 | dev->av_table.av_map = NULL; | |
257 | ||
258 | return 0; | |
259 | ||
260 | out_free_pool: | |
261 | pci_pool_destroy(dev->av_table.pool); | |
262 | ||
263 | out_free_alloc: | |
264 | mthca_alloc_cleanup(&dev->av_table.alloc); | |
265 | return -ENOMEM; | |
266 | } | |
267 | ||
e1f7868c | 268 | void mthca_cleanup_av_table(struct mthca_dev *dev) |
1da177e4 | 269 | { |
d10ddbf6 | 270 | if (mthca_is_memfree(dev)) |
1da177e4 LT |
271 | return; |
272 | ||
273 | if (dev->av_table.av_map) | |
274 | iounmap(dev->av_table.av_map); | |
275 | pci_pool_destroy(dev->av_table.pool); | |
276 | mthca_alloc_cleanup(&dev->av_table.alloc); | |
277 | } |