]>
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 | ||
08920b8f JP |
39 | #define dev_fmt(fmt) "QPLIB: " fmt |
40 | ||
1ac5a404 SX |
41 | #include <linux/interrupt.h> |
42 | #include <linux/spinlock.h> | |
43 | #include <linux/sched.h> | |
44 | #include <linux/pci.h> | |
45 | ||
46 | #include "roce_hsi.h" | |
47 | ||
48 | #include "qplib_res.h" | |
49 | #include "qplib_rcfw.h" | |
50 | #include "qplib_sp.h" | |
51 | ||
52 | const struct bnxt_qplib_gid bnxt_qplib_gid_zero = {{ 0, 0, 0, 0, 0, 0, 0, 0, | |
53 | 0, 0, 0, 0, 0, 0, 0, 0 } }; | |
54 | ||
55 | /* Device */ | |
254cd259 | 56 | |
2fc68543 SX |
57 | static void bnxt_qplib_query_version(struct bnxt_qplib_rcfw *rcfw, |
58 | char *fw_ver) | |
59 | { | |
60 | struct cmdq_query_version req; | |
61 | struct creq_query_version_resp resp; | |
62 | u16 cmd_flags = 0; | |
63 | int rc = 0; | |
64 | ||
65 | RCFW_CMD_PREP(req, QUERY_VERSION, cmd_flags); | |
66 | ||
67 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, | |
68 | (void *)&resp, NULL, 0); | |
69 | if (rc) | |
70 | return; | |
71 | fw_ver[0] = resp.fw_maj; | |
72 | fw_ver[1] = resp.fw_minor; | |
73 | fw_ver[2] = resp.fw_bld; | |
74 | fw_ver[3] = resp.fw_rsvd; | |
75 | } | |
76 | ||
1ac5a404 | 77 | int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, |
ccd9d0d3 | 78 | struct bnxt_qplib_dev_attr *attr, bool vf) |
1ac5a404 SX |
79 | { |
80 | struct cmdq_query_func req; | |
cc1ec769 DS |
81 | struct creq_query_func_resp resp; |
82 | struct bnxt_qplib_rcfw_sbuf *sbuf; | |
1ac5a404 SX |
83 | struct creq_query_func_resp_sb *sb; |
84 | u16 cmd_flags = 0; | |
85 | u32 temp; | |
86 | u8 *tqm_alloc; | |
cc1ec769 | 87 | int i, rc = 0; |
1ac5a404 SX |
88 | |
89 | RCFW_CMD_PREP(req, QUERY_FUNC, cmd_flags); | |
90 | ||
cc1ec769 DS |
91 | sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); |
92 | if (!sbuf) { | |
1ac5a404 | 93 | dev_err(&rcfw->pdev->dev, |
08920b8f | 94 | "SP: QUERY_FUNC alloc side buffer failed\n"); |
cc1ec769 | 95 | return -ENOMEM; |
1ac5a404 | 96 | } |
cc1ec769 DS |
97 | |
98 | sb = sbuf->sb; | |
99 | req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; | |
100 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, | |
101 | (void *)sbuf, 0); | |
102 | if (rc) | |
103 | goto bail; | |
104 | ||
1ac5a404 SX |
105 | /* Extract the context from the side buffer */ |
106 | attr->max_qp = le32_to_cpu(sb->max_qp); | |
58d4a671 | 107 | /* max_qp value reported by FW for PF doesn't include the QP1 for PF */ |
ccd9d0d3 SX |
108 | if (!vf) |
109 | attr->max_qp += 1; | |
1ac5a404 SX |
110 | attr->max_qp_rd_atom = |
111 | sb->max_qp_rd_atom > BNXT_QPLIB_MAX_OUT_RD_ATOM ? | |
112 | BNXT_QPLIB_MAX_OUT_RD_ATOM : sb->max_qp_rd_atom; | |
113 | attr->max_qp_init_rd_atom = | |
114 | sb->max_qp_init_rd_atom > BNXT_QPLIB_MAX_OUT_RD_ATOM ? | |
115 | BNXT_QPLIB_MAX_OUT_RD_ATOM : sb->max_qp_init_rd_atom; | |
116 | attr->max_qp_wqes = le16_to_cpu(sb->max_qp_wr); | |
9152e0b7 EW |
117 | /* |
118 | * 128 WQEs needs to be reserved for the HW (8916). Prevent | |
119 | * reporting the max number | |
120 | */ | |
121 | attr->max_qp_wqes -= BNXT_QPLIB_RESERVED_QP_WRS; | |
1ac5a404 SX |
122 | attr->max_qp_sges = sb->max_sge; |
123 | attr->max_cq = le32_to_cpu(sb->max_cq); | |
124 | attr->max_cq_wqes = le32_to_cpu(sb->max_cqe); | |
125 | attr->max_cq_sges = attr->max_qp_sges; | |
126 | attr->max_mr = le32_to_cpu(sb->max_mr); | |
127 | attr->max_mw = le32_to_cpu(sb->max_mw); | |
128 | ||
129 | attr->max_mr_size = le64_to_cpu(sb->max_mr_size); | |
130 | attr->max_pd = 64 * 1024; | |
131 | attr->max_raw_ethy_qp = le32_to_cpu(sb->max_raw_eth_qp); | |
132 | attr->max_ah = le32_to_cpu(sb->max_ah); | |
133 | ||
134 | attr->max_fmr = le32_to_cpu(sb->max_fmr); | |
135 | attr->max_map_per_fmr = sb->max_map_per_fmr; | |
136 | ||
137 | attr->max_srq = le16_to_cpu(sb->max_srq); | |
138 | attr->max_srq_wqes = le32_to_cpu(sb->max_srq_wr) - 1; | |
139 | attr->max_srq_sges = sb->max_srq_sge; | |
1ac5a404 | 140 | attr->max_pkey = le32_to_cpu(sb->max_pkeys); |
854a2020 DS |
141 | /* |
142 | * Some versions of FW reports more than 0xFFFF. | |
143 | * Restrict it for now to 0xFFFF to avoid | |
144 | * reporting trucated value | |
145 | */ | |
146 | if (attr->max_pkey > 0xFFFF) { | |
147 | /* ib_port_attr::pkey_tbl_len is u16 */ | |
148 | attr->max_pkey = 0xFFFF; | |
149 | } | |
1ac5a404 SX |
150 | |
151 | attr->max_inline_data = le32_to_cpu(sb->max_inline_data); | |
c354dff0 DS |
152 | attr->l2_db_size = (sb->l2_db_space_size + 1) * |
153 | (0x01 << RCFW_DBR_BASE_PAGE_SHIFT); | |
1ac5a404 SX |
154 | attr->max_sgid = le32_to_cpu(sb->max_gid); |
155 | ||
2fc68543 | 156 | bnxt_qplib_query_version(rcfw, attr->fw_ver); |
1ac5a404 SX |
157 | |
158 | for (i = 0; i < MAX_TQM_ALLOC_REQ / 4; i++) { | |
159 | temp = le32_to_cpu(sb->tqm_alloc_reqs[i]); | |
160 | tqm_alloc = (u8 *)&temp; | |
161 | attr->tqm_alloc_reqs[i * 4] = *tqm_alloc; | |
162 | attr->tqm_alloc_reqs[i * 4 + 1] = *(++tqm_alloc); | |
163 | attr->tqm_alloc_reqs[i * 4 + 2] = *(++tqm_alloc); | |
164 | attr->tqm_alloc_reqs[i * 4 + 3] = *(++tqm_alloc); | |
165 | } | |
cc1ec769 | 166 | |
63231585 | 167 | attr->is_atomic = false; |
cc1ec769 DS |
168 | bail: |
169 | bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); | |
170 | return rc; | |
ccd9d0d3 SX |
171 | } |
172 | ||
173 | int bnxt_qplib_set_func_resources(struct bnxt_qplib_res *res, | |
174 | struct bnxt_qplib_rcfw *rcfw, | |
175 | struct bnxt_qplib_ctx *ctx) | |
176 | { | |
177 | struct cmdq_set_func_resources req; | |
178 | struct creq_set_func_resources_resp resp; | |
179 | u16 cmd_flags = 0; | |
180 | int rc = 0; | |
181 | ||
182 | RCFW_CMD_PREP(req, SET_FUNC_RESOURCES, cmd_flags); | |
183 | ||
184 | req.number_of_qp = cpu_to_le32(ctx->qpc_count); | |
185 | req.number_of_mrw = cpu_to_le32(ctx->mrw_count); | |
186 | req.number_of_srq = cpu_to_le32(ctx->srqc_count); | |
187 | req.number_of_cq = cpu_to_le32(ctx->cq_count); | |
188 | ||
189 | req.max_qp_per_vf = cpu_to_le32(ctx->vf_res.max_qp_per_vf); | |
190 | req.max_mrw_per_vf = cpu_to_le32(ctx->vf_res.max_mrw_per_vf); | |
191 | req.max_srq_per_vf = cpu_to_le32(ctx->vf_res.max_srq_per_vf); | |
192 | req.max_cq_per_vf = cpu_to_le32(ctx->vf_res.max_cq_per_vf); | |
193 | req.max_gid_per_vf = cpu_to_le32(ctx->vf_res.max_gid_per_vf); | |
194 | ||
195 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, | |
196 | (void *)&resp, | |
197 | NULL, 0); | |
198 | if (rc) { | |
08920b8f | 199 | dev_err(&res->pdev->dev, "Failed to set function resources\n"); |
ccd9d0d3 SX |
200 | } |
201 | return rc; | |
1ac5a404 SX |
202 | } |
203 | ||
204 | /* SGID */ | |
205 | int bnxt_qplib_get_sgid(struct bnxt_qplib_res *res, | |
206 | struct bnxt_qplib_sgid_tbl *sgid_tbl, int index, | |
207 | struct bnxt_qplib_gid *gid) | |
208 | { | |
474e5a86 | 209 | if (index >= sgid_tbl->max) { |
1ac5a404 | 210 | dev_err(&res->pdev->dev, |
08920b8f | 211 | "Index %d exceeded SGID table max (%d)\n", |
1ac5a404 SX |
212 | index, sgid_tbl->max); |
213 | return -EINVAL; | |
214 | } | |
215 | memcpy(gid, &sgid_tbl->tbl[index], sizeof(*gid)); | |
216 | return 0; | |
217 | } | |
218 | ||
219 | int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, | |
220 | struct bnxt_qplib_gid *gid, bool update) | |
221 | { | |
222 | struct bnxt_qplib_res *res = to_bnxt_qplib(sgid_tbl, | |
223 | struct bnxt_qplib_res, | |
224 | sgid_tbl); | |
225 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
226 | int index; | |
227 | ||
228 | if (!sgid_tbl) { | |
08920b8f | 229 | dev_err(&res->pdev->dev, "SGID table not allocated\n"); |
1ac5a404 SX |
230 | return -EINVAL; |
231 | } | |
232 | /* Do we need a sgid_lock here? */ | |
233 | if (!sgid_tbl->active) { | |
08920b8f | 234 | dev_err(&res->pdev->dev, "SGID table has no active entries\n"); |
1ac5a404 SX |
235 | return -ENOMEM; |
236 | } | |
237 | for (index = 0; index < sgid_tbl->max; index++) { | |
238 | if (!memcmp(&sgid_tbl->tbl[index], gid, sizeof(*gid))) | |
239 | break; | |
240 | } | |
241 | if (index == sgid_tbl->max) { | |
08920b8f | 242 | dev_warn(&res->pdev->dev, "GID not found in the SGID table\n"); |
1ac5a404 SX |
243 | return 0; |
244 | } | |
245 | /* Remove GID from the SGID table */ | |
246 | if (update) { | |
247 | struct cmdq_delete_gid req; | |
cc1ec769 | 248 | struct creq_delete_gid_resp resp; |
1ac5a404 | 249 | u16 cmd_flags = 0; |
cc1ec769 | 250 | int rc; |
1ac5a404 SX |
251 | |
252 | RCFW_CMD_PREP(req, DELETE_GID, cmd_flags); | |
253 | if (sgid_tbl->hw_id[index] == 0xFFFF) { | |
254 | dev_err(&res->pdev->dev, | |
08920b8f | 255 | "GID entry contains an invalid HW id\n"); |
1ac5a404 SX |
256 | return -EINVAL; |
257 | } | |
258 | req.gid_index = cpu_to_le16(sgid_tbl->hw_id[index]); | |
cc1ec769 DS |
259 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
260 | (void *)&resp, NULL, 0); | |
261 | if (rc) | |
262 | return rc; | |
1ac5a404 SX |
263 | } |
264 | memcpy(&sgid_tbl->tbl[index], &bnxt_qplib_gid_zero, | |
265 | sizeof(bnxt_qplib_gid_zero)); | |
5fac5b1b | 266 | sgid_tbl->vlan[index] = 0; |
1ac5a404 SX |
267 | sgid_tbl->active--; |
268 | dev_dbg(&res->pdev->dev, | |
08920b8f | 269 | "SGID deleted hw_id[0x%x] = 0x%x active = 0x%x\n", |
1ac5a404 SX |
270 | index, sgid_tbl->hw_id[index], sgid_tbl->active); |
271 | sgid_tbl->hw_id[index] = (u16)-1; | |
272 | ||
273 | /* unlock */ | |
274 | return 0; | |
275 | } | |
276 | ||
277 | int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, | |
278 | struct bnxt_qplib_gid *gid, u8 *smac, u16 vlan_id, | |
279 | bool update, u32 *index) | |
280 | { | |
281 | struct bnxt_qplib_res *res = to_bnxt_qplib(sgid_tbl, | |
282 | struct bnxt_qplib_res, | |
283 | sgid_tbl); | |
284 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
cc1ec769 | 285 | int i, free_idx; |
1ac5a404 SX |
286 | |
287 | if (!sgid_tbl) { | |
08920b8f | 288 | dev_err(&res->pdev->dev, "SGID table not allocated\n"); |
1ac5a404 SX |
289 | return -EINVAL; |
290 | } | |
291 | /* Do we need a sgid_lock here? */ | |
292 | if (sgid_tbl->active == sgid_tbl->max) { | |
08920b8f | 293 | dev_err(&res->pdev->dev, "SGID table is full\n"); |
1ac5a404 SX |
294 | return -ENOMEM; |
295 | } | |
296 | free_idx = sgid_tbl->max; | |
297 | for (i = 0; i < sgid_tbl->max; i++) { | |
298 | if (!memcmp(&sgid_tbl->tbl[i], gid, sizeof(*gid))) { | |
299 | dev_dbg(&res->pdev->dev, | |
08920b8f | 300 | "SGID entry already exist in entry %d!\n", i); |
1ac5a404 SX |
301 | *index = i; |
302 | return -EALREADY; | |
303 | } else if (!memcmp(&sgid_tbl->tbl[i], &bnxt_qplib_gid_zero, | |
304 | sizeof(bnxt_qplib_gid_zero)) && | |
305 | free_idx == sgid_tbl->max) { | |
306 | free_idx = i; | |
307 | } | |
308 | } | |
309 | if (free_idx == sgid_tbl->max) { | |
310 | dev_err(&res->pdev->dev, | |
08920b8f | 311 | "SGID table is FULL but count is not MAX??\n"); |
1ac5a404 SX |
312 | return -ENOMEM; |
313 | } | |
314 | if (update) { | |
315 | struct cmdq_add_gid req; | |
cc1ec769 | 316 | struct creq_add_gid_resp resp; |
1ac5a404 | 317 | u16 cmd_flags = 0; |
cc1ec769 | 318 | int rc; |
1ac5a404 SX |
319 | |
320 | RCFW_CMD_PREP(req, ADD_GID, cmd_flags); | |
321 | ||
5fac5b1b KA |
322 | req.gid[0] = cpu_to_be32(((u32 *)gid->data)[3]); |
323 | req.gid[1] = cpu_to_be32(((u32 *)gid->data)[2]); | |
324 | req.gid[2] = cpu_to_be32(((u32 *)gid->data)[1]); | |
325 | req.gid[3] = cpu_to_be32(((u32 *)gid->data)[0]); | |
326 | /* | |
327 | * driver should ensure that all RoCE traffic is always VLAN | |
328 | * tagged if RoCE traffic is running on non-zero VLAN ID or | |
329 | * RoCE traffic is running on non-zero Priority. | |
330 | */ | |
331 | if ((vlan_id != 0xFFFF) || res->prio) { | |
332 | if (vlan_id != 0xFFFF) | |
333 | req.vlan = cpu_to_le16 | |
334 | (vlan_id & CMDQ_ADD_GID_VLAN_VLAN_ID_MASK); | |
335 | req.vlan |= cpu_to_le16 | |
336 | (CMDQ_ADD_GID_VLAN_TPID_TPID_8100 | | |
337 | CMDQ_ADD_GID_VLAN_VLAN_EN); | |
338 | } | |
1ac5a404 SX |
339 | |
340 | /* MAC in network format */ | |
5fac5b1b KA |
341 | req.src_mac[0] = cpu_to_be16(((u16 *)smac)[0]); |
342 | req.src_mac[1] = cpu_to_be16(((u16 *)smac)[1]); | |
343 | req.src_mac[2] = cpu_to_be16(((u16 *)smac)[2]); | |
1ac5a404 | 344 | |
cc1ec769 DS |
345 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
346 | (void *)&resp, NULL, 0); | |
347 | if (rc) | |
348 | return rc; | |
349 | sgid_tbl->hw_id[free_idx] = le32_to_cpu(resp.xid); | |
1ac5a404 SX |
350 | } |
351 | /* Add GID to the sgid_tbl */ | |
352 | memcpy(&sgid_tbl->tbl[free_idx], gid, sizeof(*gid)); | |
353 | sgid_tbl->active++; | |
5fac5b1b KA |
354 | if (vlan_id != 0xFFFF) |
355 | sgid_tbl->vlan[free_idx] = 1; | |
356 | ||
1ac5a404 | 357 | dev_dbg(&res->pdev->dev, |
08920b8f | 358 | "SGID added hw_id[0x%x] = 0x%x active = 0x%x\n", |
1ac5a404 SX |
359 | free_idx, sgid_tbl->hw_id[free_idx], sgid_tbl->active); |
360 | ||
361 | *index = free_idx; | |
362 | /* unlock */ | |
cc1ec769 | 363 | return 0; |
1ac5a404 SX |
364 | } |
365 | ||
5fac5b1b KA |
366 | int bnxt_qplib_update_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, |
367 | struct bnxt_qplib_gid *gid, u16 gid_idx, | |
368 | u8 *smac) | |
369 | { | |
370 | struct bnxt_qplib_res *res = to_bnxt_qplib(sgid_tbl, | |
371 | struct bnxt_qplib_res, | |
372 | sgid_tbl); | |
373 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
374 | struct creq_modify_gid_resp resp; | |
375 | struct cmdq_modify_gid req; | |
376 | int rc; | |
377 | u16 cmd_flags = 0; | |
378 | ||
379 | RCFW_CMD_PREP(req, MODIFY_GID, cmd_flags); | |
380 | ||
381 | req.gid[0] = cpu_to_be32(((u32 *)gid->data)[3]); | |
382 | req.gid[1] = cpu_to_be32(((u32 *)gid->data)[2]); | |
383 | req.gid[2] = cpu_to_be32(((u32 *)gid->data)[1]); | |
384 | req.gid[3] = cpu_to_be32(((u32 *)gid->data)[0]); | |
385 | if (res->prio) { | |
386 | req.vlan |= cpu_to_le16 | |
387 | (CMDQ_ADD_GID_VLAN_TPID_TPID_8100 | | |
388 | CMDQ_ADD_GID_VLAN_VLAN_EN); | |
389 | } | |
390 | ||
391 | /* MAC in network format */ | |
392 | req.src_mac[0] = cpu_to_be16(((u16 *)smac)[0]); | |
393 | req.src_mac[1] = cpu_to_be16(((u16 *)smac)[1]); | |
394 | req.src_mac[2] = cpu_to_be16(((u16 *)smac)[2]); | |
395 | ||
396 | req.gid_index = cpu_to_le16(gid_idx); | |
397 | ||
398 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, | |
399 | (void *)&resp, NULL, 0); | |
400 | return rc; | |
401 | } | |
402 | ||
1ac5a404 SX |
403 | /* pkeys */ |
404 | int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res, | |
405 | struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 index, | |
406 | u16 *pkey) | |
407 | { | |
408 | if (index == 0xFFFF) { | |
409 | *pkey = 0xFFFF; | |
410 | return 0; | |
411 | } | |
474e5a86 | 412 | if (index >= pkey_tbl->max) { |
1ac5a404 | 413 | dev_err(&res->pdev->dev, |
08920b8f | 414 | "Index %d exceeded PKEY table max (%d)\n", |
1ac5a404 SX |
415 | index, pkey_tbl->max); |
416 | return -EINVAL; | |
417 | } | |
418 | memcpy(pkey, &pkey_tbl->tbl[index], sizeof(*pkey)); | |
419 | return 0; | |
420 | } | |
421 | ||
422 | int bnxt_qplib_del_pkey(struct bnxt_qplib_res *res, | |
423 | struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 *pkey, | |
424 | bool update) | |
425 | { | |
426 | int i, rc = 0; | |
427 | ||
428 | if (!pkey_tbl) { | |
08920b8f | 429 | dev_err(&res->pdev->dev, "PKEY table not allocated\n"); |
1ac5a404 SX |
430 | return -EINVAL; |
431 | } | |
432 | ||
433 | /* Do we need a pkey_lock here? */ | |
434 | if (!pkey_tbl->active) { | |
08920b8f | 435 | dev_err(&res->pdev->dev, "PKEY table has no active entries\n"); |
1ac5a404 SX |
436 | return -ENOMEM; |
437 | } | |
438 | for (i = 0; i < pkey_tbl->max; i++) { | |
439 | if (!memcmp(&pkey_tbl->tbl[i], pkey, sizeof(*pkey))) | |
440 | break; | |
441 | } | |
442 | if (i == pkey_tbl->max) { | |
443 | dev_err(&res->pdev->dev, | |
08920b8f | 444 | "PKEY 0x%04x not found in the pkey table\n", *pkey); |
1ac5a404 SX |
445 | return -ENOMEM; |
446 | } | |
447 | memset(&pkey_tbl->tbl[i], 0, sizeof(*pkey)); | |
448 | pkey_tbl->active--; | |
449 | ||
450 | /* unlock */ | |
451 | return rc; | |
452 | } | |
453 | ||
454 | int bnxt_qplib_add_pkey(struct bnxt_qplib_res *res, | |
455 | struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 *pkey, | |
456 | bool update) | |
457 | { | |
458 | int i, free_idx, rc = 0; | |
459 | ||
460 | if (!pkey_tbl) { | |
08920b8f | 461 | dev_err(&res->pdev->dev, "PKEY table not allocated\n"); |
1ac5a404 SX |
462 | return -EINVAL; |
463 | } | |
464 | ||
465 | /* Do we need a pkey_lock here? */ | |
466 | if (pkey_tbl->active == pkey_tbl->max) { | |
08920b8f | 467 | dev_err(&res->pdev->dev, "PKEY table is full\n"); |
1ac5a404 SX |
468 | return -ENOMEM; |
469 | } | |
470 | free_idx = pkey_tbl->max; | |
471 | for (i = 0; i < pkey_tbl->max; i++) { | |
472 | if (!memcmp(&pkey_tbl->tbl[i], pkey, sizeof(*pkey))) | |
473 | return -EALREADY; | |
474 | else if (!pkey_tbl->tbl[i] && free_idx == pkey_tbl->max) | |
475 | free_idx = i; | |
476 | } | |
477 | if (free_idx == pkey_tbl->max) { | |
478 | dev_err(&res->pdev->dev, | |
08920b8f | 479 | "PKEY table is FULL but count is not MAX??\n"); |
1ac5a404 SX |
480 | return -ENOMEM; |
481 | } | |
482 | /* Add PKEY to the pkey_tbl */ | |
483 | memcpy(&pkey_tbl->tbl[free_idx], pkey, sizeof(*pkey)); | |
484 | pkey_tbl->active++; | |
485 | ||
486 | /* unlock */ | |
487 | return rc; | |
488 | } | |
489 | ||
490 | /* AH */ | |
90e3edd8 GP |
491 | int bnxt_qplib_create_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah, |
492 | bool block) | |
1ac5a404 SX |
493 | { |
494 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
495 | struct cmdq_create_ah req; | |
cc1ec769 | 496 | struct creq_create_ah_resp resp; |
1ac5a404 SX |
497 | u16 cmd_flags = 0; |
498 | u32 temp32[4]; | |
499 | u16 temp16[3]; | |
cc1ec769 | 500 | int rc; |
1ac5a404 SX |
501 | |
502 | RCFW_CMD_PREP(req, CREATE_AH, cmd_flags); | |
503 | ||
504 | memcpy(temp32, ah->dgid.data, sizeof(struct bnxt_qplib_gid)); | |
505 | req.dgid[0] = cpu_to_le32(temp32[0]); | |
506 | req.dgid[1] = cpu_to_le32(temp32[1]); | |
507 | req.dgid[2] = cpu_to_le32(temp32[2]); | |
508 | req.dgid[3] = cpu_to_le32(temp32[3]); | |
509 | ||
510 | req.type = ah->nw_type; | |
511 | req.hop_limit = ah->hop_limit; | |
512 | req.sgid_index = cpu_to_le16(res->sgid_tbl.hw_id[ah->sgid_index]); | |
513 | req.dest_vlan_id_flow_label = cpu_to_le32((ah->flow_label & | |
514 | CMDQ_CREATE_AH_FLOW_LABEL_MASK) | | |
515 | CMDQ_CREATE_AH_DEST_VLAN_ID_MASK); | |
516 | req.pd_id = cpu_to_le32(ah->pd->id); | |
517 | req.traffic_class = ah->traffic_class; | |
518 | ||
519 | /* MAC in network format */ | |
520 | memcpy(temp16, ah->dmac, 6); | |
521 | req.dest_mac[0] = cpu_to_le16(temp16[0]); | |
522 | req.dest_mac[1] = cpu_to_le16(temp16[1]); | |
523 | req.dest_mac[2] = cpu_to_le16(temp16[2]); | |
524 | ||
cc1ec769 | 525 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, |
90e3edd8 | 526 | NULL, block); |
cc1ec769 DS |
527 | if (rc) |
528 | return rc; | |
529 | ||
530 | ah->id = le32_to_cpu(resp.xid); | |
1ac5a404 SX |
531 | return 0; |
532 | } | |
533 | ||
50c582de GP |
534 | int bnxt_qplib_destroy_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah, |
535 | bool block) | |
1ac5a404 SX |
536 | { |
537 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
538 | struct cmdq_destroy_ah req; | |
cc1ec769 | 539 | struct creq_destroy_ah_resp resp; |
1ac5a404 | 540 | u16 cmd_flags = 0; |
cc1ec769 | 541 | int rc; |
1ac5a404 SX |
542 | |
543 | /* Clean up the AH table in the device */ | |
544 | RCFW_CMD_PREP(req, DESTROY_AH, cmd_flags); | |
545 | ||
546 | req.ah_cid = cpu_to_le32(ah->id); | |
547 | ||
cc1ec769 | 548 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, |
50c582de | 549 | NULL, block); |
cc1ec769 DS |
550 | if (rc) |
551 | return rc; | |
1ac5a404 SX |
552 | return 0; |
553 | } | |
554 | ||
555 | /* MRW */ | |
556 | int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) | |
557 | { | |
558 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
559 | struct cmdq_deallocate_key req; | |
cc1ec769 | 560 | struct creq_deallocate_key_resp resp; |
1ac5a404 | 561 | u16 cmd_flags = 0; |
cc1ec769 | 562 | int rc; |
1ac5a404 SX |
563 | |
564 | if (mrw->lkey == 0xFFFFFFFF) { | |
08920b8f | 565 | dev_info(&res->pdev->dev, "SP: Free a reserved lkey MRW\n"); |
1ac5a404 SX |
566 | return 0; |
567 | } | |
568 | ||
569 | RCFW_CMD_PREP(req, DEALLOCATE_KEY, cmd_flags); | |
570 | ||
571 | req.mrw_flags = mrw->type; | |
572 | ||
573 | if ((mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE1) || | |
574 | (mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A) || | |
575 | (mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B)) | |
576 | req.key = cpu_to_le32(mrw->rkey); | |
577 | else | |
578 | req.key = cpu_to_le32(mrw->lkey); | |
579 | ||
cc1ec769 DS |
580 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, |
581 | NULL, 0); | |
582 | if (rc) | |
583 | return rc; | |
584 | ||
1ac5a404 SX |
585 | /* Free the qplib's MRW memory */ |
586 | if (mrw->hwq.max_elements) | |
587 | bnxt_qplib_free_hwq(res->pdev, &mrw->hwq); | |
588 | ||
589 | return 0; | |
590 | } | |
591 | ||
592 | int bnxt_qplib_alloc_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw) | |
593 | { | |
594 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
595 | struct cmdq_allocate_mrw req; | |
cc1ec769 | 596 | struct creq_allocate_mrw_resp resp; |
1ac5a404 SX |
597 | u16 cmd_flags = 0; |
598 | unsigned long tmp; | |
cc1ec769 | 599 | int rc; |
1ac5a404 SX |
600 | |
601 | RCFW_CMD_PREP(req, ALLOCATE_MRW, cmd_flags); | |
602 | ||
603 | req.pd_id = cpu_to_le32(mrw->pd->id); | |
604 | req.mrw_flags = mrw->type; | |
605 | if ((mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_PMR && | |
606 | mrw->flags & BNXT_QPLIB_FR_PMR) || | |
607 | mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A || | |
608 | mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B) | |
609 | req.access = CMDQ_ALLOCATE_MRW_ACCESS_CONSUMER_OWNED_KEY; | |
610 | tmp = (unsigned long)mrw; | |
611 | req.mrw_handle = cpu_to_le64(tmp); | |
612 | ||
cc1ec769 DS |
613 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
614 | (void *)&resp, NULL, 0); | |
615 | if (rc) | |
616 | return rc; | |
617 | ||
1ac5a404 SX |
618 | if ((mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE1) || |
619 | (mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A) || | |
620 | (mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B)) | |
cc1ec769 | 621 | mrw->rkey = le32_to_cpu(resp.xid); |
1ac5a404 | 622 | else |
cc1ec769 | 623 | mrw->lkey = le32_to_cpu(resp.xid); |
1ac5a404 SX |
624 | return 0; |
625 | } | |
626 | ||
627 | int bnxt_qplib_dereg_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw, | |
628 | bool block) | |
629 | { | |
630 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
631 | struct cmdq_deregister_mr req; | |
cc1ec769 | 632 | struct creq_deregister_mr_resp resp; |
1ac5a404 SX |
633 | u16 cmd_flags = 0; |
634 | int rc; | |
635 | ||
636 | RCFW_CMD_PREP(req, DEREGISTER_MR, cmd_flags); | |
637 | ||
638 | req.lkey = cpu_to_le32(mrw->lkey); | |
cc1ec769 DS |
639 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
640 | (void *)&resp, NULL, block); | |
641 | if (rc) | |
642 | return rc; | |
1ac5a404 SX |
643 | |
644 | /* Free the qplib's MR memory */ | |
645 | if (mrw->hwq.max_elements) { | |
646 | mrw->va = 0; | |
647 | mrw->total_size = 0; | |
648 | bnxt_qplib_free_hwq(res->pdev, &mrw->hwq); | |
649 | } | |
650 | ||
651 | return 0; | |
652 | } | |
653 | ||
654 | int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, | |
872f3578 | 655 | u64 *pbl_tbl, int num_pbls, bool block, u32 buf_pg_size) |
1ac5a404 SX |
656 | { |
657 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
658 | struct cmdq_register_mr req; | |
cc1ec769 | 659 | struct creq_register_mr_resp resp; |
1ac5a404 SX |
660 | u16 cmd_flags = 0, level; |
661 | int pg_ptrs, pages, i, rc; | |
662 | dma_addr_t **pbl_ptr; | |
663 | u32 pg_size; | |
664 | ||
665 | if (num_pbls) { | |
872f3578 SK |
666 | /* Allocate memory for the non-leaf pages to store buf ptrs. |
667 | * Non-leaf pages always uses system PAGE_SIZE | |
668 | */ | |
1ac5a404 SX |
669 | pg_ptrs = roundup_pow_of_two(num_pbls); |
670 | pages = pg_ptrs >> MAX_PBL_LVL_1_PGS_SHIFT; | |
671 | if (!pages) | |
672 | pages++; | |
673 | ||
674 | if (pages > MAX_PBL_LVL_1_PGS) { | |
1ac5a404 | 675 | dev_err(&res->pdev->dev, |
08920b8f | 676 | "SP: Reg MR pages requested (0x%x) exceeded max (0x%x)\n", |
1ac5a404 SX |
677 | pages, MAX_PBL_LVL_1_PGS); |
678 | return -ENOMEM; | |
679 | } | |
680 | /* Free the hwq if it already exist, must be a rereg */ | |
681 | if (mr->hwq.max_elements) | |
682 | bnxt_qplib_free_hwq(res->pdev, &mr->hwq); | |
683 | ||
684 | mr->hwq.max_elements = pages; | |
872f3578 | 685 | /* Use system PAGE_SIZE */ |
1ac5a404 SX |
686 | rc = bnxt_qplib_alloc_init_hwq(res->pdev, &mr->hwq, NULL, 0, |
687 | &mr->hwq.max_elements, | |
688 | PAGE_SIZE, 0, PAGE_SIZE, | |
689 | HWQ_TYPE_CTX); | |
690 | if (rc) { | |
691 | dev_err(&res->pdev->dev, | |
08920b8f | 692 | "SP: Reg MR memory allocation failed\n"); |
1ac5a404 SX |
693 | return -ENOMEM; |
694 | } | |
695 | /* Write to the hwq */ | |
696 | pbl_ptr = (dma_addr_t **)mr->hwq.pbl_ptr; | |
697 | for (i = 0; i < num_pbls; i++) | |
698 | pbl_ptr[PTR_PG(i)][PTR_IDX(i)] = | |
699 | (pbl_tbl[i] & PAGE_MASK) | PTU_PTE_VALID; | |
700 | } | |
701 | ||
702 | RCFW_CMD_PREP(req, REGISTER_MR, cmd_flags); | |
703 | ||
704 | /* Configure the request */ | |
705 | if (mr->hwq.level == PBL_LVL_MAX) { | |
872f3578 | 706 | /* No PBL provided, just use system PAGE_SIZE */ |
1ac5a404 SX |
707 | level = 0; |
708 | req.pbl = 0; | |
709 | pg_size = PAGE_SIZE; | |
710 | } else { | |
711 | level = mr->hwq.level + 1; | |
712 | req.pbl = cpu_to_le64(mr->hwq.pbl[PBL_LVL_0].pg_map_arr[0]); | |
1ac5a404 | 713 | } |
872f3578 | 714 | pg_size = buf_pg_size ? buf_pg_size : PAGE_SIZE; |
1ac5a404 SX |
715 | req.log2_pg_size_lvl = (level << CMDQ_REGISTER_MR_LVL_SFT) | |
716 | ((ilog2(pg_size) << | |
717 | CMDQ_REGISTER_MR_LOG2_PG_SIZE_SFT) & | |
718 | CMDQ_REGISTER_MR_LOG2_PG_SIZE_MASK); | |
872f3578 SK |
719 | req.log2_pbl_pg_size = cpu_to_le16(((ilog2(PAGE_SIZE) << |
720 | CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_SFT) & | |
721 | CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_MASK)); | |
1ac5a404 SX |
722 | req.access = (mr->flags & 0xFFFF); |
723 | req.va = cpu_to_le64(mr->va); | |
724 | req.key = cpu_to_le32(mr->lkey); | |
725 | req.mr_size = cpu_to_le64(mr->total_size); | |
726 | ||
cc1ec769 DS |
727 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, |
728 | (void *)&resp, NULL, block); | |
729 | if (rc) | |
1ac5a404 | 730 | goto fail; |
cc1ec769 | 731 | |
1ac5a404 SX |
732 | return 0; |
733 | ||
734 | fail: | |
735 | if (mr->hwq.max_elements) | |
736 | bnxt_qplib_free_hwq(res->pdev, &mr->hwq); | |
737 | return rc; | |
738 | } | |
739 | ||
740 | int bnxt_qplib_alloc_fast_reg_page_list(struct bnxt_qplib_res *res, | |
741 | struct bnxt_qplib_frpl *frpl, | |
742 | int max_pg_ptrs) | |
743 | { | |
744 | int pg_ptrs, pages, rc; | |
745 | ||
746 | /* Re-calculate the max to fit the HWQ allocation model */ | |
747 | pg_ptrs = roundup_pow_of_two(max_pg_ptrs); | |
748 | pages = pg_ptrs >> MAX_PBL_LVL_1_PGS_SHIFT; | |
749 | if (!pages) | |
750 | pages++; | |
751 | ||
752 | if (pages > MAX_PBL_LVL_1_PGS) | |
753 | return -ENOMEM; | |
754 | ||
755 | frpl->hwq.max_elements = pages; | |
756 | rc = bnxt_qplib_alloc_init_hwq(res->pdev, &frpl->hwq, NULL, 0, | |
757 | &frpl->hwq.max_elements, PAGE_SIZE, 0, | |
758 | PAGE_SIZE, HWQ_TYPE_CTX); | |
759 | if (!rc) | |
760 | frpl->max_pg_ptrs = pg_ptrs; | |
761 | ||
762 | return rc; | |
763 | } | |
764 | ||
765 | int bnxt_qplib_free_fast_reg_page_list(struct bnxt_qplib_res *res, | |
766 | struct bnxt_qplib_frpl *frpl) | |
767 | { | |
768 | bnxt_qplib_free_hwq(res->pdev, &frpl->hwq); | |
769 | return 0; | |
770 | } | |
771 | ||
772 | int bnxt_qplib_map_tc2cos(struct bnxt_qplib_res *res, u16 *cids) | |
773 | { | |
774 | struct bnxt_qplib_rcfw *rcfw = res->rcfw; | |
775 | struct cmdq_map_tc_to_cos req; | |
cc1ec769 | 776 | struct creq_map_tc_to_cos_resp resp; |
1ac5a404 | 777 | u16 cmd_flags = 0; |
1ac5a404 SX |
778 | |
779 | RCFW_CMD_PREP(req, MAP_TC_TO_COS, cmd_flags); | |
780 | req.cos0 = cpu_to_le16(cids[0]); | |
781 | req.cos1 = cpu_to_le16(cids[1]); | |
782 | ||
94edd87a AP |
783 | return bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, |
784 | NULL, 0); | |
1ac5a404 | 785 | } |
89f81008 SX |
786 | |
787 | int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw, | |
788 | struct bnxt_qplib_roce_stats *stats) | |
789 | { | |
790 | struct cmdq_query_roce_stats req; | |
791 | struct creq_query_roce_stats_resp resp; | |
792 | struct bnxt_qplib_rcfw_sbuf *sbuf; | |
793 | struct creq_query_roce_stats_resp_sb *sb; | |
794 | u16 cmd_flags = 0; | |
795 | int rc = 0; | |
796 | ||
797 | RCFW_CMD_PREP(req, QUERY_ROCE_STATS, cmd_flags); | |
798 | ||
799 | sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); | |
800 | if (!sbuf) { | |
801 | dev_err(&rcfw->pdev->dev, | |
08920b8f | 802 | "SP: QUERY_ROCE_STATS alloc side buffer failed\n"); |
89f81008 SX |
803 | return -ENOMEM; |
804 | } | |
805 | ||
806 | sb = sbuf->sb; | |
807 | req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; | |
808 | rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, | |
809 | (void *)sbuf, 0); | |
810 | if (rc) | |
811 | goto bail; | |
812 | /* Extract the context from the side buffer */ | |
813 | stats->to_retransmits = le64_to_cpu(sb->to_retransmits); | |
814 | stats->seq_err_naks_rcvd = le64_to_cpu(sb->seq_err_naks_rcvd); | |
815 | stats->max_retry_exceeded = le64_to_cpu(sb->max_retry_exceeded); | |
816 | stats->rnr_naks_rcvd = le64_to_cpu(sb->rnr_naks_rcvd); | |
817 | stats->missing_resp = le64_to_cpu(sb->missing_resp); | |
818 | stats->unrecoverable_err = le64_to_cpu(sb->unrecoverable_err); | |
819 | stats->bad_resp_err = le64_to_cpu(sb->bad_resp_err); | |
820 | stats->local_qp_op_err = le64_to_cpu(sb->local_qp_op_err); | |
821 | stats->local_protection_err = le64_to_cpu(sb->local_protection_err); | |
822 | stats->mem_mgmt_op_err = le64_to_cpu(sb->mem_mgmt_op_err); | |
823 | stats->remote_invalid_req_err = le64_to_cpu(sb->remote_invalid_req_err); | |
824 | stats->remote_access_err = le64_to_cpu(sb->remote_access_err); | |
825 | stats->remote_op_err = le64_to_cpu(sb->remote_op_err); | |
826 | stats->dup_req = le64_to_cpu(sb->dup_req); | |
827 | stats->res_exceed_max = le64_to_cpu(sb->res_exceed_max); | |
828 | stats->res_length_mismatch = le64_to_cpu(sb->res_length_mismatch); | |
829 | stats->res_exceeds_wqe = le64_to_cpu(sb->res_exceeds_wqe); | |
830 | stats->res_opcode_err = le64_to_cpu(sb->res_opcode_err); | |
831 | stats->res_rx_invalid_rkey = le64_to_cpu(sb->res_rx_invalid_rkey); | |
832 | stats->res_rx_domain_err = le64_to_cpu(sb->res_rx_domain_err); | |
833 | stats->res_rx_no_perm = le64_to_cpu(sb->res_rx_no_perm); | |
834 | stats->res_rx_range_err = le64_to_cpu(sb->res_rx_range_err); | |
835 | stats->res_tx_invalid_rkey = le64_to_cpu(sb->res_tx_invalid_rkey); | |
836 | stats->res_tx_domain_err = le64_to_cpu(sb->res_tx_domain_err); | |
837 | stats->res_tx_no_perm = le64_to_cpu(sb->res_tx_no_perm); | |
838 | stats->res_tx_range_err = le64_to_cpu(sb->res_tx_range_err); | |
839 | stats->res_irrq_oflow = le64_to_cpu(sb->res_irrq_oflow); | |
840 | stats->res_unsup_opcode = le64_to_cpu(sb->res_unsup_opcode); | |
841 | stats->res_unaligned_atomic = le64_to_cpu(sb->res_unaligned_atomic); | |
842 | stats->res_rem_inv_err = le64_to_cpu(sb->res_rem_inv_err); | |
843 | stats->res_mem_error = le64_to_cpu(sb->res_mem_error); | |
844 | stats->res_srq_err = le64_to_cpu(sb->res_srq_err); | |
845 | stats->res_cmp_err = le64_to_cpu(sb->res_cmp_err); | |
846 | stats->res_invalid_dup_rkey = le64_to_cpu(sb->res_invalid_dup_rkey); | |
847 | stats->res_wqe_format_err = le64_to_cpu(sb->res_wqe_format_err); | |
848 | stats->res_cq_load_err = le64_to_cpu(sb->res_cq_load_err); | |
849 | stats->res_srq_load_err = le64_to_cpu(sb->res_srq_load_err); | |
850 | stats->res_tx_pci_err = le64_to_cpu(sb->res_tx_pci_err); | |
851 | stats->res_rx_pci_err = le64_to_cpu(sb->res_rx_pci_err); | |
316dd282 SX |
852 | if (!rcfw->init_oos_stats) { |
853 | rcfw->oos_prev = le64_to_cpu(sb->res_oos_drop_count); | |
854 | rcfw->init_oos_stats = 1; | |
855 | } else { | |
856 | stats->res_oos_drop_count += | |
857 | (le64_to_cpu(sb->res_oos_drop_count) - | |
858 | rcfw->oos_prev) & BNXT_QPLIB_OOS_COUNT_MASK; | |
859 | rcfw->oos_prev = le64_to_cpu(sb->res_oos_drop_count); | |
860 | } | |
861 | ||
89f81008 SX |
862 | bail: |
863 | bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); | |
864 | return rc; | |
865 | } |