OSDN Git Service

block: Fix partition support for host aware zoned block devices
[tomoyo/tomoyo-test1.git] / drivers / net / ethernet / broadcom / bnxt / bnxt_devlink.c
1 /* Broadcom NetXtreme-C/E network driver.
2  *
3  * Copyright (c) 2017 Broadcom Limited
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation.
8  */
9
10 #include <linux/pci.h>
11 #include <linux/netdevice.h>
12 #include <net/devlink.h>
13 #include "bnxt_hsi.h"
14 #include "bnxt.h"
15 #include "bnxt_vfr.h"
16 #include "bnxt_devlink.h"
17 #include "bnxt_ethtool.h"
18
19 static int
20 bnxt_dl_flash_update(struct devlink *dl, const char *filename,
21                      const char *region, struct netlink_ext_ack *extack)
22 {
23         struct bnxt *bp = bnxt_get_bp_from_dl(dl);
24         int rc;
25
26         if (region)
27                 return -EOPNOTSUPP;
28
29         if (!BNXT_PF(bp)) {
30                 NL_SET_ERR_MSG_MOD(extack,
31                                    "flash update not supported from a VF");
32                 return -EPERM;
33         }
34
35         devlink_flash_update_begin_notify(dl);
36         devlink_flash_update_status_notify(dl, "Preparing to flash", region, 0,
37                                            0);
38         rc = bnxt_flash_package_from_file(bp->dev, filename, 0);
39         if (!rc)
40                 devlink_flash_update_status_notify(dl, "Flashing done", region,
41                                                    0, 0);
42         else
43                 devlink_flash_update_status_notify(dl, "Flashing failed",
44                                                    region, 0, 0);
45         devlink_flash_update_end_notify(dl);
46         return rc;
47 }
48
49 static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
50                                      struct devlink_fmsg *fmsg,
51                                      struct netlink_ext_ack *extack)
52 {
53         struct bnxt *bp = devlink_health_reporter_priv(reporter);
54         u32 val, health_status;
55         int rc;
56
57         if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
58                 return 0;
59
60         val = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG);
61         health_status = val & 0xffff;
62
63         if (health_status < BNXT_FW_STATUS_HEALTHY) {
64                 rc = devlink_fmsg_string_pair_put(fmsg, "Description",
65                                                   "Not yet completed initialization");
66                 if (rc)
67                         return rc;
68         } else if (health_status > BNXT_FW_STATUS_HEALTHY) {
69                 rc = devlink_fmsg_string_pair_put(fmsg, "Description",
70                                                   "Encountered fatal error and cannot recover");
71                 if (rc)
72                         return rc;
73         }
74
75         if (val >> 16) {
76                 rc = devlink_fmsg_u32_pair_put(fmsg, "Error code", val >> 16);
77                 if (rc)
78                         return rc;
79         }
80
81         val = bnxt_fw_health_readl(bp, BNXT_FW_RESET_CNT_REG);
82         rc = devlink_fmsg_u32_pair_put(fmsg, "Reset count", val);
83         if (rc)
84                 return rc;
85
86         return 0;
87 }
88
89 static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = {
90         .name = "fw",
91         .diagnose = bnxt_fw_reporter_diagnose,
92 };
93
94 static int bnxt_fw_reset_recover(struct devlink_health_reporter *reporter,
95                                  void *priv_ctx,
96                                  struct netlink_ext_ack *extack)
97 {
98         struct bnxt *bp = devlink_health_reporter_priv(reporter);
99
100         if (!priv_ctx)
101                 return -EOPNOTSUPP;
102
103         bnxt_fw_reset(bp);
104         return -EINPROGRESS;
105 }
106
107 static const
108 struct devlink_health_reporter_ops bnxt_dl_fw_reset_reporter_ops = {
109         .name = "fw_reset",
110         .recover = bnxt_fw_reset_recover,
111 };
112
113 static int bnxt_fw_fatal_recover(struct devlink_health_reporter *reporter,
114                                  void *priv_ctx,
115                                  struct netlink_ext_ack *extack)
116 {
117         struct bnxt *bp = devlink_health_reporter_priv(reporter);
118         struct bnxt_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
119         unsigned long event;
120
121         if (!priv_ctx)
122                 return -EOPNOTSUPP;
123
124         bp->fw_health->fatal = true;
125         event = fw_reporter_ctx->sp_event;
126         if (event == BNXT_FW_RESET_NOTIFY_SP_EVENT)
127                 bnxt_fw_reset(bp);
128         else if (event == BNXT_FW_EXCEPTION_SP_EVENT)
129                 bnxt_fw_exception(bp);
130
131         return -EINPROGRESS;
132 }
133
134 static const
135 struct devlink_health_reporter_ops bnxt_dl_fw_fatal_reporter_ops = {
136         .name = "fw_fatal",
137         .recover = bnxt_fw_fatal_recover,
138 };
139
140 void bnxt_dl_fw_reporters_create(struct bnxt *bp)
141 {
142         struct bnxt_fw_health *health = bp->fw_health;
143
144         if (!bp->dl || !health)
145                 return;
146
147         if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) || health->fw_reset_reporter)
148                 goto err_recovery;
149
150         health->fw_reset_reporter =
151                 devlink_health_reporter_create(bp->dl,
152                                                &bnxt_dl_fw_reset_reporter_ops,
153                                                0, true, bp);
154         if (IS_ERR(health->fw_reset_reporter)) {
155                 netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
156                             PTR_ERR(health->fw_reset_reporter));
157                 health->fw_reset_reporter = NULL;
158                 bp->fw_cap &= ~BNXT_FW_CAP_HOT_RESET;
159         }
160
161 err_recovery:
162         if (!(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
163                 return;
164
165         if (!health->fw_reporter) {
166                 health->fw_reporter =
167                         devlink_health_reporter_create(bp->dl,
168                                                        &bnxt_dl_fw_reporter_ops,
169                                                        0, false, bp);
170                 if (IS_ERR(health->fw_reporter)) {
171                         netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n",
172                                     PTR_ERR(health->fw_reporter));
173                         health->fw_reporter = NULL;
174                         bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
175                         return;
176                 }
177         }
178
179         if (health->fw_fatal_reporter)
180                 return;
181
182         health->fw_fatal_reporter =
183                 devlink_health_reporter_create(bp->dl,
184                                                &bnxt_dl_fw_fatal_reporter_ops,
185                                                0, true, bp);
186         if (IS_ERR(health->fw_fatal_reporter)) {
187                 netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
188                             PTR_ERR(health->fw_fatal_reporter));
189                 health->fw_fatal_reporter = NULL;
190                 bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
191         }
192 }
193
194 void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all)
195 {
196         struct bnxt_fw_health *health = bp->fw_health;
197
198         if (!bp->dl || !health)
199                 return;
200
201         if ((all || !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) &&
202             health->fw_reset_reporter) {
203                 devlink_health_reporter_destroy(health->fw_reset_reporter);
204                 health->fw_reset_reporter = NULL;
205         }
206
207         if ((bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) && !all)
208                 return;
209
210         if (health->fw_reporter) {
211                 devlink_health_reporter_destroy(health->fw_reporter);
212                 health->fw_reporter = NULL;
213         }
214
215         if (health->fw_fatal_reporter) {
216                 devlink_health_reporter_destroy(health->fw_fatal_reporter);
217                 health->fw_fatal_reporter = NULL;
218         }
219 }
220
221 void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event)
222 {
223         struct bnxt_fw_health *fw_health = bp->fw_health;
224         struct bnxt_fw_reporter_ctx fw_reporter_ctx;
225
226         fw_reporter_ctx.sp_event = event;
227         switch (event) {
228         case BNXT_FW_RESET_NOTIFY_SP_EVENT:
229                 if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) {
230                         if (!fw_health->fw_fatal_reporter)
231                                 return;
232
233                         devlink_health_report(fw_health->fw_fatal_reporter,
234                                               "FW fatal async event received",
235                                               &fw_reporter_ctx);
236                         return;
237                 }
238                 if (!fw_health->fw_reset_reporter)
239                         return;
240
241                 devlink_health_report(fw_health->fw_reset_reporter,
242                                       "FW non-fatal reset event received",
243                                       &fw_reporter_ctx);
244                 return;
245
246         case BNXT_FW_EXCEPTION_SP_EVENT:
247                 if (!fw_health->fw_fatal_reporter)
248                         return;
249
250                 devlink_health_report(fw_health->fw_fatal_reporter,
251                                       "FW fatal error reported",
252                                       &fw_reporter_ctx);
253                 return;
254         }
255 }
256
257 void bnxt_dl_health_status_update(struct bnxt *bp, bool healthy)
258 {
259         struct bnxt_fw_health *health = bp->fw_health;
260         u8 state;
261
262         if (healthy)
263                 state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
264         else
265                 state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
266
267         if (health->fatal)
268                 devlink_health_reporter_state_update(health->fw_fatal_reporter,
269                                                      state);
270         else
271                 devlink_health_reporter_state_update(health->fw_reset_reporter,
272                                                      state);
273
274         health->fatal = false;
275 }
276
277 void bnxt_dl_health_recovery_done(struct bnxt *bp)
278 {
279         struct bnxt_fw_health *hlth = bp->fw_health;
280
281         if (hlth->fatal)
282                 devlink_health_reporter_recovery_done(hlth->fw_fatal_reporter);
283         else
284                 devlink_health_reporter_recovery_done(hlth->fw_reset_reporter);
285 }
286
287 static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
288                             struct netlink_ext_ack *extack);
289
290 static const struct devlink_ops bnxt_dl_ops = {
291 #ifdef CONFIG_BNXT_SRIOV
292         .eswitch_mode_set = bnxt_dl_eswitch_mode_set,
293         .eswitch_mode_get = bnxt_dl_eswitch_mode_get,
294 #endif /* CONFIG_BNXT_SRIOV */
295         .info_get         = bnxt_dl_info_get,
296         .flash_update     = bnxt_dl_flash_update,
297 };
298
299 static const struct devlink_ops bnxt_vf_dl_ops;
300
301 enum bnxt_dl_param_id {
302         BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
303         BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
304 };
305
306 static const struct bnxt_dl_nvm_param nvm_params[] = {
307         {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV,
308          BNXT_NVM_SHARED_CFG, 1, 1},
309         {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI,
310          BNXT_NVM_SHARED_CFG, 1, 1},
311         {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
312          NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10, 4},
313         {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
314          NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7, 4},
315         {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK,
316          BNXT_NVM_SHARED_CFG, 1, 1},
317 };
318
319 union bnxt_nvm_data {
320         u8      val8;
321         __le32  val32;
322 };
323
324 static void bnxt_copy_to_nvm_data(union bnxt_nvm_data *dst,
325                                   union devlink_param_value *src,
326                                   int nvm_num_bits, int dl_num_bytes)
327 {
328         u32 val32 = 0;
329
330         if (nvm_num_bits == 1) {
331                 dst->val8 = src->vbool;
332                 return;
333         }
334         if (dl_num_bytes == 4)
335                 val32 = src->vu32;
336         else if (dl_num_bytes == 2)
337                 val32 = (u32)src->vu16;
338         else if (dl_num_bytes == 1)
339                 val32 = (u32)src->vu8;
340         dst->val32 = cpu_to_le32(val32);
341 }
342
343 static void bnxt_copy_from_nvm_data(union devlink_param_value *dst,
344                                     union bnxt_nvm_data *src,
345                                     int nvm_num_bits, int dl_num_bytes)
346 {
347         u32 val32;
348
349         if (nvm_num_bits == 1) {
350                 dst->vbool = src->val8;
351                 return;
352         }
353         val32 = le32_to_cpu(src->val32);
354         if (dl_num_bytes == 4)
355                 dst->vu32 = val32;
356         else if (dl_num_bytes == 2)
357                 dst->vu16 = (u16)val32;
358         else if (dl_num_bytes == 1)
359                 dst->vu8 = (u8)val32;
360 }
361
362 static int bnxt_hwrm_get_nvm_cfg_ver(struct bnxt *bp,
363                                      union devlink_param_value *nvm_cfg_ver)
364 {
365         struct hwrm_nvm_get_variable_input req = {0};
366         union bnxt_nvm_data *data;
367         dma_addr_t data_dma_addr;
368         int rc;
369
370         bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
371         data = dma_alloc_coherent(&bp->pdev->dev, sizeof(*data),
372                                   &data_dma_addr, GFP_KERNEL);
373         if (!data)
374                 return -ENOMEM;
375
376         req.dest_data_addr = cpu_to_le64(data_dma_addr);
377         req.data_len = cpu_to_le16(BNXT_NVM_CFG_VER_BITS);
378         req.option_num = cpu_to_le16(NVM_OFF_NVM_CFG_VER);
379
380         rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
381         if (!rc)
382                 bnxt_copy_from_nvm_data(nvm_cfg_ver, data,
383                                         BNXT_NVM_CFG_VER_BITS,
384                                         BNXT_NVM_CFG_VER_BYTES);
385
386         dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr);
387         return rc;
388 }
389
390 static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
391                             struct netlink_ext_ack *extack)
392 {
393         struct bnxt *bp = bnxt_get_bp_from_dl(dl);
394         union devlink_param_value nvm_cfg_ver;
395         struct hwrm_ver_get_output *ver_resp;
396         char mgmt_ver[FW_VER_STR_LEN];
397         char roce_ver[FW_VER_STR_LEN];
398         char fw_ver[FW_VER_STR_LEN];
399         char buf[32];
400         int rc;
401
402         rc = devlink_info_driver_name_put(req, DRV_MODULE_NAME);
403         if (rc)
404                 return rc;
405
406         sprintf(buf, "%X", bp->chip_num);
407         rc = devlink_info_version_fixed_put(req,
408                         DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, buf);
409         if (rc)
410                 return rc;
411
412         ver_resp = &bp->ver_resp;
413         sprintf(buf, "%X", ver_resp->chip_rev);
414         rc = devlink_info_version_fixed_put(req,
415                         DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, buf);
416         if (rc)
417                 return rc;
418
419         if (BNXT_PF(bp)) {
420                 sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
421                         bp->dsn[7], bp->dsn[6], bp->dsn[5], bp->dsn[4],
422                         bp->dsn[3], bp->dsn[2], bp->dsn[1], bp->dsn[0]);
423                 rc = devlink_info_serial_number_put(req, buf);
424                 if (rc)
425                         return rc;
426         }
427
428         if (strlen(ver_resp->active_pkg_name)) {
429                 rc =
430                     devlink_info_version_running_put(req,
431                                         DEVLINK_INFO_VERSION_GENERIC_FW,
432                                         ver_resp->active_pkg_name);
433                 if (rc)
434                         return rc;
435         }
436
437         if (BNXT_PF(bp) && !bnxt_hwrm_get_nvm_cfg_ver(bp, &nvm_cfg_ver)) {
438                 u32 ver = nvm_cfg_ver.vu32;
439
440                 sprintf(buf, "%X.%X.%X", (ver >> 16) & 0xF, (ver >> 8) & 0xF,
441                         ver & 0xF);
442                 rc = devlink_info_version_running_put(req,
443                                 DEVLINK_INFO_VERSION_GENERIC_FW_PSID, buf);
444                 if (rc)
445                         return rc;
446         }
447
448         if (ver_resp->flags & VER_GET_RESP_FLAGS_EXT_VER_AVAIL) {
449                 snprintf(fw_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
450                          ver_resp->hwrm_fw_major, ver_resp->hwrm_fw_minor,
451                          ver_resp->hwrm_fw_build, ver_resp->hwrm_fw_patch);
452
453                 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
454                          ver_resp->mgmt_fw_major, ver_resp->mgmt_fw_minor,
455                          ver_resp->mgmt_fw_build, ver_resp->mgmt_fw_patch);
456
457                 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
458                          ver_resp->roce_fw_major, ver_resp->roce_fw_minor,
459                          ver_resp->roce_fw_build, ver_resp->roce_fw_patch);
460         } else {
461                 snprintf(fw_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
462                          ver_resp->hwrm_fw_maj_8b, ver_resp->hwrm_fw_min_8b,
463                          ver_resp->hwrm_fw_bld_8b, ver_resp->hwrm_fw_rsvd_8b);
464
465                 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
466                          ver_resp->mgmt_fw_maj_8b, ver_resp->mgmt_fw_min_8b,
467                          ver_resp->mgmt_fw_bld_8b, ver_resp->mgmt_fw_rsvd_8b);
468
469                 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
470                          ver_resp->roce_fw_maj_8b, ver_resp->roce_fw_min_8b,
471                          ver_resp->roce_fw_bld_8b, ver_resp->roce_fw_rsvd_8b);
472         }
473         rc = devlink_info_version_running_put(req,
474                         DEVLINK_INFO_VERSION_GENERIC_FW_APP, fw_ver);
475         if (rc)
476                 return rc;
477
478         if (!(bp->flags & BNXT_FLAG_CHIP_P5)) {
479                 rc = devlink_info_version_running_put(req,
480                         DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver);
481                 if (rc)
482                         return rc;
483
484                 rc = devlink_info_version_running_put(req,
485                         DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver);
486                 if (rc)
487                         return rc;
488         }
489         return 0;
490 }
491
492 static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
493                              int msg_len, union devlink_param_value *val)
494 {
495         struct hwrm_nvm_get_variable_input *req = msg;
496         struct bnxt_dl_nvm_param nvm_param;
497         union bnxt_nvm_data *data;
498         dma_addr_t data_dma_addr;
499         int idx = 0, rc, i;
500
501         /* Get/Set NVM CFG parameter is supported only on PFs */
502         if (BNXT_VF(bp))
503                 return -EPERM;
504
505         for (i = 0; i < ARRAY_SIZE(nvm_params); i++) {
506                 if (nvm_params[i].id == param_id) {
507                         nvm_param = nvm_params[i];
508                         break;
509                 }
510         }
511
512         if (i == ARRAY_SIZE(nvm_params))
513                 return -EOPNOTSUPP;
514
515         if (nvm_param.dir_type == BNXT_NVM_PORT_CFG)
516                 idx = bp->pf.port_id;
517         else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG)
518                 idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID;
519
520         data = dma_alloc_coherent(&bp->pdev->dev, sizeof(*data),
521                                   &data_dma_addr, GFP_KERNEL);
522         if (!data)
523                 return -ENOMEM;
524
525         req->dest_data_addr = cpu_to_le64(data_dma_addr);
526         req->data_len = cpu_to_le16(nvm_param.nvm_num_bits);
527         req->option_num = cpu_to_le16(nvm_param.offset);
528         req->index_0 = cpu_to_le16(idx);
529         if (idx)
530                 req->dimensions = cpu_to_le16(1);
531
532         if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) {
533                 bnxt_copy_to_nvm_data(data, val, nvm_param.nvm_num_bits,
534                                       nvm_param.dl_num_bytes);
535                 rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
536         } else {
537                 rc = hwrm_send_message_silent(bp, msg, msg_len,
538                                               HWRM_CMD_TIMEOUT);
539                 if (!rc) {
540                         bnxt_copy_from_nvm_data(val, data,
541                                                 nvm_param.nvm_num_bits,
542                                                 nvm_param.dl_num_bytes);
543                 } else {
544                         struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
545
546                         if (resp->cmd_err ==
547                                 NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST)
548                                 rc = -EOPNOTSUPP;
549                 }
550         }
551         dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr);
552         if (rc == -EACCES)
553                 netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
554         return rc;
555 }
556
557 static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
558                                  struct devlink_param_gset_ctx *ctx)
559 {
560         struct hwrm_nvm_get_variable_input req = {0};
561         struct bnxt *bp = bnxt_get_bp_from_dl(dl);
562         int rc;
563
564         bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
565         rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
566         if (!rc)
567                 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
568                         ctx->val.vbool = !ctx->val.vbool;
569
570         return rc;
571 }
572
573 static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
574                                  struct devlink_param_gset_ctx *ctx)
575 {
576         struct hwrm_nvm_set_variable_input req = {0};
577         struct bnxt *bp = bnxt_get_bp_from_dl(dl);
578
579         bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1);
580
581         if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
582                 ctx->val.vbool = !ctx->val.vbool;
583
584         return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
585 }
586
587 static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
588                                  union devlink_param_value val,
589                                  struct netlink_ext_ack *extack)
590 {
591         int max_val = -1;
592
593         if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX)
594                 max_val = BNXT_MSIX_VEC_MAX;
595
596         if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
597                 max_val = BNXT_MSIX_VEC_MIN_MAX;
598
599         if (val.vu32 > max_val) {
600                 NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
601                 return -EINVAL;
602         }
603
604         return 0;
605 }
606
607 static const struct devlink_param bnxt_dl_params[] = {
608         DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
609                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
610                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
611                               NULL),
612         DEVLINK_PARAM_GENERIC(IGNORE_ARI,
613                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
614                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
615                               NULL),
616         DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX,
617                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
618                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
619                               bnxt_dl_msix_validate),
620         DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN,
621                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
622                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
623                               bnxt_dl_msix_validate),
624         DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
625                              "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL,
626                              BIT(DEVLINK_PARAM_CMODE_PERMANENT),
627                              bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
628                              NULL),
629 };
630
631 static const struct devlink_param bnxt_dl_port_params[] = {
632 };
633
634 static int bnxt_dl_params_register(struct bnxt *bp)
635 {
636         int rc;
637
638         if (bp->hwrm_spec_code < 0x10600)
639                 return 0;
640
641         rc = devlink_params_register(bp->dl, bnxt_dl_params,
642                                      ARRAY_SIZE(bnxt_dl_params));
643         if (rc) {
644                 netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
645                             rc);
646                 return rc;
647         }
648         rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
649                                           ARRAY_SIZE(bnxt_dl_port_params));
650         if (rc) {
651                 netdev_err(bp->dev, "devlink_port_params_register failed");
652                 devlink_params_unregister(bp->dl, bnxt_dl_params,
653                                           ARRAY_SIZE(bnxt_dl_params));
654                 return rc;
655         }
656         devlink_params_publish(bp->dl);
657
658         return 0;
659 }
660
661 static void bnxt_dl_params_unregister(struct bnxt *bp)
662 {
663         if (bp->hwrm_spec_code < 0x10600)
664                 return;
665
666         devlink_params_unregister(bp->dl, bnxt_dl_params,
667                                   ARRAY_SIZE(bnxt_dl_params));
668         devlink_port_params_unregister(&bp->dl_port, bnxt_dl_port_params,
669                                        ARRAY_SIZE(bnxt_dl_port_params));
670 }
671
672 int bnxt_dl_register(struct bnxt *bp)
673 {
674         struct devlink *dl;
675         int rc;
676
677         if (BNXT_PF(bp))
678                 dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
679         else
680                 dl = devlink_alloc(&bnxt_vf_dl_ops, sizeof(struct bnxt_dl));
681         if (!dl) {
682                 netdev_warn(bp->dev, "devlink_alloc failed");
683                 return -ENOMEM;
684         }
685
686         bnxt_link_bp_to_dl(bp, dl);
687
688         /* Add switchdev eswitch mode setting, if SRIOV supported */
689         if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
690             bp->hwrm_spec_code > 0x10803)
691                 bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
692
693         rc = devlink_register(dl, &bp->pdev->dev);
694         if (rc) {
695                 netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
696                 goto err_dl_free;
697         }
698
699         if (!BNXT_PF(bp))
700                 return 0;
701
702         devlink_port_attrs_set(&bp->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
703                                bp->pf.port_id, false, 0, bp->dsn,
704                                sizeof(bp->dsn));
705         rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
706         if (rc) {
707                 netdev_err(bp->dev, "devlink_port_register failed");
708                 goto err_dl_unreg;
709         }
710
711         rc = bnxt_dl_params_register(bp);
712         if (rc)
713                 goto err_dl_port_unreg;
714
715         return 0;
716
717 err_dl_port_unreg:
718         devlink_port_unregister(&bp->dl_port);
719 err_dl_unreg:
720         devlink_unregister(dl);
721 err_dl_free:
722         bnxt_link_bp_to_dl(bp, NULL);
723         devlink_free(dl);
724         return rc;
725 }
726
727 void bnxt_dl_unregister(struct bnxt *bp)
728 {
729         struct devlink *dl = bp->dl;
730
731         if (!dl)
732                 return;
733
734         if (BNXT_PF(bp)) {
735                 bnxt_dl_params_unregister(bp);
736                 devlink_port_unregister(&bp->dl_port);
737         }
738         devlink_unregister(dl);
739         devlink_free(dl);
740 }