]>
Commit | Line | Data |
---|---|---|
1ac5a404 SX |
1 | /* |
2 | * Broadcom NetXtreme-E RoCE driver. | |
3 | * | |
4 | * Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term | |
5 | * Broadcom refers to Broadcom Limited and/or its subsidiaries. | |
6 | * | |
7 | * This software is available to you under a choice of one of two | |
8 | * licenses. You may choose to be licensed under the terms of the GNU | |
9 | * General Public License (GPL) Version 2, available from the file | |
10 | * COPYING in the main directory of this source tree, or the | |
11 | * BSD license below: | |
12 | * | |
13 | * Redistribution and use in source and binary forms, with or without | |
14 | * modification, are permitted provided that the following conditions | |
15 | * are met: | |
16 | * | |
17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in | |
21 | * the documentation and/or other materials provided with the | |
22 | * distribution. | |
23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' | |
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
26 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
27 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS | |
28 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | |
31 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
32 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |
33 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | |
34 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
35 | * | |
36 | * Description: Slow Path Operators | |
37 | */ | |
38 | ||
39 | #include <linux/interrupt.h> | |
40 | #include <linux/spinlock.h> | |
41 | #include <linux/sched.h> | |
42 | #include <linux/pci.h> | |
43 | ||
44 | #include "roce_hsi.h" | |
45 | ||
46 | #include "qplib_res.h" | |
47 | #include "qplib_rcfw.h" | |
48 | #include "qplib_sp.h" | |
49 | ||
50 | const struct bnxt_qplib_gid bnxt_qplib_gid_zero = {{ 0, 0, 0, 0, 0, 0, 0, 0, | |
51 | 0, 0, 0, 0, 0, 0, 0, 0 } }; | |
52 | ||
53 | /* Device */ | |
254cd259 DS |
54 | |
55 | static bool bnxt_qplib_is_atomic_cap(struct bnxt_qplib_rcfw *rcfw) | |
56 | { | |
57 | int rc; | |
58 | u16 pcie_ctl2; | |
59 | ||
60 | rc = pcie_capability_read_word(rcfw->pdev, PCI_EXP_DEVCTL2, | |
61 | &pcie_ctl2); | |
62 | if (rc) | |
63 | return false; | |
64 | return !!(pcie_ctl2 & PCI_EXP_DEVCTL2_ATOMIC_REQ); | |
65 | } | |
66 | ||
1ac5a404 SX |
67 | int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, |
68 | struct bnxt_qplib_dev_attr *attr) | |
69 | { | |
70 | struct cmdq_query_func req; | |
cc1ec769 DS |
71 | struct creq_query_func_resp resp; |
72 | struct bnxt_qplib_rcfw_sbuf *sbuf; | |
1ac5a404 SX |
73 | struct creq_query_func_resp_sb *sb; |
74 | u16 cmd_flags = 0; | |
75 | u32 temp; | |
76 | u8 *tqm_alloc; | |
cc1ec769 | 77 | int i, rc = 0; |
1ac5a404 SX |
78 | |
79 | RCFW_CMD_PREP(req, QUERY_FUNC, cmd_flags); | |
80 | ||
cc1ec769 DS |
81 | sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); |
82 | if (!sbuf) { | |
1ac5a404 | 83 | dev_err(&rcfw->pdev->dev, |
cc1ec769 DS |
84 | "QPLIB: SP: QUERY_FUNC alloc side buffer failed"); |
85 | return -ENOMEM; | |
1ac5a404 | 86 | } |
cc1ec769 DS |
87 | |
88 | sb = sbuf->sb; | |
89 | req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; | |
90 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, | |
91 | (void *)sbuf, 0); | |
92 | if (rc) | |
93 | goto bail; | |
94 | ||
1ac5a404 SX |
95 | /* Extract the context from the side buffer */ |
96 | attr->max_qp = le32_to_cpu(sb->max_qp); | |
58d4a671 SX |
97 | /* max_qp value reported by FW for PF doesn't include the QP1 for PF */ |
98 | attr->max_qp += 1; | |
1ac5a404 SX |
99 | attr->max_qp_rd_atom = |
100 | sb->max_qp_rd_atom > BNXT_QPLIB_MAX_OUT_RD_ATOM ? | |
101 | BNXT_QPLIB_MAX_OUT_RD_ATOM : sb->max_qp_rd_atom; | |
102 | attr->max_qp_init_rd_atom = | |
103 | sb->max_qp_init_rd_atom > BNXT_QPLIB_MAX_OUT_RD_ATOM ? | |
104 | BNXT_QPLIB_MAX_OUT_RD_ATOM : sb->max_qp_init_rd_atom; | |
105 | attr->max_qp_wqes = le16_to_cpu(sb->max_qp_wr); | |
9152e0b7 EW |
106 | /* |
107 | * 128 WQEs needs to be reserved for the HW (8916). Prevent | |
108 | * reporting the max number | |
109 | */ | |
110 | attr->max_qp_wqes -= BNXT_QPLIB_RESERVED_QP_WRS; | |
1ac5a404 SX |
111 | attr->max_qp_sges = sb->max_sge; |
112 | attr->max_cq = le32_to_cpu(sb->max_cq); | |
113 | attr->max_cq_wqes = le32_to_cpu(sb->max_cqe); | |
114 | attr->max_cq_sges = attr->max_qp_sges; | |
115 | attr->max_mr = le32_to_cpu(sb->max_mr); | |
116 | attr->max_mw = le32_to_cpu(sb->max_mw); | |
117 | ||
118 | attr->max_mr_size = le64_to_cpu(sb->max_mr_size); | |
119 | attr->max_pd = 64 * 1024; | |
120 | attr->max_raw_ethy_qp = le32_to_cpu(sb->max_raw_eth_qp); | |
121 | attr->max_ah = le32_to_cpu(sb->max_ah); | |
122 | ||
123 | attr->max_fmr = le32_to_cpu(sb->max_fmr); | |
124 | attr->max_map_per_fmr = sb->max_map_per_fmr; | |
125 | ||
126 | attr->max_srq = le16_to_cpu(sb->max_srq); | |
127 | attr->max_srq_wqes = le32_to_cpu(sb->max_srq_wr) - 1; | |
128 | attr->max_srq_sges = sb->max_srq_sge; | |
129 | /* Bono only reports 1 PKEY for now, but it can support > 1 */ | |
130 | attr->max_pkey = le32_to_cpu(sb->max_pkeys); | |
131 | ||
132 | attr->max_inline_data = le32_to_cpu(sb->max_inline_data); | |
133 | attr->l2_db_size = (sb->l2_db_space_size + 1) * PAGE_SIZE; | |
134 | attr->max_sgid = le32_to_cpu(sb->max_gid); | |
135 | ||
136 | strlcpy(attr->fw_ver, "20.6.28.0", sizeof(attr->fw_ver)); | |
137 | ||
138 | for (i = 0; i < MAX_TQM_ALLOC_REQ / 4; i++) { | |
139 | temp = le32_to_cpu(sb->tqm_alloc_reqs[i]); | |
140 | tqm_alloc = (u8 *)&temp; | |
141 | attr->tqm_alloc_reqs[i * 4] = *tqm_alloc; | |
142 | attr->tqm_alloc_reqs[i * 4 + 1] = *(++tqm_alloc); | |
143 | attr->tqm_alloc_reqs[i * 4 + 2] = *(++tqm_alloc); | |
144 | attr->tqm_alloc_reqs[i * 4 + 3] = *(++tqm_alloc); | |
145 | } | |
cc1ec769 | 146 | |
254cd259 | 147 | attr->is_atomic = bnxt_qplib_is_atomic_cap(rcfw); |
cc1ec769 DS |
148 | bail: |
149 | bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); | |
150 | return rc; | |
1ac5a404 SX |
151 | } |
152 | ||
153 | /* SGID */ | |
154 | int bnxt_qplib_get_sgid(struct bnxt_qplib_res *res, | |
155 | struct bnxt_qplib_sgid_tbl *sgid_tbl, int index, | |
156 | struct bnxt_qplib_gid *gid) | |
157 | { | |
158 | if (index > sgid_tbl->max) { | |
159 | dev_err(&res->pdev->dev, | |
160 | "QPLIB: Index %d exceeded SGID table max (%d)", | |
161 | index, sgid_tbl->max); | |
162 | return -EINVAL; | |
163 | } | |
164 | memcpy(gid, &sgid_tbl->tbl[index], sizeof(*gid)); | |
165 | return 0; | |
166 | } | |
167 | ||
168 | int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, | |
169 | struct bnxt_qplib_gid *gid, bool update) | |
170 | { | |
171 | struct bnxt_qplib_res *res = to_bnxt_qplib(sgid_tbl, | |
172 | struct bnxt_qplib_res, | |
173 | sgid_tbl); | |
174 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
175 | int index; | |
176 | ||
177 | if (!sgid_tbl) { | |
178 | dev_err(&res->pdev->dev, "QPLIB: SGID table not allocated"); | |
179 | return -EINVAL; | |
180 | } | |
181 | /* Do we need a sgid_lock here? */ | |
182 | if (!sgid_tbl->active) { | |
183 | dev_err(&res->pdev->dev, | |
184 | "QPLIB: SGID table has no active entries"); | |
185 | return -ENOMEM; | |
186 | } | |
187 | for (index = 0; index < sgid_tbl->max; index++) { | |
188 | if (!memcmp(&sgid_tbl->tbl[index], gid, sizeof(*gid))) | |
189 | break; | |
190 | } | |
191 | if (index == sgid_tbl->max) { | |
192 | dev_warn(&res->pdev->dev, "GID not found in the SGID table"); | |
193 | return 0; | |
194 | } | |
195 | /* Remove GID from the SGID table */ | |
196 | if (update) { | |
197 | struct cmdq_delete_gid req; | |
cc1ec769 | 198 | struct creq_delete_gid_resp resp; |
1ac5a404 | 199 | u16 cmd_flags = 0; |
cc1ec769 | 200 | int rc; |
1ac5a404 SX |
201 | |
202 | RCFW_CMD_PREP(req, DELETE_GID, cmd_flags); | |
203 | if (sgid_tbl->hw_id[index] == 0xFFFF) { | |
204 | dev_err(&res->pdev->dev, | |
205 | "QPLIB: GID entry contains an invalid HW id"); | |
206 | return -EINVAL; | |
207 | } | |
208 | req.gid_index = cpu_to_le16(sgid_tbl->hw_id[index]); | |
cc1ec769 DS |
209 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
210 | (void *)&resp, NULL, 0); | |
211 | if (rc) | |
212 | return rc; | |
1ac5a404 SX |
213 | } |
214 | memcpy(&sgid_tbl->tbl[index], &bnxt_qplib_gid_zero, | |
215 | sizeof(bnxt_qplib_gid_zero)); | |
216 | sgid_tbl->active--; | |
217 | dev_dbg(&res->pdev->dev, | |
218 | "QPLIB: SGID deleted hw_id[0x%x] = 0x%x active = 0x%x", | |
219 | index, sgid_tbl->hw_id[index], sgid_tbl->active); | |
220 | sgid_tbl->hw_id[index] = (u16)-1; | |
221 | ||
222 | /* unlock */ | |
223 | return 0; | |
224 | } | |
225 | ||
226 | int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, | |
227 | struct bnxt_qplib_gid *gid, u8 *smac, u16 vlan_id, | |
228 | bool update, u32 *index) | |
229 | { | |
230 | struct bnxt_qplib_res *res = to_bnxt_qplib(sgid_tbl, | |
231 | struct bnxt_qplib_res, | |
232 | sgid_tbl); | |
233 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
cc1ec769 | 234 | int i, free_idx; |
1ac5a404 SX |
235 | |
236 | if (!sgid_tbl) { | |
237 | dev_err(&res->pdev->dev, "QPLIB: SGID table not allocated"); | |
238 | return -EINVAL; | |
239 | } | |
240 | /* Do we need a sgid_lock here? */ | |
241 | if (sgid_tbl->active == sgid_tbl->max) { | |
242 | dev_err(&res->pdev->dev, "QPLIB: SGID table is full"); | |
243 | return -ENOMEM; | |
244 | } | |
245 | free_idx = sgid_tbl->max; | |
246 | for (i = 0; i < sgid_tbl->max; i++) { | |
247 | if (!memcmp(&sgid_tbl->tbl[i], gid, sizeof(*gid))) { | |
248 | dev_dbg(&res->pdev->dev, | |
249 | "QPLIB: SGID entry already exist in entry %d!", | |
250 | i); | |
251 | *index = i; | |
252 | return -EALREADY; | |
253 | } else if (!memcmp(&sgid_tbl->tbl[i], &bnxt_qplib_gid_zero, | |
254 | sizeof(bnxt_qplib_gid_zero)) && | |
255 | free_idx == sgid_tbl->max) { | |
256 | free_idx = i; | |
257 | } | |
258 | } | |
259 | if (free_idx == sgid_tbl->max) { | |
260 | dev_err(&res->pdev->dev, | |
261 | "QPLIB: SGID table is FULL but count is not MAX??"); | |
262 | return -ENOMEM; | |
263 | } | |
264 | if (update) { | |
265 | struct cmdq_add_gid req; | |
cc1ec769 | 266 | struct creq_add_gid_resp resp; |
1ac5a404 SX |
267 | u16 cmd_flags = 0; |
268 | u32 temp32[4]; | |
269 | u16 temp16[3]; | |
cc1ec769 | 270 | int rc; |
1ac5a404 SX |
271 | |
272 | RCFW_CMD_PREP(req, ADD_GID, cmd_flags); | |
273 | ||
274 | memcpy(temp32, gid->data, sizeof(struct bnxt_qplib_gid)); | |
275 | req.gid[0] = cpu_to_be32(temp32[3]); | |
276 | req.gid[1] = cpu_to_be32(temp32[2]); | |
277 | req.gid[2] = cpu_to_be32(temp32[1]); | |
278 | req.gid[3] = cpu_to_be32(temp32[0]); | |
279 | if (vlan_id != 0xFFFF) | |
280 | req.vlan = cpu_to_le16((vlan_id & | |
281 | CMDQ_ADD_GID_VLAN_VLAN_ID_MASK) | | |
282 | CMDQ_ADD_GID_VLAN_TPID_TPID_8100 | | |
283 | CMDQ_ADD_GID_VLAN_VLAN_EN); | |
284 | ||
285 | /* MAC in network format */ | |
286 | memcpy(temp16, smac, 6); | |
287 | req.src_mac[0] = cpu_to_be16(temp16[0]); | |
288 | req.src_mac[1] = cpu_to_be16(temp16[1]); | |
289 | req.src_mac[2] = cpu_to_be16(temp16[2]); | |
290 | ||
cc1ec769 DS |
291 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
292 | (void *)&resp, NULL, 0); | |
293 | if (rc) | |
294 | return rc; | |
295 | sgid_tbl->hw_id[free_idx] = le32_to_cpu(resp.xid); | |
1ac5a404 SX |
296 | } |
297 | /* Add GID to the sgid_tbl */ | |
298 | memcpy(&sgid_tbl->tbl[free_idx], gid, sizeof(*gid)); | |
299 | sgid_tbl->active++; | |
300 | dev_dbg(&res->pdev->dev, | |
301 | "QPLIB: SGID added hw_id[0x%x] = 0x%x active = 0x%x", | |
302 | free_idx, sgid_tbl->hw_id[free_idx], sgid_tbl->active); | |
303 | ||
304 | *index = free_idx; | |
305 | /* unlock */ | |
cc1ec769 | 306 | return 0; |
1ac5a404 SX |
307 | } |
308 | ||
309 | /* pkeys */ | |
310 | int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res, | |
311 | struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 index, | |
312 | u16 *pkey) | |
313 | { | |
314 | if (index == 0xFFFF) { | |
315 | *pkey = 0xFFFF; | |
316 | return 0; | |
317 | } | |
318 | if (index > pkey_tbl->max) { | |
319 | dev_err(&res->pdev->dev, | |
320 | "QPLIB: Index %d exceeded PKEY table max (%d)", | |
321 | index, pkey_tbl->max); | |
322 | return -EINVAL; | |
323 | } | |
324 | memcpy(pkey, &pkey_tbl->tbl[index], sizeof(*pkey)); | |
325 | return 0; | |
326 | } | |
327 | ||
328 | int bnxt_qplib_del_pkey(struct bnxt_qplib_res *res, | |
329 | struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 *pkey, | |
330 | bool update) | |
331 | { | |
332 | int i, rc = 0; | |
333 | ||
334 | if (!pkey_tbl) { | |
335 | dev_err(&res->pdev->dev, "QPLIB: PKEY table not allocated"); | |
336 | return -EINVAL; | |
337 | } | |
338 | ||
339 | /* Do we need a pkey_lock here? */ | |
340 | if (!pkey_tbl->active) { | |
341 | dev_err(&res->pdev->dev, | |
342 | "QPLIB: PKEY table has no active entries"); | |
343 | return -ENOMEM; | |
344 | } | |
345 | for (i = 0; i < pkey_tbl->max; i++) { | |
346 | if (!memcmp(&pkey_tbl->tbl[i], pkey, sizeof(*pkey))) | |
347 | break; | |
348 | } | |
349 | if (i == pkey_tbl->max) { | |
350 | dev_err(&res->pdev->dev, | |
351 | "QPLIB: PKEY 0x%04x not found in the pkey table", | |
352 | *pkey); | |
353 | return -ENOMEM; | |
354 | } | |
355 | memset(&pkey_tbl->tbl[i], 0, sizeof(*pkey)); | |
356 | pkey_tbl->active--; | |
357 | ||
358 | /* unlock */ | |
359 | return rc; | |
360 | } | |
361 | ||
362 | int bnxt_qplib_add_pkey(struct bnxt_qplib_res *res, | |
363 | struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 *pkey, | |
364 | bool update) | |
365 | { | |
366 | int i, free_idx, rc = 0; | |
367 | ||
368 | if (!pkey_tbl) { | |
369 | dev_err(&res->pdev->dev, "QPLIB: PKEY table not allocated"); | |
370 | return -EINVAL; | |
371 | } | |
372 | ||
373 | /* Do we need a pkey_lock here? */ | |
374 | if (pkey_tbl->active == pkey_tbl->max) { | |
375 | dev_err(&res->pdev->dev, "QPLIB: PKEY table is full"); | |
376 | return -ENOMEM; | |
377 | } | |
378 | free_idx = pkey_tbl->max; | |
379 | for (i = 0; i < pkey_tbl->max; i++) { | |
380 | if (!memcmp(&pkey_tbl->tbl[i], pkey, sizeof(*pkey))) | |
381 | return -EALREADY; | |
382 | else if (!pkey_tbl->tbl[i] && free_idx == pkey_tbl->max) | |
383 | free_idx = i; | |
384 | } | |
385 | if (free_idx == pkey_tbl->max) { | |
386 | dev_err(&res->pdev->dev, | |
387 | "QPLIB: PKEY table is FULL but count is not MAX??"); | |
388 | return -ENOMEM; | |
389 | } | |
390 | /* Add PKEY to the pkey_tbl */ | |
391 | memcpy(&pkey_tbl->tbl[free_idx], pkey, sizeof(*pkey)); | |
392 | pkey_tbl->active++; | |
393 | ||
394 | /* unlock */ | |
395 | return rc; | |
396 | } | |
397 | ||
398 | /* AH */ | |
399 | int bnxt_qplib_create_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah) | |
400 | { | |
401 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
402 | struct cmdq_create_ah req; | |
cc1ec769 | 403 | struct creq_create_ah_resp resp; |
1ac5a404 SX |
404 | u16 cmd_flags = 0; |
405 | u32 temp32[4]; | |
406 | u16 temp16[3]; | |
cc1ec769 | 407 | int rc; |
1ac5a404 SX |
408 | |
409 | RCFW_CMD_PREP(req, CREATE_AH, cmd_flags); | |
410 | ||
411 | memcpy(temp32, ah->dgid.data, sizeof(struct bnxt_qplib_gid)); | |
412 | req.dgid[0] = cpu_to_le32(temp32[0]); | |
413 | req.dgid[1] = cpu_to_le32(temp32[1]); | |
414 | req.dgid[2] = cpu_to_le32(temp32[2]); | |
415 | req.dgid[3] = cpu_to_le32(temp32[3]); | |
416 | ||
417 | req.type = ah->nw_type; | |
418 | req.hop_limit = ah->hop_limit; | |
419 | req.sgid_index = cpu_to_le16(res->sgid_tbl.hw_id[ah->sgid_index]); | |
420 | req.dest_vlan_id_flow_label = cpu_to_le32((ah->flow_label & | |
421 | CMDQ_CREATE_AH_FLOW_LABEL_MASK) | | |
422 | CMDQ_CREATE_AH_DEST_VLAN_ID_MASK); | |
423 | req.pd_id = cpu_to_le32(ah->pd->id); | |
424 | req.traffic_class = ah->traffic_class; | |
425 | ||
426 | /* MAC in network format */ | |
427 | memcpy(temp16, ah->dmac, 6); | |
428 | req.dest_mac[0] = cpu_to_le16(temp16[0]); | |
429 | req.dest_mac[1] = cpu_to_le16(temp16[1]); | |
430 | req.dest_mac[2] = cpu_to_le16(temp16[2]); | |
431 | ||
cc1ec769 DS |
432 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, |
433 | NULL, 1); | |
434 | if (rc) | |
435 | return rc; | |
436 | ||
437 | ah->id = le32_to_cpu(resp.xid); | |
1ac5a404 SX |
438 | return 0; |
439 | } | |
440 | ||
441 | int bnxt_qplib_destroy_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah) | |
442 | { | |
443 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
444 | struct cmdq_destroy_ah req; | |
cc1ec769 | 445 | struct creq_destroy_ah_resp resp; |
1ac5a404 | 446 | u16 cmd_flags = 0; |
cc1ec769 | 447 | int rc; |
1ac5a404 SX |
448 | |
449 | /* Clean up the AH table in the device */ | |
450 | RCFW_CMD_PREP(req, DESTROY_AH, cmd_flags); | |
451 | ||
452 | req.ah_cid = cpu_to_le32(ah->id); | |
453 | ||
cc1ec769 DS |
454 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, |
455 | NULL, 1); | |
456 | if (rc) | |
457 | return rc; | |
1ac5a404 SX |
458 | return 0; |
459 | } | |
460 | ||
461 | /* MRW */ | |
462 | int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) | |
463 | { | |
464 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
465 | struct cmdq_deallocate_key req; | |
cc1ec769 | 466 | struct creq_deallocate_key_resp resp; |
1ac5a404 | 467 | u16 cmd_flags = 0; |
cc1ec769 | 468 | int rc; |
1ac5a404 SX |
469 | |
470 | if (mrw->lkey == 0xFFFFFFFF) { | |
471 | dev_info(&res->pdev->dev, | |
472 | "QPLIB: SP: Free a reserved lkey MRW"); | |
473 | return 0; | |
474 | } | |
475 | ||
476 | RCFW_CMD_PREP(req, DEALLOCATE_KEY, cmd_flags); | |
477 | ||
478 | req.mrw_flags = mrw->type; | |
479 | ||
480 | if ((mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE1) || | |
481 | (mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A) || | |
482 | (mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B)) | |
483 | req.key = cpu_to_le32(mrw->rkey); | |
484 | else | |
485 | req.key = cpu_to_le32(mrw->lkey); | |
486 | ||
cc1ec769 DS |
487 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, |
488 | NULL, 0); | |
489 | if (rc) | |
490 | return rc; | |
491 | ||
1ac5a404 SX |
492 | /* Free the qplib's MRW memory */ |
493 | if (mrw->hwq.max_elements) | |
494 | bnxt_qplib_free_hwq(res->pdev, &mrw->hwq); | |
495 | ||
496 | return 0; | |
497 | } | |
498 | ||
499 | int bnxt_qplib_alloc_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) | |
500 | { | |
501 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
502 | struct cmdq_allocate_mrw req; | |
cc1ec769 | 503 | struct creq_allocate_mrw_resp resp; |
1ac5a404 SX |
504 | u16 cmd_flags = 0; |
505 | unsigned long tmp; | |
cc1ec769 | 506 | int rc; |
1ac5a404 SX |
507 | |
508 | RCFW_CMD_PREP(req, ALLOCATE_MRW, cmd_flags); | |
509 | ||
510 | req.pd_id = cpu_to_le32(mrw->pd->id); | |
511 | req.mrw_flags = mrw->type; | |
512 | if ((mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_PMR && | |
513 | mrw->flags & BNXT_QPLIB_FR_PMR) || | |
514 | mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A || | |
515 | mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B) | |
516 | req.access = CMDQ_ALLOCATE_MRW_ACCESS_CONSUMER_OWNED_KEY; | |
517 | tmp = (unsigned long)mrw; | |
518 | req.mrw_handle = cpu_to_le64(tmp); | |
519 | ||
cc1ec769 DS |
520 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
521 | (void *)&resp, NULL, 0); | |
522 | if (rc) | |
523 | return rc; | |
524 | ||
1ac5a404 SX |
525 | if ((mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE1) || |
526 | (mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A) || | |
527 | (mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B)) | |
cc1ec769 | 528 | mrw->rkey = le32_to_cpu(resp.xid); |
1ac5a404 | 529 | else |
cc1ec769 | 530 | mrw->lkey = le32_to_cpu(resp.xid); |
1ac5a404 SX |
531 | return 0; |
532 | } | |
533 | ||
534 | int bnxt_qplib_dereg_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw, | |
535 | bool block) | |
536 | { | |
537 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
538 | struct cmdq_deregister_mr req; | |
cc1ec769 | 539 | struct creq_deregister_mr_resp resp; |
1ac5a404 SX |
540 | u16 cmd_flags = 0; |
541 | int rc; | |
542 | ||
543 | RCFW_CMD_PREP(req, DEREGISTER_MR, cmd_flags); | |
544 | ||
545 | req.lkey = cpu_to_le32(mrw->lkey); | |
cc1ec769 DS |
546 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
547 | (void *)&resp, NULL, block); | |
548 | if (rc) | |
549 | return rc; | |
1ac5a404 SX |
550 | |
551 | /* Free the qplib's MR memory */ | |
552 | if (mrw->hwq.max_elements) { | |
553 | mrw->va = 0; | |
554 | mrw->total_size = 0; | |
555 | bnxt_qplib_free_hwq(res->pdev, &mrw->hwq); | |
556 | } | |
557 | ||
558 | return 0; | |
559 | } | |
560 | ||
561 | int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, | |
562 | u64 *pbl_tbl, int num_pbls, bool block) | |
563 | { | |
564 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
565 | struct cmdq_register_mr req; | |
cc1ec769 | 566 | struct creq_register_mr_resp resp; |
1ac5a404 SX |
567 | u16 cmd_flags = 0, level; |
568 | int pg_ptrs, pages, i, rc; | |
569 | dma_addr_t **pbl_ptr; | |
570 | u32 pg_size; | |
571 | ||
572 | if (num_pbls) { | |
573 | pg_ptrs = roundup_pow_of_two(num_pbls); | |
574 | pages = pg_ptrs >> MAX_PBL_LVL_1_PGS_SHIFT; | |
575 | if (!pages) | |
576 | pages++; | |
577 | ||
578 | if (pages > MAX_PBL_LVL_1_PGS) { | |
579 | dev_err(&res->pdev->dev, "QPLIB: SP: Reg MR pages "); | |
580 | dev_err(&res->pdev->dev, | |
581 | "requested (0x%x) exceeded max (0x%x)", | |
582 | pages, MAX_PBL_LVL_1_PGS); | |
583 | return -ENOMEM; | |
584 | } | |
585 | /* Free the hwq if it already exist, must be a rereg */ | |
586 | if (mr->hwq.max_elements) | |
587 | bnxt_qplib_free_hwq(res->pdev, &mr->hwq); | |
588 | ||
589 | mr->hwq.max_elements = pages; | |
590 | rc = bnxt_qplib_alloc_init_hwq(res->pdev, &mr->hwq, NULL, 0, | |
591 | &mr->hwq.max_elements, | |
592 | PAGE_SIZE, 0, PAGE_SIZE, | |
593 | HWQ_TYPE_CTX); | |
594 | if (rc) { | |
595 | dev_err(&res->pdev->dev, | |
596 | "SP: Reg MR memory allocation failed"); | |
597 | return -ENOMEM; | |
598 | } | |
599 | /* Write to the hwq */ | |
600 | pbl_ptr = (dma_addr_t **)mr->hwq.pbl_ptr; | |
601 | for (i = 0; i < num_pbls; i++) | |
602 | pbl_ptr[PTR_PG(i)][PTR_IDX(i)] = | |
603 | (pbl_tbl[i] & PAGE_MASK) | PTU_PTE_VALID; | |
604 | } | |
605 | ||
606 | RCFW_CMD_PREP(req, REGISTER_MR, cmd_flags); | |
607 | ||
608 | /* Configure the request */ | |
609 | if (mr->hwq.level == PBL_LVL_MAX) { | |
610 | level = 0; | |
611 | req.pbl = 0; | |
612 | pg_size = PAGE_SIZE; | |
613 | } else { | |
614 | level = mr->hwq.level + 1; | |
615 | req.pbl = cpu_to_le64(mr->hwq.pbl[PBL_LVL_0].pg_map_arr[0]); | |
616 | pg_size = mr->hwq.pbl[PBL_LVL_0].pg_size; | |
617 | } | |
618 | req.log2_pg_size_lvl = (level << CMDQ_REGISTER_MR_LVL_SFT) | | |
619 | ((ilog2(pg_size) << | |
620 | CMDQ_REGISTER_MR_LOG2_PG_SIZE_SFT) & | |
621 | CMDQ_REGISTER_MR_LOG2_PG_SIZE_MASK); | |
622 | req.access = (mr->flags & 0xFFFF); | |
623 | req.va = cpu_to_le64(mr->va); | |
624 | req.key = cpu_to_le32(mr->lkey); | |
625 | req.mr_size = cpu_to_le64(mr->total_size); | |
626 | ||
cc1ec769 DS |
627 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
628 | (void *)&resp, NULL, block); | |
629 | if (rc) | |
1ac5a404 | 630 | goto fail; |
cc1ec769 | 631 | |
1ac5a404 SX |
632 | return 0; |
633 | ||
634 | fail: | |
635 | if (mr->hwq.max_elements) | |
636 | bnxt_qplib_free_hwq(res->pdev, &mr->hwq); | |
637 | return rc; | |
638 | } | |
639 | ||
640 | int bnxt_qplib_alloc_fast_reg_page_list(struct bnxt_qplib_res *res, | |
641 | struct bnxt_qplib_frpl *frpl, | |
642 | int max_pg_ptrs) | |
643 | { | |
644 | int pg_ptrs, pages, rc; | |
645 | ||
646 | /* Re-calculate the max to fit the HWQ allocation model */ | |
647 | pg_ptrs = roundup_pow_of_two(max_pg_ptrs); | |
648 | pages = pg_ptrs >> MAX_PBL_LVL_1_PGS_SHIFT; | |
649 | if (!pages) | |
650 | pages++; | |
651 | ||
652 | if (pages > MAX_PBL_LVL_1_PGS) | |
653 | return -ENOMEM; | |
654 | ||
655 | frpl->hwq.max_elements = pages; | |
656 | rc = bnxt_qplib_alloc_init_hwq(res->pdev, &frpl->hwq, NULL, 0, | |
657 | &frpl->hwq.max_elements, PAGE_SIZE, 0, | |
658 | PAGE_SIZE, HWQ_TYPE_CTX); | |
659 | if (!rc) | |
660 | frpl->max_pg_ptrs = pg_ptrs; | |
661 | ||
662 | return rc; | |
663 | } | |
664 | ||
665 | int bnxt_qplib_free_fast_reg_page_list(struct bnxt_qplib_res *res, | |
666 | struct bnxt_qplib_frpl *frpl) | |
667 | { | |
668 | bnxt_qplib_free_hwq(res->pdev, &frpl->hwq); | |
669 | return 0; | |
670 | } | |
671 | ||
672 | int bnxt_qplib_map_tc2cos(struct bnxt_qplib_res *res, u16 *cids) | |
673 | { | |
674 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
675 | struct cmdq_map_tc_to_cos req; | |
cc1ec769 | 676 | struct creq_map_tc_to_cos_resp resp; |
1ac5a404 | 677 | u16 cmd_flags = 0; |
cc1ec769 | 678 | int rc = 0; |
1ac5a404 SX |
679 | |
680 | RCFW_CMD_PREP(req, MAP_TC_TO_COS, cmd_flags); | |
681 | req.cos0 = cpu_to_le16(cids[0]); | |
682 | req.cos1 = cpu_to_le16(cids[1]); | |
683 | ||
cc1ec769 DS |
684 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
685 | (void *)&resp, NULL, 0); | |
1ac5a404 SX |
686 | return 0; |
687 | } |