diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnxt')
-rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 245 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c | 1 |
6 files changed, 166 insertions, 91 deletions
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 0af0af2b70fe..4edd6f8e017e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2884,7 +2884,7 @@ static int bnxt_alloc_rx_rings(struct bnxt *bp) if (rc) return rc; - rc = xdp_rxq_info_reg(&rxr->xdp_rxq, bp->dev, i); + rc = xdp_rxq_info_reg(&rxr->xdp_rxq, bp->dev, i, 0); if (rc < 0) return rc; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 47b3c3127879..950ea26ae0d2 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -20,6 +20,7 @@ #define DRV_VER_MIN 10 #define DRV_VER_UPD 1 +#include <linux/ethtool.h> #include <linux/interrupt.h> #include <linux/rhashtable.h> #include <linux/crash_dump.h> diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index 184b6d0513b2..6b7b69ed62db 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -30,14 +30,12 @@ bnxt_dl_flash_update(struct devlink *dl, return -EPERM; } - devlink_flash_update_begin_notify(dl); devlink_flash_update_status_notify(dl, "Preparing to flash", NULL, 0, 0); - rc = bnxt_flash_package_from_file(bp->dev, params->file_name, 0); + rc = bnxt_flash_package_from_fw_obj(bp->dev, params->fw, 0); if (!rc) devlink_flash_update_status_notify(dl, "Flashing done", NULL, 0, 0); else devlink_flash_update_status_notify(dl, "Flashing failed", NULL, 0, 0); - devlink_flash_update_end_notify(dl); return rc; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 1471c9a36238..9ff79d5d14c4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2100,19 +2100,16 @@ static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal, u16 ext, u16 *index, u32 *item_length, u32 *data_length); -static int bnxt_flash_nvram(struct net_device *dev, - u16 dir_type, - u16 dir_ordinal, - u16 dir_ext, - u16 dir_attr, - const u8 *data, - size_t data_len) +static int __bnxt_flash_nvram(struct net_device *dev, u16 dir_type, + u16 dir_ordinal, u16 dir_ext, u16 dir_attr, + u32 dir_item_len, const u8 *data, + size_t data_len) { struct bnxt *bp = netdev_priv(dev); int rc; struct hwrm_nvm_write_input req = {0}; dma_addr_t dma_handle; - u8 *kmem; + u8 *kmem = NULL; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_WRITE, -1, -1); @@ -2120,26 +2117,42 @@ static int bnxt_flash_nvram(struct net_device *dev, req.dir_ordinal = cpu_to_le16(dir_ordinal); req.dir_ext = cpu_to_le16(dir_ext); req.dir_attr = cpu_to_le16(dir_attr); - req.dir_data_length = cpu_to_le32(data_len); + req.dir_item_length = cpu_to_le32(dir_item_len); + if (data_len && data) { + req.dir_data_length = cpu_to_le32(data_len); - kmem = dma_alloc_coherent(&bp->pdev->dev, data_len, &dma_handle, - GFP_KERNEL); - if (!kmem) { - netdev_err(dev, "dma_alloc_coherent failure, length = %u\n", - (unsigned)data_len); - return -ENOMEM; + kmem = dma_alloc_coherent(&bp->pdev->dev, data_len, &dma_handle, + GFP_KERNEL); + if (!kmem) + return -ENOMEM; + + memcpy(kmem, data, data_len); + req.host_src_addr = cpu_to_le64(dma_handle); } - memcpy(kmem, data, data_len); - req.host_src_addr = cpu_to_le64(dma_handle); - rc = hwrm_send_message(bp, &req, sizeof(req), FLASH_NVRAM_TIMEOUT); - dma_free_coherent(&bp->pdev->dev, data_len, kmem, dma_handle); + rc = _hwrm_send_message(bp, &req, sizeof(req), FLASH_NVRAM_TIMEOUT); + if (kmem) + dma_free_coherent(&bp->pdev->dev, data_len, kmem, dma_handle); if (rc == -EACCES) bnxt_print_admin_err(bp); return rc; } +static int bnxt_flash_nvram(struct net_device *dev, u16 dir_type, + u16 dir_ordinal, u16 dir_ext, u16 dir_attr, + const u8 *data, size_t data_len) +{ + struct bnxt *bp = netdev_priv(dev); + int rc; + + mutex_lock(&bp->hwrm_cmd_lock); + rc = __bnxt_flash_nvram(dev, dir_type, dir_ordinal, dir_ext, dir_attr, + 0, data, data_len); + mutex_unlock(&bp->hwrm_cmd_lock); + return rc; +} + static int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type, u8 self_reset, u8 flags) { @@ -2419,104 +2432,166 @@ static int bnxt_flash_firmware_from_file(struct net_device *dev, return rc; } -int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, - u32 install_type) +#define BNXT_PKG_DMA_SIZE 0x40000 +#define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE)) +#define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST)) + +int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, + u32 install_type) { - struct bnxt *bp = netdev_priv(dev); - struct hwrm_nvm_install_update_output *resp = bp->hwrm_cmd_resp_addr; struct hwrm_nvm_install_update_input install = {0}; - const struct firmware *fw; + struct hwrm_nvm_install_update_output resp = {0}; + struct hwrm_nvm_modify_input modify = {0}; + struct bnxt *bp = netdev_priv(dev); + bool defrag_attempted = false; + dma_addr_t dma_handle; + u8 *kmem = NULL; + u32 modify_len; u32 item_len; int rc = 0; u16 index; bnxt_hwrm_fw_set_time(bp); - rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, - BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, - &index, &item_len, NULL); - if (rc) { - netdev_err(dev, "PKG update area not created in nvram\n"); - return rc; - } + bnxt_hwrm_cmd_hdr_init(bp, &modify, HWRM_NVM_MODIFY, -1, -1); - rc = request_firmware(&fw, filename, &dev->dev); - if (rc != 0) { - netdev_err(dev, "PKG error %d requesting file: %s\n", - rc, filename); - return rc; + /* Try allocating a large DMA buffer first. Older fw will + * cause excessive NVRAM erases when using small blocks. + */ + modify_len = roundup_pow_of_two(fw->size); + modify_len = min_t(u32, modify_len, BNXT_PKG_DMA_SIZE); + while (1) { + kmem = dma_alloc_coherent(&bp->pdev->dev, modify_len, + &dma_handle, GFP_KERNEL); + if (!kmem && modify_len > PAGE_SIZE) + modify_len /= 2; + else + break; } + if (!kmem) + return -ENOMEM; - if (fw->size > item_len) { - netdev_err(dev, "PKG insufficient update area in nvram: %lu\n", - (unsigned long)fw->size); - rc = -EFBIG; - } else { - dma_addr_t dma_handle; - u8 *kmem; - struct hwrm_nvm_modify_input modify = {0}; + modify.host_src_addr = cpu_to_le64(dma_handle); - bnxt_hwrm_cmd_hdr_init(bp, &modify, HWRM_NVM_MODIFY, -1, -1); + bnxt_hwrm_cmd_hdr_init(bp, &install, HWRM_NVM_INSTALL_UPDATE, -1, -1); + if ((install_type & 0xffff) == 0) + install_type >>= 16; + install.install_type = cpu_to_le32(install_type); + + do { + u32 copied = 0, len = modify_len; + + rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE, + BNX_DIR_ORDINAL_FIRST, + BNX_DIR_EXT_NONE, + &index, &item_len, NULL); + if (rc) { + netdev_err(dev, "PKG update area not created in nvram\n"); + break; + } + if (fw->size > item_len) { + netdev_err(dev, "PKG insufficient update area in nvram: %lu\n", + (unsigned long)fw->size); + rc = -EFBIG; + break; + } modify.dir_idx = cpu_to_le16(index); - modify.len = cpu_to_le32(fw->size); - kmem = dma_alloc_coherent(&bp->pdev->dev, fw->size, - &dma_handle, GFP_KERNEL); - if (!kmem) { - netdev_err(dev, - "dma_alloc_coherent failure, length = %u\n", - (unsigned int)fw->size); - rc = -ENOMEM; - } else { - memcpy(kmem, fw->data, fw->size); - modify.host_src_addr = cpu_to_le64(dma_handle); + if (fw->size > modify_len) + modify.flags = BNXT_NVM_MORE_FLAG; + while (copied < fw->size) { + u32 balance = fw->size - copied; + if (balance <= modify_len) { + len = balance; + if (copied) + modify.flags |= BNXT_NVM_LAST_FLAG; + } + memcpy(kmem, fw->data + copied, len); + modify.len = cpu_to_le32(len); + modify.offset = cpu_to_le32(copied); rc = hwrm_send_message(bp, &modify, sizeof(modify), FLASH_PACKAGE_TIMEOUT); - dma_free_coherent(&bp->pdev->dev, fw->size, kmem, - dma_handle); + if (rc) + goto pkg_abort; + copied += len; } - } - release_firmware(fw); - if (rc) - goto err_exit; - - if ((install_type & 0xffff) == 0) - install_type >>= 16; - bnxt_hwrm_cmd_hdr_init(bp, &install, HWRM_NVM_INSTALL_UPDATE, -1, -1); - install.install_type = cpu_to_le32(install_type); + mutex_lock(&bp->hwrm_cmd_lock); + rc = _hwrm_send_message_silent(bp, &install, sizeof(install), + INSTALL_PACKAGE_TIMEOUT); + memcpy(&resp, bp->hwrm_cmd_resp_addr, sizeof(resp)); - mutex_lock(&bp->hwrm_cmd_lock); - rc = _hwrm_send_message(bp, &install, sizeof(install), - INSTALL_PACKAGE_TIMEOUT); - if (rc) { - u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err; + if (defrag_attempted) { + /* We have tried to defragment already in the previous + * iteration. Return with the result for INSTALL_UPDATE + */ + mutex_unlock(&bp->hwrm_cmd_lock); + break; + } - if (resp->error_code && error_code == + if (rc && ((struct hwrm_err_output *)&resp)->cmd_err == NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) { - install.flags |= cpu_to_le16( - NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); - rc = _hwrm_send_message(bp, &install, sizeof(install), - INSTALL_PACKAGE_TIMEOUT); + install.flags |= + cpu_to_le16(NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); + + rc = _hwrm_send_message_silent(bp, &install, + sizeof(install), + INSTALL_PACKAGE_TIMEOUT); + memcpy(&resp, bp->hwrm_cmd_resp_addr, sizeof(resp)); + + if (rc && ((struct hwrm_err_output *)&resp)->cmd_err == + NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE) { + /* FW has cleared NVM area, driver will create + * UPDATE directory and try the flash again + */ + defrag_attempted = true; + rc = __bnxt_flash_nvram(bp->dev, + BNX_DIR_TYPE_UPDATE, + BNX_DIR_ORDINAL_FIRST, + 0, 0, item_len, NULL, + 0); + } else if (rc) { + netdev_err(dev, "HWRM_NVM_INSTALL_UPDATE failure rc :%x\n", rc); + } + } else if (rc) { + netdev_err(dev, "HWRM_NVM_INSTALL_UPDATE failure rc :%x\n", rc); } - if (rc) - goto flash_pkg_exit; - } + mutex_unlock(&bp->hwrm_cmd_lock); + } while (defrag_attempted && !rc); - if (resp->result) { +pkg_abort: + dma_free_coherent(&bp->pdev->dev, modify_len, kmem, dma_handle); + if (resp.result) { netdev_err(dev, "PKG install error = %d, problem_item = %d\n", - (s8)resp->result, (int)resp->problem_item); + (s8)resp.result, (int)resp.problem_item); rc = -ENOPKG; } -flash_pkg_exit: - mutex_unlock(&bp->hwrm_cmd_lock); -err_exit: if (rc == -EACCES) bnxt_print_admin_err(bp); return rc; } +static int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, + u32 install_type) +{ + const struct firmware *fw; + int rc; + + rc = request_firmware(&fw, filename, &dev->dev); + if (rc != 0) { + netdev_err(dev, "PKG error %d requesting file: %s\n", + rc, filename); + return rc; + } + + rc = bnxt_flash_package_from_fw_obj(dev, fw, install_type); + + release_firmware(fw); + + return rc; +} + static int bnxt_flash_device(struct net_device *dev, struct ethtool_flash *flash) { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h index fa6fbde52bea..0a57cb6a4a4b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h @@ -94,8 +94,8 @@ u32 bnxt_fw_to_ethtool_speed(u16); u16 bnxt_get_fw_auto_link_speeds(u32); int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp, struct hwrm_nvm_get_dev_info_output *nvm_dev_info); -int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, - u32 install_type); +int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw, + u32 install_type); void bnxt_ethtool_init(struct bnxt *bp); void bnxt_ethtool_free(struct bnxt *bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index 23b80aa171dd..a217316228f4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -8,6 +8,7 @@ * the Free Software Foundation. */ +#include <linux/ethtool.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/netdevice.h> |