Merge tag 'armsoc-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[sfrench/cifs-2.6.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                 rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
104         } else {
105                 rc = hwrm_send_message_silent(bp, msg, msg_len,
106                                               HWRM_CMD_TIMEOUT);
107         }
108         if (!rc && req->req_type == cpu_to_le16(HWRM_NVM_GET_VARIABLE))
109                 memcpy(buf, data_addr, bytesize);
110
111         dma_free_coherent(&bp->pdev->dev, bytesize, data_addr, data_dma_addr);
112         if (rc == HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED) {
113                 netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
114                 return -EACCES;
115         } else if (rc) {
116                 return -EIO;
117         }
118         return 0;
119 }
120
121 static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
122                                  struct devlink_param_gset_ctx *ctx)
123 {
124         struct hwrm_nvm_get_variable_input req = {0};
125         struct bnxt *bp = bnxt_get_bp_from_dl(dl);
126         int rc;
127
128         bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
129         rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
130         if (!rc)
131                 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
132                         ctx->val.vbool = !ctx->val.vbool;
133
134         return rc;
135 }
136
137 static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
138                                  struct devlink_param_gset_ctx *ctx)
139 {
140         struct hwrm_nvm_set_variable_input req = {0};
141         struct bnxt *bp = bnxt_get_bp_from_dl(dl);
142
143         bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1);
144
145         if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
146                 ctx->val.vbool = !ctx->val.vbool;
147
148         return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
149 }
150
151 static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
152                                  union devlink_param_value val,
153                                  struct netlink_ext_ack *extack)
154 {
155         int max_val = -1;
156
157         if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX)
158                 max_val = BNXT_MSIX_VEC_MAX;
159
160         if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
161                 max_val = BNXT_MSIX_VEC_MIN_MAX;
162
163         if (val.vu32 > max_val) {
164                 NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
165                 return -EINVAL;
166         }
167
168         return 0;
169 }
170
171 static const struct devlink_param bnxt_dl_params[] = {
172         DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
173                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
174                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
175                               NULL),
176         DEVLINK_PARAM_GENERIC(IGNORE_ARI,
177                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
178                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
179                               NULL),
180         DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX,
181                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
182                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
183                               bnxt_dl_msix_validate),
184         DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN,
185                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
186                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
187                               bnxt_dl_msix_validate),
188         DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
189                              "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL,
190                              BIT(DEVLINK_PARAM_CMODE_PERMANENT),
191                              bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
192                              NULL),
193 };
194
195 static const struct devlink_param bnxt_dl_port_params[] = {
196 };
197
198 int bnxt_dl_register(struct bnxt *bp)
199 {
200         struct devlink *dl;
201         int rc;
202
203         if (bp->hwrm_spec_code < 0x10600) {
204                 netdev_warn(bp->dev, "Firmware does not support NVM params");
205                 return -ENOTSUPP;
206         }
207
208         dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
209         if (!dl) {
210                 netdev_warn(bp->dev, "devlink_alloc failed");
211                 return -ENOMEM;
212         }
213
214         bnxt_link_bp_to_dl(bp, dl);
215
216         /* Add switchdev eswitch mode setting, if SRIOV supported */
217         if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
218             bp->hwrm_spec_code > 0x10803)
219                 bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
220
221         rc = devlink_register(dl, &bp->pdev->dev);
222         if (rc) {
223                 netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
224                 goto err_dl_free;
225         }
226
227         rc = devlink_params_register(dl, bnxt_dl_params,
228                                      ARRAY_SIZE(bnxt_dl_params));
229         if (rc) {
230                 netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
231                             rc);
232                 goto err_dl_unreg;
233         }
234
235         devlink_port_attrs_set(&bp->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
236                                bp->pf.port_id, false, 0,
237                                bp->switch_id, sizeof(bp->switch_id));
238         rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
239         if (rc) {
240                 netdev_err(bp->dev, "devlink_port_register failed");
241                 goto err_dl_param_unreg;
242         }
243         devlink_port_type_eth_set(&bp->dl_port, bp->dev);
244
245         rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
246                                           ARRAY_SIZE(bnxt_dl_port_params));
247         if (rc) {
248                 netdev_err(bp->dev, "devlink_port_params_register failed");
249                 goto err_dl_port_unreg;
250         }
251
252         devlink_params_publish(dl);
253
254         return 0;
255
256 err_dl_port_unreg:
257         devlink_port_unregister(&bp->dl_port);
258 err_dl_param_unreg:
259         devlink_params_unregister(dl, bnxt_dl_params,
260                                   ARRAY_SIZE(bnxt_dl_params));
261 err_dl_unreg:
262         devlink_unregister(dl);
263 err_dl_free:
264         bnxt_link_bp_to_dl(bp, NULL);
265         devlink_free(dl);
266         return rc;
267 }
268
269 void bnxt_dl_unregister(struct bnxt *bp)
270 {
271         struct devlink *dl = bp->dl;
272
273         if (!dl)
274                 return;
275
276         devlink_port_params_unregister(&bp->dl_port, bnxt_dl_port_params,
277                                        ARRAY_SIZE(bnxt_dl_port_params));
278         devlink_port_unregister(&bp->dl_port);
279         devlink_params_unregister(dl, bnxt_dl_params,
280                                   ARRAY_SIZE(bnxt_dl_params));
281         devlink_unregister(dl);
282         devlink_free(dl);
283 }