brintos

brintos / linux-shallow public Read only

0
0
Text · 8.9 KiB · ea75b9a Raw
370 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/* Copyright (C) 2017-2018 Netronome Systems, Inc. */3 4#include <linux/rtnetlink.h>5#include <net/devlink.h>6 7#include "nfpcore/nfp.h"8#include "nfpcore/nfp_nsp.h"9#include "nfp_app.h"10#include "nfp_main.h"11#include "nfp_port.h"12 13static int14nfp_devlink_fill_eth_port(struct nfp_port *port,15			  struct nfp_eth_table_port *copy)16{17	struct nfp_eth_table_port *eth_port;18 19	eth_port = __nfp_port_get_eth_port(port);20	if (!eth_port)21		return -EINVAL;22 23	memcpy(copy, eth_port, sizeof(*eth_port));24 25	return 0;26}27 28static int29nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf,30				  struct devlink_port *dl_port,31				  struct nfp_eth_table_port *copy)32{33	struct nfp_port *port = container_of(dl_port, struct nfp_port, dl_port);34 35	return nfp_devlink_fill_eth_port(port, copy);36}37 38static int39nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes)40{41	struct nfp_nsp *nsp;42	int ret;43 44	nsp = nfp_eth_config_start(pf->cpp, idx);45	if (IS_ERR(nsp))46		return PTR_ERR(nsp);47 48	ret = __nfp_eth_set_split(nsp, lanes);49	if (ret) {50		nfp_eth_config_cleanup_end(nsp);51		return ret;52	}53 54	ret = nfp_eth_config_commit_end(nsp);55	if (ret < 0)56		return ret;57	if (ret) /* no change */58		return 0;59 60	return nfp_net_refresh_port_table_sync(pf);61}62 63static int64nfp_devlink_port_split(struct devlink *devlink, struct devlink_port *port,65		       unsigned int count, struct netlink_ext_ack *extack)66{67	struct nfp_pf *pf = devlink_priv(devlink);68	struct nfp_eth_table_port eth_port;69	unsigned int lanes;70	int ret;71 72	rtnl_lock();73	ret = nfp_devlink_fill_eth_port_from_id(pf, port, &eth_port);74	rtnl_unlock();75	if (ret)76		return ret;77 78	if (eth_port.port_lanes % count) {79		NL_SET_ERR_MSG_MOD(extack, "invalid count");80		return -EINVAL;81	}82 83	/* Special case the 100G CXP -> 2x40G split */84	lanes = eth_port.port_lanes / count;85	if (eth_port.lanes == 10 && count == 2)86		lanes = 8 / count;87 88	return nfp_devlink_set_lanes(pf, eth_port.index, lanes);89}90 91static int92nfp_devlink_port_unsplit(struct devlink *devlink, struct devlink_port *port,93			 struct netlink_ext_ack *extack)94{95	struct nfp_pf *pf = devlink_priv(devlink);96	struct nfp_eth_table_port eth_port;97	unsigned int lanes;98	int ret;99 100	rtnl_lock();101	ret = nfp_devlink_fill_eth_port_from_id(pf, port, &eth_port);102	rtnl_unlock();103	if (ret)104		return ret;105 106	if (!eth_port.is_split) {107		NL_SET_ERR_MSG_MOD(extack, "port is not split");108		return -EINVAL;109	}110 111	/* Special case the 100G CXP -> 2x40G unsplit */112	lanes = eth_port.port_lanes;113	if (eth_port.port_lanes == 8)114		lanes = 10;115 116	return nfp_devlink_set_lanes(pf, eth_port.index, lanes);117}118 119static int120nfp_devlink_sb_pool_get(struct devlink *devlink, unsigned int sb_index,121			u16 pool_index, struct devlink_sb_pool_info *pool_info)122{123	struct nfp_pf *pf = devlink_priv(devlink);124 125	return nfp_shared_buf_pool_get(pf, sb_index, pool_index, pool_info);126}127 128static int129nfp_devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,130			u16 pool_index,131			u32 size, enum devlink_sb_threshold_type threshold_type,132			struct netlink_ext_ack *extack)133{134	struct nfp_pf *pf = devlink_priv(devlink);135 136	return nfp_shared_buf_pool_set(pf, sb_index, pool_index,137				       size, threshold_type);138}139 140static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)141{142	struct nfp_pf *pf = devlink_priv(devlink);143 144	return nfp_app_eswitch_mode_get(pf->app, mode);145}146 147static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,148					struct netlink_ext_ack *extack)149{150	struct nfp_pf *pf = devlink_priv(devlink);151 152	return nfp_app_eswitch_mode_set(pf->app, mode);153}154 155static const struct nfp_devlink_versions_simple {156	const char *key;157	const char *hwinfo;158} nfp_devlink_versions_hwinfo[] = {159	{ DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,	"assembly.partno", },160	{ DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,	"assembly.revision", },161	{ DEVLINK_INFO_VERSION_GENERIC_BOARD_MANUFACTURE, "assembly.vendor", },162	{ "board.model", /* code name */		"assembly.model", },163	{ DEVLINK_INFO_VERSION_GENERIC_BOARD_PART_NUMBER, "pn", },164};165 166static int167nfp_devlink_versions_get_hwinfo(struct nfp_pf *pf, struct devlink_info_req *req)168{169	unsigned int i;170	int err;171 172	for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_hwinfo); i++) {173		const struct nfp_devlink_versions_simple *info;174		const char *val;175 176		info = &nfp_devlink_versions_hwinfo[i];177 178		val = nfp_hwinfo_lookup(pf->hwinfo, info->hwinfo);179		if (!val)180			continue;181 182		err = devlink_info_version_fixed_put(req, info->key, val);183		if (err)184			return err;185	}186 187	return 0;188}189 190static const struct nfp_devlink_versions {191	enum nfp_nsp_versions id;192	const char *key;193} nfp_devlink_versions_nsp[] = {194	{ NFP_VERSIONS_BUNDLE,	DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, },195	{ NFP_VERSIONS_BSP,	DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, },196	{ NFP_VERSIONS_CPLD,	"fw.cpld", },197	{ NFP_VERSIONS_APP,	DEVLINK_INFO_VERSION_GENERIC_FW_APP, },198	{ NFP_VERSIONS_UNDI,	DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, },199	{ NFP_VERSIONS_NCSI,	DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, },200	{ NFP_VERSIONS_CFGR,	"chip.init", },201};202 203static int204nfp_devlink_versions_get_nsp(struct devlink_info_req *req, bool flash,205			     const u8 *buf, unsigned int size)206{207	unsigned int i;208	int err;209 210	for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_nsp); i++) {211		const struct nfp_devlink_versions *info;212		const char *version;213 214		info = &nfp_devlink_versions_nsp[i];215 216		version = nfp_nsp_versions_get(info->id, flash, buf, size);217		if (IS_ERR(version)) {218			if (PTR_ERR(version) == -ENOENT)219				continue;220			else221				return PTR_ERR(version);222		}223 224		if (flash)225			err = devlink_info_version_stored_put(req, info->key,226							      version);227		else228			err = devlink_info_version_running_put(req, info->key,229							       version);230		if (err)231			return err;232	}233 234	return 0;235}236 237static int238nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,239		     struct netlink_ext_ack *extack)240{241	struct nfp_pf *pf = devlink_priv(devlink);242	const char *sn, *vendor, *part;243	struct nfp_nsp *nsp;244	char *buf = NULL;245	int err;246 247	vendor = nfp_hwinfo_lookup(pf->hwinfo, "assembly.vendor");248	part = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno");249	sn = nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial");250	if (vendor && part && sn) {251		char *buf;252 253		buf = kmalloc(strlen(vendor) + strlen(part) + strlen(sn) + 1,254			      GFP_KERNEL);255		if (!buf)256			return -ENOMEM;257 258		buf[0] = '\0';259		strcat(buf, vendor);260		strcat(buf, part);261		strcat(buf, sn);262 263		err = devlink_info_serial_number_put(req, buf);264		kfree(buf);265		if (err)266			return err;267	}268 269	nsp = nfp_nsp_open(pf->cpp);270	if (IS_ERR(nsp)) {271		NL_SET_ERR_MSG_MOD(extack, "can't access NSP");272		return PTR_ERR(nsp);273	}274 275	if (nfp_nsp_has_versions(nsp)) {276		buf = kzalloc(NFP_NSP_VERSION_BUFSZ, GFP_KERNEL);277		if (!buf) {278			err = -ENOMEM;279			goto err_close_nsp;280		}281 282		err = nfp_nsp_versions(nsp, buf, NFP_NSP_VERSION_BUFSZ);283		if (err)284			goto err_free_buf;285 286		err = nfp_devlink_versions_get_nsp(req, false,287						   buf, NFP_NSP_VERSION_BUFSZ);288		if (err)289			goto err_free_buf;290 291		err = nfp_devlink_versions_get_nsp(req, true,292						   buf, NFP_NSP_VERSION_BUFSZ);293		if (err)294			goto err_free_buf;295 296		kfree(buf);297	}298 299	nfp_nsp_close(nsp);300 301	return nfp_devlink_versions_get_hwinfo(pf, req);302 303err_free_buf:304	kfree(buf);305err_close_nsp:306	nfp_nsp_close(nsp);307	return err;308}309 310static int311nfp_devlink_flash_update(struct devlink *devlink,312			 struct devlink_flash_update_params *params,313			 struct netlink_ext_ack *extack)314{315	return nfp_flash_update_common(devlink_priv(devlink), params->fw, extack);316}317 318const struct devlink_ops nfp_devlink_ops = {319	.sb_pool_get		= nfp_devlink_sb_pool_get,320	.sb_pool_set		= nfp_devlink_sb_pool_set,321	.eswitch_mode_get	= nfp_devlink_eswitch_mode_get,322	.eswitch_mode_set	= nfp_devlink_eswitch_mode_set,323	.info_get		= nfp_devlink_info_get,324	.flash_update		= nfp_devlink_flash_update,325};326 327static const struct devlink_port_ops nfp_devlink_port_ops = {328	.port_split		= nfp_devlink_port_split,329	.port_unsplit		= nfp_devlink_port_unsplit,330};331 332int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)333{334	struct devlink_port_attrs attrs = {};335	struct nfp_eth_table_port eth_port;336	struct devlink *devlink;337	const u8 *serial;338	int serial_len;339	int ret;340 341	SET_NETDEV_DEVLINK_PORT(port->netdev, &port->dl_port);342 343	rtnl_lock();344	ret = nfp_devlink_fill_eth_port(port, &eth_port);345	rtnl_unlock();346	if (ret)347		return ret;348 349	attrs.split = eth_port.is_split;350	attrs.splittable = eth_port.port_lanes > 1 && !attrs.split;351	attrs.lanes = eth_port.port_lanes;352	attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;353	attrs.phys.port_number = eth_port.label_port;354	attrs.phys.split_subport_number = eth_port.label_subport;355	serial_len = nfp_cpp_serial(port->app->cpp, &serial);356	memcpy(attrs.switch_id.id, serial, serial_len);357	attrs.switch_id.id_len = serial_len;358	devlink_port_attrs_set(&port->dl_port, &attrs);359 360	devlink = priv_to_devlink(app->pf);361 362	return devl_port_register_with_ops(devlink, &port->dl_port,363					   port->eth_id, &nfp_devlink_port_ops);364}365 366void nfp_devlink_port_unregister(struct nfp_port *port)367{368	devl_port_unregister(&port->dl_port);369}370