18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2020, Intel Corporation. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include "ice.h"
58c2ecf20Sopenharmony_ci#include "ice_lib.h"
68c2ecf20Sopenharmony_ci#include "ice_devlink.h"
78c2ecf20Sopenharmony_ci#include "ice_fw_update.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_cistatic void ice_info_get_dsn(struct ice_pf *pf, char *buf, size_t len)
108c2ecf20Sopenharmony_ci{
118c2ecf20Sopenharmony_ci	u8 dsn[8];
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci	/* Copy the DSN into an array in Big Endian format */
148c2ecf20Sopenharmony_ci	put_unaligned_be64(pci_get_dsn(pf->pdev), dsn);
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci	snprintf(buf, len, "%8phD", dsn);
178c2ecf20Sopenharmony_ci}
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic int ice_info_pba(struct ice_pf *pf, char *buf, size_t len)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
228c2ecf20Sopenharmony_ci	enum ice_status status;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	status = ice_read_pba_string(hw, (u8 *)buf, len);
258c2ecf20Sopenharmony_ci	if (status)
268c2ecf20Sopenharmony_ci		/* We failed to locate the PBA, so just skip this entry */
278c2ecf20Sopenharmony_ci		dev_dbg(ice_pf_to_dev(pf), "Failed to read Product Board Assembly string, status %s\n",
288c2ecf20Sopenharmony_ci			ice_stat_str(status));
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	return 0;
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic int ice_info_fw_mgmt(struct ice_pf *pf, char *buf, size_t len)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	snprintf(buf, len, "%u.%u.%u", hw->fw_maj_ver, hw->fw_min_ver,
388c2ecf20Sopenharmony_ci		 hw->fw_patch);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	return 0;
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic int ice_info_fw_api(struct ice_pf *pf, char *buf, size_t len)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	snprintf(buf, len, "%u.%u", hw->api_maj_ver, hw->api_min_ver);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	return 0;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic int ice_info_fw_build(struct ice_pf *pf, char *buf, size_t len)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	snprintf(buf, len, "0x%08x", hw->fw_build);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return 0;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int ice_info_orom_ver(struct ice_pf *pf, char *buf, size_t len)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct ice_orom_info *orom = &pf->hw.nvm.orom;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	snprintf(buf, len, "%u.%u.%u", orom->major, orom->build, orom->patch);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	return 0;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic int ice_info_nvm_ver(struct ice_pf *pf, char *buf, size_t len)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct ice_nvm_info *nvm = &pf->hw.nvm;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	snprintf(buf, len, "%x.%02x", nvm->major_ver, nvm->minor_ver);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return 0;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int ice_info_eetrack(struct ice_pf *pf, char *buf, size_t len)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	struct ice_nvm_info *nvm = &pf->hw.nvm;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	snprintf(buf, len, "0x%08x", nvm->eetrack);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return 0;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic int ice_info_ddp_pkg_name(struct ice_pf *pf, char *buf, size_t len)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	snprintf(buf, len, "%s", hw->active_pkg_name);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return 0;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic int ice_info_ddp_pkg_version(struct ice_pf *pf, char *buf, size_t len)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct ice_pkg_ver *pkg = &pf->hw.active_pkg_ver;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	snprintf(buf, len, "%u.%u.%u.%u", pkg->major, pkg->minor, pkg->update,
1028c2ecf20Sopenharmony_ci		 pkg->draft);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	return 0;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int ice_info_ddp_pkg_bundle_id(struct ice_pf *pf, char *buf, size_t len)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	snprintf(buf, len, "0x%08x", pf->hw.active_track_id);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return 0;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic int ice_info_netlist_ver(struct ice_pf *pf, char *buf, size_t len)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct ice_netlist_ver_info *netlist = &pf->hw.netlist_ver;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* The netlist version fields are BCD formatted */
1198c2ecf20Sopenharmony_ci	snprintf(buf, len, "%x.%x.%x-%x.%x.%x", netlist->major, netlist->minor,
1208c2ecf20Sopenharmony_ci		 netlist->type >> 16, netlist->type & 0xFFFF, netlist->rev,
1218c2ecf20Sopenharmony_ci		 netlist->cust_ver);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return 0;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic int ice_info_netlist_build(struct ice_pf *pf, char *buf, size_t len)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct ice_netlist_ver_info *netlist = &pf->hw.netlist_ver;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	snprintf(buf, len, "0x%08x", netlist->hash);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return 0;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci#define fixed(key, getter) { ICE_VERSION_FIXED, key, getter }
1368c2ecf20Sopenharmony_ci#define running(key, getter) { ICE_VERSION_RUNNING, key, getter }
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cienum ice_version_type {
1398c2ecf20Sopenharmony_ci	ICE_VERSION_FIXED,
1408c2ecf20Sopenharmony_ci	ICE_VERSION_RUNNING,
1418c2ecf20Sopenharmony_ci	ICE_VERSION_STORED,
1428c2ecf20Sopenharmony_ci};
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic const struct ice_devlink_version {
1458c2ecf20Sopenharmony_ci	enum ice_version_type type;
1468c2ecf20Sopenharmony_ci	const char *key;
1478c2ecf20Sopenharmony_ci	int (*getter)(struct ice_pf *pf, char *buf, size_t len);
1488c2ecf20Sopenharmony_ci} ice_devlink_versions[] = {
1498c2ecf20Sopenharmony_ci	fixed(DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, ice_info_pba),
1508c2ecf20Sopenharmony_ci	running(DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, ice_info_fw_mgmt),
1518c2ecf20Sopenharmony_ci	running("fw.mgmt.api", ice_info_fw_api),
1528c2ecf20Sopenharmony_ci	running("fw.mgmt.build", ice_info_fw_build),
1538c2ecf20Sopenharmony_ci	running(DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, ice_info_orom_ver),
1548c2ecf20Sopenharmony_ci	running("fw.psid.api", ice_info_nvm_ver),
1558c2ecf20Sopenharmony_ci	running(DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, ice_info_eetrack),
1568c2ecf20Sopenharmony_ci	running("fw.app.name", ice_info_ddp_pkg_name),
1578c2ecf20Sopenharmony_ci	running(DEVLINK_INFO_VERSION_GENERIC_FW_APP, ice_info_ddp_pkg_version),
1588c2ecf20Sopenharmony_ci	running("fw.app.bundle_id", ice_info_ddp_pkg_bundle_id),
1598c2ecf20Sopenharmony_ci	running("fw.netlist", ice_info_netlist_ver),
1608c2ecf20Sopenharmony_ci	running("fw.netlist.build", ice_info_netlist_build),
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/**
1648c2ecf20Sopenharmony_ci * ice_devlink_info_get - .info_get devlink handler
1658c2ecf20Sopenharmony_ci * @devlink: devlink instance structure
1668c2ecf20Sopenharmony_ci * @req: the devlink info request
1678c2ecf20Sopenharmony_ci * @extack: extended netdev ack structure
1688c2ecf20Sopenharmony_ci *
1698c2ecf20Sopenharmony_ci * Callback for the devlink .info_get operation. Reports information about the
1708c2ecf20Sopenharmony_ci * device.
1718c2ecf20Sopenharmony_ci *
1728c2ecf20Sopenharmony_ci * Return: zero on success or an error code on failure.
1738c2ecf20Sopenharmony_ci */
1748c2ecf20Sopenharmony_cistatic int ice_devlink_info_get(struct devlink *devlink,
1758c2ecf20Sopenharmony_ci				struct devlink_info_req *req,
1768c2ecf20Sopenharmony_ci				struct netlink_ext_ack *extack)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct ice_pf *pf = devlink_priv(devlink);
1798c2ecf20Sopenharmony_ci	char buf[100];
1808c2ecf20Sopenharmony_ci	size_t i;
1818c2ecf20Sopenharmony_ci	int err;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	err = devlink_info_driver_name_put(req, KBUILD_MODNAME);
1848c2ecf20Sopenharmony_ci	if (err) {
1858c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Unable to set driver name");
1868c2ecf20Sopenharmony_ci		return err;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	ice_info_get_dsn(pf, buf, sizeof(buf));
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	err = devlink_info_serial_number_put(req, buf);
1928c2ecf20Sopenharmony_ci	if (err) {
1938c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Unable to set serial number");
1948c2ecf20Sopenharmony_ci		return err;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ice_devlink_versions); i++) {
1988c2ecf20Sopenharmony_ci		enum ice_version_type type = ice_devlink_versions[i].type;
1998c2ecf20Sopenharmony_ci		const char *key = ice_devlink_versions[i].key;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		err = ice_devlink_versions[i].getter(pf, buf, sizeof(buf));
2028c2ecf20Sopenharmony_ci		if (err) {
2038c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Unable to obtain version info");
2048c2ecf20Sopenharmony_ci			return err;
2058c2ecf20Sopenharmony_ci		}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		switch (type) {
2088c2ecf20Sopenharmony_ci		case ICE_VERSION_FIXED:
2098c2ecf20Sopenharmony_ci			err = devlink_info_version_fixed_put(req, key, buf);
2108c2ecf20Sopenharmony_ci			if (err) {
2118c2ecf20Sopenharmony_ci				NL_SET_ERR_MSG_MOD(extack, "Unable to set fixed version");
2128c2ecf20Sopenharmony_ci				return err;
2138c2ecf20Sopenharmony_ci			}
2148c2ecf20Sopenharmony_ci			break;
2158c2ecf20Sopenharmony_ci		case ICE_VERSION_RUNNING:
2168c2ecf20Sopenharmony_ci			err = devlink_info_version_running_put(req, key, buf);
2178c2ecf20Sopenharmony_ci			if (err) {
2188c2ecf20Sopenharmony_ci				NL_SET_ERR_MSG_MOD(extack, "Unable to set running version");
2198c2ecf20Sopenharmony_ci				return err;
2208c2ecf20Sopenharmony_ci			}
2218c2ecf20Sopenharmony_ci			break;
2228c2ecf20Sopenharmony_ci		case ICE_VERSION_STORED:
2238c2ecf20Sopenharmony_ci			err = devlink_info_version_stored_put(req, key, buf);
2248c2ecf20Sopenharmony_ci			if (err) {
2258c2ecf20Sopenharmony_ci				NL_SET_ERR_MSG_MOD(extack, "Unable to set stored version");
2268c2ecf20Sopenharmony_ci				return err;
2278c2ecf20Sopenharmony_ci			}
2288c2ecf20Sopenharmony_ci			break;
2298c2ecf20Sopenharmony_ci		}
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return 0;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci/**
2368c2ecf20Sopenharmony_ci * ice_devlink_flash_update - Update firmware stored in flash on the device
2378c2ecf20Sopenharmony_ci * @devlink: pointer to devlink associated with device to update
2388c2ecf20Sopenharmony_ci * @params: flash update parameters
2398c2ecf20Sopenharmony_ci * @extack: netlink extended ACK structure
2408c2ecf20Sopenharmony_ci *
2418c2ecf20Sopenharmony_ci * Perform a device flash update. The bulk of the update logic is contained
2428c2ecf20Sopenharmony_ci * within the ice_flash_pldm_image function.
2438c2ecf20Sopenharmony_ci *
2448c2ecf20Sopenharmony_ci * Returns: zero on success, or an error code on failure.
2458c2ecf20Sopenharmony_ci */
2468c2ecf20Sopenharmony_cistatic int
2478c2ecf20Sopenharmony_ciice_devlink_flash_update(struct devlink *devlink,
2488c2ecf20Sopenharmony_ci			 struct devlink_flash_update_params *params,
2498c2ecf20Sopenharmony_ci			 struct netlink_ext_ack *extack)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct ice_pf *pf = devlink_priv(devlink);
2528c2ecf20Sopenharmony_ci	struct device *dev = &pf->pdev->dev;
2538c2ecf20Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
2548c2ecf20Sopenharmony_ci	const struct firmware *fw;
2558c2ecf20Sopenharmony_ci	u8 preservation;
2568c2ecf20Sopenharmony_ci	int err;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	if (!params->overwrite_mask) {
2598c2ecf20Sopenharmony_ci		/* preserve all settings and identifiers */
2608c2ecf20Sopenharmony_ci		preservation = ICE_AQC_NVM_PRESERVE_ALL;
2618c2ecf20Sopenharmony_ci	} else if (params->overwrite_mask == DEVLINK_FLASH_OVERWRITE_SETTINGS) {
2628c2ecf20Sopenharmony_ci		/* overwrite settings, but preserve the vital device identifiers */
2638c2ecf20Sopenharmony_ci		preservation = ICE_AQC_NVM_PRESERVE_SELECTED;
2648c2ecf20Sopenharmony_ci	} else if (params->overwrite_mask == (DEVLINK_FLASH_OVERWRITE_SETTINGS |
2658c2ecf20Sopenharmony_ci					      DEVLINK_FLASH_OVERWRITE_IDENTIFIERS)) {
2668c2ecf20Sopenharmony_ci		/* overwrite both settings and identifiers, preserve nothing */
2678c2ecf20Sopenharmony_ci		preservation = ICE_AQC_NVM_NO_PRESERVATION;
2688c2ecf20Sopenharmony_ci	} else {
2698c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Requested overwrite mask is not supported");
2708c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (!hw->dev_caps.common_cap.nvm_unified_update) {
2748c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Current firmware does not support unified update");
2758c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	err = ice_check_for_pending_update(pf, NULL, extack);
2798c2ecf20Sopenharmony_ci	if (err)
2808c2ecf20Sopenharmony_ci		return err;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	err = request_firmware(&fw, params->file_name, dev);
2838c2ecf20Sopenharmony_ci	if (err) {
2848c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Unable to read file from disk");
2858c2ecf20Sopenharmony_ci		return err;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	dev_dbg(dev, "Beginning flash update with file '%s'\n", params->file_name);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	devlink_flash_update_begin_notify(devlink);
2918c2ecf20Sopenharmony_ci	devlink_flash_update_status_notify(devlink, "Preparing to flash", NULL, 0, 0);
2928c2ecf20Sopenharmony_ci	err = ice_flash_pldm_image(pf, fw, preservation, extack);
2938c2ecf20Sopenharmony_ci	devlink_flash_update_end_notify(devlink);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	release_firmware(fw);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return err;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic const struct devlink_ops ice_devlink_ops = {
3018c2ecf20Sopenharmony_ci	.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK,
3028c2ecf20Sopenharmony_ci	.info_get = ice_devlink_info_get,
3038c2ecf20Sopenharmony_ci	.flash_update = ice_devlink_flash_update,
3048c2ecf20Sopenharmony_ci};
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic void ice_devlink_free(void *devlink_ptr)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	devlink_free((struct devlink *)devlink_ptr);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci/**
3128c2ecf20Sopenharmony_ci * ice_allocate_pf - Allocate devlink and return PF structure pointer
3138c2ecf20Sopenharmony_ci * @dev: the device to allocate for
3148c2ecf20Sopenharmony_ci *
3158c2ecf20Sopenharmony_ci * Allocate a devlink instance for this device and return the private area as
3168c2ecf20Sopenharmony_ci * the PF structure. The devlink memory is kept track of through devres by
3178c2ecf20Sopenharmony_ci * adding an action to remove it when unwinding.
3188c2ecf20Sopenharmony_ci */
3198c2ecf20Sopenharmony_cistruct ice_pf *ice_allocate_pf(struct device *dev)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	struct devlink *devlink;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	devlink = devlink_alloc(&ice_devlink_ops, sizeof(struct ice_pf));
3248c2ecf20Sopenharmony_ci	if (!devlink)
3258c2ecf20Sopenharmony_ci		return NULL;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* Add an action to teardown the devlink when unwinding the driver */
3288c2ecf20Sopenharmony_ci	if (devm_add_action(dev, ice_devlink_free, devlink)) {
3298c2ecf20Sopenharmony_ci		devlink_free(devlink);
3308c2ecf20Sopenharmony_ci		return NULL;
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	return devlink_priv(devlink);
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci/**
3378c2ecf20Sopenharmony_ci * ice_devlink_register - Register devlink interface for this PF
3388c2ecf20Sopenharmony_ci * @pf: the PF to register the devlink for.
3398c2ecf20Sopenharmony_ci *
3408c2ecf20Sopenharmony_ci * Register the devlink instance associated with this physical function.
3418c2ecf20Sopenharmony_ci *
3428c2ecf20Sopenharmony_ci * Return: zero on success or an error code on failure.
3438c2ecf20Sopenharmony_ci */
3448c2ecf20Sopenharmony_ciint ice_devlink_register(struct ice_pf *pf)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct devlink *devlink = priv_to_devlink(pf);
3478c2ecf20Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
3488c2ecf20Sopenharmony_ci	int err;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	err = devlink_register(devlink, dev);
3518c2ecf20Sopenharmony_ci	if (err) {
3528c2ecf20Sopenharmony_ci		dev_err(dev, "devlink registration failed: %d\n", err);
3538c2ecf20Sopenharmony_ci		return err;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return 0;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci/**
3608c2ecf20Sopenharmony_ci * ice_devlink_unregister - Unregister devlink resources for this PF.
3618c2ecf20Sopenharmony_ci * @pf: the PF structure to cleanup
3628c2ecf20Sopenharmony_ci *
3638c2ecf20Sopenharmony_ci * Releases resources used by devlink and cleans up associated memory.
3648c2ecf20Sopenharmony_ci */
3658c2ecf20Sopenharmony_civoid ice_devlink_unregister(struct ice_pf *pf)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	devlink_unregister(priv_to_devlink(pf));
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci/**
3718c2ecf20Sopenharmony_ci * ice_devlink_create_port - Create a devlink port for this VSI
3728c2ecf20Sopenharmony_ci * @vsi: the VSI to create a port for
3738c2ecf20Sopenharmony_ci *
3748c2ecf20Sopenharmony_ci * Create and register a devlink_port for this VSI.
3758c2ecf20Sopenharmony_ci *
3768c2ecf20Sopenharmony_ci * Return: zero on success or an error code on failure.
3778c2ecf20Sopenharmony_ci */
3788c2ecf20Sopenharmony_ciint ice_devlink_create_port(struct ice_vsi *vsi)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct devlink_port_attrs attrs = {};
3818c2ecf20Sopenharmony_ci	struct ice_port_info *pi;
3828c2ecf20Sopenharmony_ci	struct devlink *devlink;
3838c2ecf20Sopenharmony_ci	struct device *dev;
3848c2ecf20Sopenharmony_ci	struct ice_pf *pf;
3858c2ecf20Sopenharmony_ci	int err;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/* Currently we only create devlink_port instances for PF VSIs */
3888c2ecf20Sopenharmony_ci	if (vsi->type != ICE_VSI_PF)
3898c2ecf20Sopenharmony_ci		return -EINVAL;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	pf = vsi->back;
3928c2ecf20Sopenharmony_ci	devlink = priv_to_devlink(pf);
3938c2ecf20Sopenharmony_ci	dev = ice_pf_to_dev(pf);
3948c2ecf20Sopenharmony_ci	pi = pf->hw.port_info;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
3978c2ecf20Sopenharmony_ci	attrs.phys.port_number = pi->lport;
3988c2ecf20Sopenharmony_ci	devlink_port_attrs_set(&vsi->devlink_port, &attrs);
3998c2ecf20Sopenharmony_ci	err = devlink_port_register(devlink, &vsi->devlink_port, vsi->idx);
4008c2ecf20Sopenharmony_ci	if (err) {
4018c2ecf20Sopenharmony_ci		dev_err(dev, "devlink_port_register failed: %d\n", err);
4028c2ecf20Sopenharmony_ci		return err;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	vsi->devlink_port_registered = true;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	return 0;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci/**
4118c2ecf20Sopenharmony_ci * ice_devlink_destroy_port - Destroy the devlink_port for this VSI
4128c2ecf20Sopenharmony_ci * @vsi: the VSI to cleanup
4138c2ecf20Sopenharmony_ci *
4148c2ecf20Sopenharmony_ci * Unregisters the devlink_port structure associated with this VSI.
4158c2ecf20Sopenharmony_ci */
4168c2ecf20Sopenharmony_civoid ice_devlink_destroy_port(struct ice_vsi *vsi)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	if (!vsi->devlink_port_registered)
4198c2ecf20Sopenharmony_ci		return;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	devlink_port_type_clear(&vsi->devlink_port);
4228c2ecf20Sopenharmony_ci	devlink_port_unregister(&vsi->devlink_port);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	vsi->devlink_port_registered = false;
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci/**
4288c2ecf20Sopenharmony_ci * ice_devlink_nvm_snapshot - Capture a snapshot of the Shadow RAM contents
4298c2ecf20Sopenharmony_ci * @devlink: the devlink instance
4308c2ecf20Sopenharmony_ci * @ops: the devlink region being snapshotted
4318c2ecf20Sopenharmony_ci * @extack: extended ACK response structure
4328c2ecf20Sopenharmony_ci * @data: on exit points to snapshot data buffer
4338c2ecf20Sopenharmony_ci *
4348c2ecf20Sopenharmony_ci * This function is called in response to the DEVLINK_CMD_REGION_TRIGGER for
4358c2ecf20Sopenharmony_ci * the shadow-ram devlink region. It captures a snapshot of the shadow ram
4368c2ecf20Sopenharmony_ci * contents. This snapshot can later be viewed via the devlink-region
4378c2ecf20Sopenharmony_ci * interface.
4388c2ecf20Sopenharmony_ci *
4398c2ecf20Sopenharmony_ci * @returns zero on success, and updates the data pointer. Returns a non-zero
4408c2ecf20Sopenharmony_ci * error code on failure.
4418c2ecf20Sopenharmony_ci */
4428c2ecf20Sopenharmony_cistatic int ice_devlink_nvm_snapshot(struct devlink *devlink,
4438c2ecf20Sopenharmony_ci				    const struct devlink_region_ops *ops,
4448c2ecf20Sopenharmony_ci				    struct netlink_ext_ack *extack, u8 **data)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	struct ice_pf *pf = devlink_priv(devlink);
4478c2ecf20Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
4488c2ecf20Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
4498c2ecf20Sopenharmony_ci	enum ice_status status;
4508c2ecf20Sopenharmony_ci	void *nvm_data;
4518c2ecf20Sopenharmony_ci	u32 nvm_size;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	nvm_size = hw->nvm.flash_size;
4548c2ecf20Sopenharmony_ci	nvm_data = vzalloc(nvm_size);
4558c2ecf20Sopenharmony_ci	if (!nvm_data)
4568c2ecf20Sopenharmony_ci		return -ENOMEM;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	status = ice_acquire_nvm(hw, ICE_RES_READ);
4598c2ecf20Sopenharmony_ci	if (status) {
4608c2ecf20Sopenharmony_ci		dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
4618c2ecf20Sopenharmony_ci			status, hw->adminq.sq_last_status);
4628c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
4638c2ecf20Sopenharmony_ci		vfree(nvm_data);
4648c2ecf20Sopenharmony_ci		return -EIO;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	status = ice_read_flat_nvm(hw, 0, &nvm_size, nvm_data, false);
4688c2ecf20Sopenharmony_ci	if (status) {
4698c2ecf20Sopenharmony_ci		dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
4708c2ecf20Sopenharmony_ci			nvm_size, status, hw->adminq.sq_last_status);
4718c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
4728c2ecf20Sopenharmony_ci		ice_release_nvm(hw);
4738c2ecf20Sopenharmony_ci		vfree(nvm_data);
4748c2ecf20Sopenharmony_ci		return -EIO;
4758c2ecf20Sopenharmony_ci	}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	ice_release_nvm(hw);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	*data = nvm_data;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	return 0;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci/**
4858c2ecf20Sopenharmony_ci * ice_devlink_devcaps_snapshot - Capture snapshot of device capabilities
4868c2ecf20Sopenharmony_ci * @devlink: the devlink instance
4878c2ecf20Sopenharmony_ci * @ops: the devlink region being snapshotted
4888c2ecf20Sopenharmony_ci * @extack: extended ACK response structure
4898c2ecf20Sopenharmony_ci * @data: on exit points to snapshot data buffer
4908c2ecf20Sopenharmony_ci *
4918c2ecf20Sopenharmony_ci * This function is called in response to the DEVLINK_CMD_REGION_TRIGGER for
4928c2ecf20Sopenharmony_ci * the device-caps devlink region. It captures a snapshot of the device
4938c2ecf20Sopenharmony_ci * capabilities reported by firmware.
4948c2ecf20Sopenharmony_ci *
4958c2ecf20Sopenharmony_ci * @returns zero on success, and updates the data pointer. Returns a non-zero
4968c2ecf20Sopenharmony_ci * error code on failure.
4978c2ecf20Sopenharmony_ci */
4988c2ecf20Sopenharmony_cistatic int
4998c2ecf20Sopenharmony_ciice_devlink_devcaps_snapshot(struct devlink *devlink,
5008c2ecf20Sopenharmony_ci			     const struct devlink_region_ops *ops,
5018c2ecf20Sopenharmony_ci			     struct netlink_ext_ack *extack, u8 **data)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	struct ice_pf *pf = devlink_priv(devlink);
5048c2ecf20Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
5058c2ecf20Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
5068c2ecf20Sopenharmony_ci	enum ice_status status;
5078c2ecf20Sopenharmony_ci	void *devcaps;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	devcaps = vzalloc(ICE_AQ_MAX_BUF_LEN);
5108c2ecf20Sopenharmony_ci	if (!devcaps)
5118c2ecf20Sopenharmony_ci		return -ENOMEM;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	status = ice_aq_list_caps(hw, devcaps, ICE_AQ_MAX_BUF_LEN, NULL,
5148c2ecf20Sopenharmony_ci				  ice_aqc_opc_list_dev_caps, NULL);
5158c2ecf20Sopenharmony_ci	if (status) {
5168c2ecf20Sopenharmony_ci		dev_dbg(dev, "ice_aq_list_caps: failed to read device capabilities, err %d aq_err %d\n",
5178c2ecf20Sopenharmony_ci			status, hw->adminq.sq_last_status);
5188c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Failed to read device capabilities");
5198c2ecf20Sopenharmony_ci		vfree(devcaps);
5208c2ecf20Sopenharmony_ci		return -EIO;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	*data = (u8 *)devcaps;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	return 0;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic const struct devlink_region_ops ice_nvm_region_ops = {
5298c2ecf20Sopenharmony_ci	.name = "nvm-flash",
5308c2ecf20Sopenharmony_ci	.destructor = vfree,
5318c2ecf20Sopenharmony_ci	.snapshot = ice_devlink_nvm_snapshot,
5328c2ecf20Sopenharmony_ci};
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic const struct devlink_region_ops ice_devcaps_region_ops = {
5358c2ecf20Sopenharmony_ci	.name = "device-caps",
5368c2ecf20Sopenharmony_ci	.destructor = vfree,
5378c2ecf20Sopenharmony_ci	.snapshot = ice_devlink_devcaps_snapshot,
5388c2ecf20Sopenharmony_ci};
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci/**
5418c2ecf20Sopenharmony_ci * ice_devlink_init_regions - Initialize devlink regions
5428c2ecf20Sopenharmony_ci * @pf: the PF device structure
5438c2ecf20Sopenharmony_ci *
5448c2ecf20Sopenharmony_ci * Create devlink regions used to enable access to dump the contents of the
5458c2ecf20Sopenharmony_ci * flash memory on the device.
5468c2ecf20Sopenharmony_ci */
5478c2ecf20Sopenharmony_civoid ice_devlink_init_regions(struct ice_pf *pf)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	struct devlink *devlink = priv_to_devlink(pf);
5508c2ecf20Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
5518c2ecf20Sopenharmony_ci	u64 nvm_size;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	nvm_size = pf->hw.nvm.flash_size;
5548c2ecf20Sopenharmony_ci	pf->nvm_region = devlink_region_create(devlink, &ice_nvm_region_ops, 1,
5558c2ecf20Sopenharmony_ci					       nvm_size);
5568c2ecf20Sopenharmony_ci	if (IS_ERR(pf->nvm_region)) {
5578c2ecf20Sopenharmony_ci		dev_err(dev, "failed to create NVM devlink region, err %ld\n",
5588c2ecf20Sopenharmony_ci			PTR_ERR(pf->nvm_region));
5598c2ecf20Sopenharmony_ci		pf->nvm_region = NULL;
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	pf->devcaps_region = devlink_region_create(devlink,
5638c2ecf20Sopenharmony_ci						   &ice_devcaps_region_ops, 10,
5648c2ecf20Sopenharmony_ci						   ICE_AQ_MAX_BUF_LEN);
5658c2ecf20Sopenharmony_ci	if (IS_ERR(pf->devcaps_region)) {
5668c2ecf20Sopenharmony_ci		dev_err(dev, "failed to create device-caps devlink region, err %ld\n",
5678c2ecf20Sopenharmony_ci			PTR_ERR(pf->devcaps_region));
5688c2ecf20Sopenharmony_ci		pf->devcaps_region = NULL;
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci/**
5738c2ecf20Sopenharmony_ci * ice_devlink_destroy_regions - Destroy devlink regions
5748c2ecf20Sopenharmony_ci * @pf: the PF device structure
5758c2ecf20Sopenharmony_ci *
5768c2ecf20Sopenharmony_ci * Remove previously created regions for this PF.
5778c2ecf20Sopenharmony_ci */
5788c2ecf20Sopenharmony_civoid ice_devlink_destroy_regions(struct ice_pf *pf)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	if (pf->nvm_region)
5818c2ecf20Sopenharmony_ci		devlink_region_destroy(pf->nvm_region);
5828c2ecf20Sopenharmony_ci	if (pf->devcaps_region)
5838c2ecf20Sopenharmony_ci		devlink_region_destroy(pf->devcaps_region);
5848c2ecf20Sopenharmony_ci}
585