549c90d3e465f2fd4f7eb494cee47373b953aaf5
[linux-2.6-microblaze.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
18 static const struct devlink_ops bnxt_dl_ops = {
19 #ifdef CONFIG_BNXT_SRIOV
20         .eswitch_mode_set = bnxt_dl_eswitch_mode_set,
21         .eswitch_mode_get = bnxt_dl_eswitch_mode_get,
22 #endif /* CONFIG_BNXT_SRIOV */
23 };
24
25 enum bnxt_dl_param_id {
26         BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
27         BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
28 };
29
30 static const struct bnxt_dl_nvm_param nvm_params[] = {
31         {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV,
32          BNXT_NVM_SHARED_CFG, 1},
33         {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI,
34          BNXT_NVM_SHARED_CFG, 1},
35         {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
36          NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10},
37         {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
38          NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7},
39         {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK,
40          BNXT_NVM_SHARED_CFG, 1},
41 };
42
43 static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
44                              int msg_len, union devlink_param_value *val)
45 {
46         struct hwrm_nvm_get_variable_input *req = msg;
47         void *data_addr = NULL, *buf = NULL;
48         struct bnxt_dl_nvm_param nvm_param;
49         int bytesize, idx = 0, rc, i;
50         dma_addr_t data_dma_addr;
51
52         /* Get/Set NVM CFG parameter is supported only on PFs */
53         if (BNXT_VF(bp))
54                 return -EPERM;
55
56         for (i = 0; i < ARRAY_SIZE(nvm_params); i++) {
57                 if (nvm_params[i].id == param_id) {
58                         nvm_param = nvm_params[i];
59                         break;
60                 }
61         }
62
63         if (i == ARRAY_SIZE(nvm_params))
64                 return -EOPNOTSUPP;
65
66         if (nvm_param.dir_type == BNXT_NVM_PORT_CFG)
67                 idx = bp->pf.port_id;
68         else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG)
69                 idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID;
70
71         bytesize = roundup(nvm_param.num_bits, BITS_PER_BYTE) / BITS_PER_BYTE;
72         switch (bytesize) {
73         case 1:
74                 if (nvm_param.num_bits == 1)
75                         buf = &val->vbool;
76                 else
77                         buf = &val->vu8;
78                 break;
79         case 2:
80                 buf = &val->vu16;
81                 break;
82         case 4:
83                 buf = &val->vu32;
84                 break;
85         default:
86                 return -EFAULT;
87         }
88
89         data_addr = dma_alloc_coherent(&bp->pdev->dev, bytesize,
90                                        &data_dma_addr, GFP_KERNEL);
91         if (!data_addr)
92                 return -ENOMEM;
93
94         req->dest_data_addr = cpu_to_le64(data_dma_addr);
95         req->data_len = cpu_to_le16(nvm_param.num_bits);
96         req->option_num = cpu_to_le16(nvm_param.offset);
97         req->index_0 = cpu_to_le16(idx);
98         if (idx)
99                 req->dimensions = cpu_to_le16(1);
100
101         if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE))
102                 memcpy(data_addr, buf, bytesize);
103
104         rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
105         if (!rc && req->req_type == cpu_to_le16(HWRM_NVM_GET_VARIABLE))
106                 memcpy(buf, data_addr, bytesize);
107
108         dma_free_coherent(&bp->pdev->dev, bytesize, data_addr, data_dma_addr);
109         if (rc == HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED) {
110                 netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
111                 return -EACCES;
112         } else if (rc) {
113                 return -EIO;
114         }
115         return 0;
116 }
117
118 static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
119                                  struct devlink_param_gset_ctx *ctx)
120 {
121         struct hwrm_nvm_get_variable_input req = {0};
122         struct bnxt *bp = bnxt_get_bp_from_dl(dl);
123         int rc;
124
125         bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
126         rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
127         if (!rc)
128                 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
129                         ctx->val.vbool = !ctx->val.vbool;
130
131         return rc;
132 }
133
134 static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
135                                  struct devlink_param_gset_ctx *ctx)
136 {
137         struct hwrm_nvm_set_variable_input req = {0};
138         struct bnxt *bp = bnxt_get_bp_from_dl(dl);
139
140         bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1);
141
142         if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
143                 ctx->val.vbool = !ctx->val.vbool;
144
145         return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
146 }
147
148 static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
149                                  union devlink_param_value val,
150                                  struct netlink_ext_ack *extack)
151 {
152         int max_val = -1;
153
154         if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX)
155                 max_val = BNXT_MSIX_VEC_MAX;
156
157         if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
158                 max_val = BNXT_MSIX_VEC_MIN_MAX;
159
160         if (val.vu32 > max_val) {
161                 NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
162                 return -EINVAL;
163         }
164
165         return 0;
166 }
167
168 static const struct devlink_param bnxt_dl_params[] = {
169         DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
170                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
171                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
172                               NULL),
173         DEVLINK_PARAM_GENERIC(IGNORE_ARI,
174                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
175                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
176                               NULL),
177         DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX,
178                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
179                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
180                               bnxt_dl_msix_validate),
181         DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN,
182                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
183                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
184                               bnxt_dl_msix_validate),
185         DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
186                              "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL,
187                              BIT(DEVLINK_PARAM_CMODE_PERMANENT),
188                              bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
189                              NULL),
190 };
191
192 static const struct devlink_param bnxt_dl_port_params[] = {
193 };
194
195 int bnxt_dl_register(struct bnxt *bp)
196 {
197         struct devlink *dl;
198         int rc;
199
200         if (bp->hwrm_spec_code < 0x10600) {
201                 netdev_warn(bp->dev, "Firmware does not support NVM params");
202                 return -ENOTSUPP;
203         }
204
205         dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
206         if (!dl) {
207                 netdev_warn(bp->dev, "devlink_alloc failed");
208                 return -ENOMEM;
209         }
210
211         bnxt_link_bp_to_dl(bp, dl);
212
213         /* Add switchdev eswitch mode setting, if SRIOV supported */
214         if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
215             bp->hwrm_spec_code > 0x10803)
216                 bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
217
218         rc = devlink_register(dl, &bp->pdev->dev);
219         if (rc) {
220                 netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
221                 goto err_dl_free;
222         }
223
224         rc = devlink_params_register(dl, bnxt_dl_params,
225                                      ARRAY_SIZE(bnxt_dl_params));
226         if (rc) {
227                 netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
228                             rc);
229                 goto err_dl_unreg;
230         }
231
232         devlink_port_attrs_set(&bp->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
233                                bp->pf.port_id, false, 0,
234                                bp->switch_id, sizeof(bp->switch_id));
235         rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
236         if (rc) {
237                 netdev_err(bp->dev, "devlink_port_register failed");
238                 goto err_dl_param_unreg;
239         }
240         devlink_port_type_eth_set(&bp->dl_port, bp->dev);
241
242         rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
243                                           ARRAY_SIZE(bnxt_dl_port_params));
244         if (rc) {
245                 netdev_err(bp->dev, "devlink_port_params_register failed");
246                 goto err_dl_port_unreg;
247         }
248
249         devlink_params_publish(dl);
250
251         return 0;
252
253 err_dl_port_unreg:
254         devlink_port_unregister(&bp->dl_port);
255 err_dl_param_unreg:
256         devlink_params_unregister(dl, bnxt_dl_params,
257                                   ARRAY_SIZE(bnxt_dl_params));
258 err_dl_unreg:
259         devlink_unregister(dl);
260 err_dl_free:
261         bnxt_link_bp_to_dl(bp, NULL);
262         devlink_free(dl);
263         return rc;
264 }
265
266 void bnxt_dl_unregister(struct bnxt *bp)
267 {
268         struct devlink *dl = bp->dl;
269
270         if (!dl)
271                 return;
272
273         devlink_port_params_unregister(&bp->dl_port, bnxt_dl_port_params,
274                                        ARRAY_SIZE(bnxt_dl_port_params));
275         devlink_port_unregister(&bp->dl_port);
276         devlink_params_unregister(dl, bnxt_dl_params,
277                                   ARRAY_SIZE(bnxt_dl_params));
278         devlink_unregister(dl);
279         devlink_free(dl);
280 }