Merge branch 'bnxt_en-improve-firmware-flashing'
Michael Chan says: ==================== bnxt_en: Improve firmware flashing. This patchset improves firmware flashing in 2 ways: - If firmware returns NO_SPACE error during flashing, the driver will create the UPDATE directory with more staging area and retry. - Instead of allocating a big DMA buffer for the entire contents of the firmware package size, fallback to a smaller buffer to DMA the contents in multiple DMA operations. ==================== Link: https://lore.kernel.org/r/1607860306-17244-1-git-send-email-michael.chan@broadcom.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
22f07b86d4
1 changed files with 143 additions and 79 deletions
|
|
@ -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,90 +2432,141 @@ static int bnxt_flash_firmware_from_file(struct net_device *dev,
|
|||
return rc;
|
||||
}
|
||||
|
||||
#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};
|
||||
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);
|
||||
|
||||
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};
|
||||
|
||||
bnxt_hwrm_cmd_hdr_init(bp, &modify, HWRM_NVM_MODIFY, -1, -1);
|
||||
|
||||
modify.dir_idx = cpu_to_le16(index);
|
||||
modify.len = cpu_to_le32(fw->size);
|
||||
|
||||
kmem = dma_alloc_coherent(&bp->pdev->dev, fw->size,
|
||||
/* 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) {
|
||||
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);
|
||||
|
||||
rc = hwrm_send_message(bp, &modify, sizeof(modify),
|
||||
FLASH_PACKAGE_TIMEOUT);
|
||||
dma_free_coherent(&bp->pdev->dev, fw->size, kmem,
|
||||
dma_handle);
|
||||
}
|
||||
if (!kmem && modify_len > PAGE_SIZE)
|
||||
modify_len /= 2;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (rc)
|
||||
goto err_exit;
|
||||
if (!kmem)
|
||||
return -ENOMEM;
|
||||
|
||||
modify.host_src_addr = cpu_to_le64(dma_handle);
|
||||
|
||||
bnxt_hwrm_cmd_hdr_init(bp, &install, HWRM_NVM_INSTALL_UPDATE, -1, -1);
|
||||
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(bp, &install, sizeof(install),
|
||||
INSTALL_PACKAGE_TIMEOUT);
|
||||
if (rc) {
|
||||
u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err;
|
||||
do {
|
||||
u32 copied = 0, len = modify_len;
|
||||
|
||||
if (resp->error_code && error_code ==
|
||||
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);
|
||||
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;
|
||||
}
|
||||
if (rc)
|
||||
goto flash_pkg_exit;
|
||||
}
|
||||
|
||||
if (resp->result) {
|
||||
modify.dir_idx = cpu_to_le16(index);
|
||||
|
||||
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);
|
||||
if (rc)
|
||||
goto pkg_abort;
|
||||
copied += len;
|
||||
}
|
||||
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));
|
||||
|
||||
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 (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_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);
|
||||
}
|
||||
mutex_unlock(&bp->hwrm_cmd_lock);
|
||||
} while (defrag_attempted && !rc);
|
||||
|
||||
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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue