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