Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
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) /* no change */
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, &eth_port);
0074     rtnl_unlock();
0075     if (ret)
0076         return ret;
0077 
0078     if (eth_port.port_lanes % count)
0079         return -EINVAL;
0080 
0081     /* Special case the 100G CXP -> 2x40G split */
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, &eth_port);
0100     rtnl_unlock();
0101     if (ret)
0102         return ret;
0103 
0104     if (!eth_port.is_split)
0105         return -EINVAL;
0106 
0107     /* Special case the 100G CXP -> 2x40G unsplit */
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", /* code name */        "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, &eth_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 }