0001
0002
0003
0004 #include <linux/rtnetlink.h>
0005 #include <net/devlink.h>
0006
0007 #include "nfpcore/nfp.h"
0008 #include "nfpcore/nfp_nsp.h"
0009 #include "nfp_app.h"
0010 #include "nfp_main.h"
0011 #include "nfp_port.h"
0012
0013 static int
0014 nfp_devlink_fill_eth_port(struct nfp_port *port,
0015 struct nfp_eth_table_port *copy)
0016 {
0017 struct nfp_eth_table_port *eth_port;
0018
0019 eth_port = __nfp_port_get_eth_port(port);
0020 if (!eth_port)
0021 return -EINVAL;
0022
0023 memcpy(copy, eth_port, sizeof(*eth_port));
0024
0025 return 0;
0026 }
0027
0028 static int
0029 nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf,
0030 struct devlink_port *dl_port,
0031 struct nfp_eth_table_port *copy)
0032 {
0033 struct nfp_port *port = container_of(dl_port, struct nfp_port, dl_port);
0034
0035 return nfp_devlink_fill_eth_port(port, copy);
0036 }
0037
0038 static int
0039 nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes)
0040 {
0041 struct nfp_nsp *nsp;
0042 int ret;
0043
0044 nsp = nfp_eth_config_start(pf->cpp, idx);
0045 if (IS_ERR(nsp))
0046 return PTR_ERR(nsp);
0047
0048 ret = __nfp_eth_set_split(nsp, lanes);
0049 if (ret) {
0050 nfp_eth_config_cleanup_end(nsp);
0051 return ret;
0052 }
0053
0054 ret = nfp_eth_config_commit_end(nsp);
0055 if (ret < 0)
0056 return ret;
0057 if (ret)
0058 return 0;
0059
0060 return nfp_net_refresh_port_table_sync(pf);
0061 }
0062
0063 static int
0064 nfp_devlink_port_split(struct devlink *devlink, struct devlink_port *port,
0065 unsigned int count, struct netlink_ext_ack *extack)
0066 {
0067 struct nfp_pf *pf = devlink_priv(devlink);
0068 struct nfp_eth_table_port eth_port;
0069 unsigned int lanes;
0070 int ret;
0071
0072 rtnl_lock();
0073 ret = nfp_devlink_fill_eth_port_from_id(pf, port, ð_port);
0074 rtnl_unlock();
0075 if (ret)
0076 return ret;
0077
0078 if (eth_port.port_lanes % count)
0079 return -EINVAL;
0080
0081
0082 lanes = eth_port.port_lanes / count;
0083 if (eth_port.lanes == 10 && count == 2)
0084 lanes = 8 / count;
0085
0086 return nfp_devlink_set_lanes(pf, eth_port.index, lanes);
0087 }
0088
0089 static int
0090 nfp_devlink_port_unsplit(struct devlink *devlink, struct devlink_port *port,
0091 struct netlink_ext_ack *extack)
0092 {
0093 struct nfp_pf *pf = devlink_priv(devlink);
0094 struct nfp_eth_table_port eth_port;
0095 unsigned int lanes;
0096 int ret;
0097
0098 rtnl_lock();
0099 ret = nfp_devlink_fill_eth_port_from_id(pf, port, ð_port);
0100 rtnl_unlock();
0101 if (ret)
0102 return ret;
0103
0104 if (!eth_port.is_split)
0105 return -EINVAL;
0106
0107
0108 lanes = eth_port.port_lanes;
0109 if (eth_port.port_lanes == 8)
0110 lanes = 10;
0111
0112 return nfp_devlink_set_lanes(pf, eth_port.index, lanes);
0113 }
0114
0115 static int
0116 nfp_devlink_sb_pool_get(struct devlink *devlink, unsigned int sb_index,
0117 u16 pool_index, struct devlink_sb_pool_info *pool_info)
0118 {
0119 struct nfp_pf *pf = devlink_priv(devlink);
0120
0121 return nfp_shared_buf_pool_get(pf, sb_index, pool_index, pool_info);
0122 }
0123
0124 static int
0125 nfp_devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
0126 u16 pool_index,
0127 u32 size, enum devlink_sb_threshold_type threshold_type,
0128 struct netlink_ext_ack *extack)
0129 {
0130 struct nfp_pf *pf = devlink_priv(devlink);
0131
0132 return nfp_shared_buf_pool_set(pf, sb_index, pool_index,
0133 size, threshold_type);
0134 }
0135
0136 static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
0137 {
0138 struct nfp_pf *pf = devlink_priv(devlink);
0139
0140 return nfp_app_eswitch_mode_get(pf->app, mode);
0141 }
0142
0143 static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
0144 struct netlink_ext_ack *extack)
0145 {
0146 struct nfp_pf *pf = devlink_priv(devlink);
0147
0148 return nfp_app_eswitch_mode_set(pf->app, mode);
0149 }
0150
0151 static const struct nfp_devlink_versions_simple {
0152 const char *key;
0153 const char *hwinfo;
0154 } nfp_devlink_versions_hwinfo[] = {
0155 { DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, "assembly.partno", },
0156 { DEVLINK_INFO_VERSION_GENERIC_BOARD_REV, "assembly.revision", },
0157 { DEVLINK_INFO_VERSION_GENERIC_BOARD_MANUFACTURE, "assembly.vendor", },
0158 { "board.model", "assembly.model", },
0159 };
0160
0161 static int
0162 nfp_devlink_versions_get_hwinfo(struct nfp_pf *pf, struct devlink_info_req *req)
0163 {
0164 unsigned int i;
0165 int err;
0166
0167 for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_hwinfo); i++) {
0168 const struct nfp_devlink_versions_simple *info;
0169 const char *val;
0170
0171 info = &nfp_devlink_versions_hwinfo[i];
0172
0173 val = nfp_hwinfo_lookup(pf->hwinfo, info->hwinfo);
0174 if (!val)
0175 continue;
0176
0177 err = devlink_info_version_fixed_put(req, info->key, val);
0178 if (err)
0179 return err;
0180 }
0181
0182 return 0;
0183 }
0184
0185 static const struct nfp_devlink_versions {
0186 enum nfp_nsp_versions id;
0187 const char *key;
0188 } nfp_devlink_versions_nsp[] = {
0189 { NFP_VERSIONS_BUNDLE, DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, },
0190 { NFP_VERSIONS_BSP, DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, },
0191 { NFP_VERSIONS_CPLD, "fw.cpld", },
0192 { NFP_VERSIONS_APP, DEVLINK_INFO_VERSION_GENERIC_FW_APP, },
0193 { NFP_VERSIONS_UNDI, DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, },
0194 { NFP_VERSIONS_NCSI, DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, },
0195 { NFP_VERSIONS_CFGR, "chip.init", },
0196 };
0197
0198 static int
0199 nfp_devlink_versions_get_nsp(struct devlink_info_req *req, bool flash,
0200 const u8 *buf, unsigned int size)
0201 {
0202 unsigned int i;
0203 int err;
0204
0205 for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_nsp); i++) {
0206 const struct nfp_devlink_versions *info;
0207 const char *version;
0208
0209 info = &nfp_devlink_versions_nsp[i];
0210
0211 version = nfp_nsp_versions_get(info->id, flash, buf, size);
0212 if (IS_ERR(version)) {
0213 if (PTR_ERR(version) == -ENOENT)
0214 continue;
0215 else
0216 return PTR_ERR(version);
0217 }
0218
0219 if (flash)
0220 err = devlink_info_version_stored_put(req, info->key,
0221 version);
0222 else
0223 err = devlink_info_version_running_put(req, info->key,
0224 version);
0225 if (err)
0226 return err;
0227 }
0228
0229 return 0;
0230 }
0231
0232 static int
0233 nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
0234 struct netlink_ext_ack *extack)
0235 {
0236 struct nfp_pf *pf = devlink_priv(devlink);
0237 const char *sn, *vendor, *part;
0238 struct nfp_nsp *nsp;
0239 char *buf = NULL;
0240 int err;
0241
0242 err = devlink_info_driver_name_put(req, "nfp");
0243 if (err)
0244 return err;
0245
0246 vendor = nfp_hwinfo_lookup(pf->hwinfo, "assembly.vendor");
0247 part = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno");
0248 sn = nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial");
0249 if (vendor && part && sn) {
0250 char *buf;
0251
0252 buf = kmalloc(strlen(vendor) + strlen(part) + strlen(sn) + 1,
0253 GFP_KERNEL);
0254 if (!buf)
0255 return -ENOMEM;
0256
0257 buf[0] = '\0';
0258 strcat(buf, vendor);
0259 strcat(buf, part);
0260 strcat(buf, sn);
0261
0262 err = devlink_info_serial_number_put(req, buf);
0263 kfree(buf);
0264 if (err)
0265 return err;
0266 }
0267
0268 nsp = nfp_nsp_open(pf->cpp);
0269 if (IS_ERR(nsp)) {
0270 NL_SET_ERR_MSG_MOD(extack, "can't access NSP");
0271 return PTR_ERR(nsp);
0272 }
0273
0274 if (nfp_nsp_has_versions(nsp)) {
0275 buf = kzalloc(NFP_NSP_VERSION_BUFSZ, GFP_KERNEL);
0276 if (!buf) {
0277 err = -ENOMEM;
0278 goto err_close_nsp;
0279 }
0280
0281 err = nfp_nsp_versions(nsp, buf, NFP_NSP_VERSION_BUFSZ);
0282 if (err)
0283 goto err_free_buf;
0284
0285 err = nfp_devlink_versions_get_nsp(req, false,
0286 buf, NFP_NSP_VERSION_BUFSZ);
0287 if (err)
0288 goto err_free_buf;
0289
0290 err = nfp_devlink_versions_get_nsp(req, true,
0291 buf, NFP_NSP_VERSION_BUFSZ);
0292 if (err)
0293 goto err_free_buf;
0294
0295 kfree(buf);
0296 }
0297
0298 nfp_nsp_close(nsp);
0299
0300 return nfp_devlink_versions_get_hwinfo(pf, req);
0301
0302 err_free_buf:
0303 kfree(buf);
0304 err_close_nsp:
0305 nfp_nsp_close(nsp);
0306 return err;
0307 }
0308
0309 static int
0310 nfp_devlink_flash_update(struct devlink *devlink,
0311 struct devlink_flash_update_params *params,
0312 struct netlink_ext_ack *extack)
0313 {
0314 return nfp_flash_update_common(devlink_priv(devlink), params->fw, extack);
0315 }
0316
0317 const struct devlink_ops nfp_devlink_ops = {
0318 .port_split = nfp_devlink_port_split,
0319 .port_unsplit = nfp_devlink_port_unsplit,
0320 .sb_pool_get = nfp_devlink_sb_pool_get,
0321 .sb_pool_set = nfp_devlink_sb_pool_set,
0322 .eswitch_mode_get = nfp_devlink_eswitch_mode_get,
0323 .eswitch_mode_set = nfp_devlink_eswitch_mode_set,
0324 .info_get = nfp_devlink_info_get,
0325 .flash_update = nfp_devlink_flash_update,
0326 };
0327
0328 int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
0329 {
0330 struct devlink_port_attrs attrs = {};
0331 struct nfp_eth_table_port eth_port;
0332 struct devlink *devlink;
0333 const u8 *serial;
0334 int serial_len;
0335 int ret;
0336
0337 rtnl_lock();
0338 ret = nfp_devlink_fill_eth_port(port, ð_port);
0339 rtnl_unlock();
0340 if (ret)
0341 return ret;
0342
0343 attrs.split = eth_port.is_split;
0344 attrs.splittable = !attrs.split;
0345 attrs.lanes = eth_port.port_lanes;
0346 attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
0347 attrs.phys.port_number = eth_port.label_port;
0348 attrs.phys.split_subport_number = eth_port.label_subport;
0349 serial_len = nfp_cpp_serial(port->app->cpp, &serial);
0350 memcpy(attrs.switch_id.id, serial, serial_len);
0351 attrs.switch_id.id_len = serial_len;
0352 devlink_port_attrs_set(&port->dl_port, &attrs);
0353
0354 devlink = priv_to_devlink(app->pf);
0355
0356 return devl_port_register(devlink, &port->dl_port, port->eth_id);
0357 }
0358
0359 void nfp_devlink_port_unregister(struct nfp_port *port)
0360 {
0361 devl_port_unregister(&port->dl_port);
0362 }
0363
0364 void nfp_devlink_port_type_eth_set(struct nfp_port *port)
0365 {
0366 devlink_port_type_eth_set(&port->dl_port, port->netdev);
0367 }
0368
0369 void nfp_devlink_port_type_clear(struct nfp_port *port)
0370 {
0371 devlink_port_type_clear(&port->dl_port);
0372 }
0373
0374 struct devlink_port *nfp_devlink_get_devlink_port(struct net_device *netdev)
0375 {
0376 struct nfp_port *port;
0377
0378 port = nfp_port_from_netdev(netdev);
0379 if (!port)
0380 return NULL;
0381
0382 return &port->dl_port;
0383 }