Skip to content

Commit 22f07b8

Browse files
committed
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/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 2aa899e + a86b313 commit 22f07b8

File tree

1 file changed

+139
-75
lines changed

1 file changed

+139
-75
lines changed

drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c

Lines changed: 139 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2100,46 +2100,59 @@ static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal,
21002100
u16 ext, u16 *index, u32 *item_length,
21012101
u32 *data_length);
21022102

2103-
static int bnxt_flash_nvram(struct net_device *dev,
2104-
u16 dir_type,
2105-
u16 dir_ordinal,
2106-
u16 dir_ext,
2107-
u16 dir_attr,
2108-
const u8 *data,
2109-
size_t data_len)
2103+
static int __bnxt_flash_nvram(struct net_device *dev, u16 dir_type,
2104+
u16 dir_ordinal, u16 dir_ext, u16 dir_attr,
2105+
u32 dir_item_len, const u8 *data,
2106+
size_t data_len)
21102107
{
21112108
struct bnxt *bp = netdev_priv(dev);
21122109
int rc;
21132110
struct hwrm_nvm_write_input req = {0};
21142111
dma_addr_t dma_handle;
2115-
u8 *kmem;
2112+
u8 *kmem = NULL;
21162113

21172114
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_WRITE, -1, -1);
21182115

21192116
req.dir_type = cpu_to_le16(dir_type);
21202117
req.dir_ordinal = cpu_to_le16(dir_ordinal);
21212118
req.dir_ext = cpu_to_le16(dir_ext);
21222119
req.dir_attr = cpu_to_le16(dir_attr);
2123-
req.dir_data_length = cpu_to_le32(data_len);
2120+
req.dir_item_length = cpu_to_le32(dir_item_len);
2121+
if (data_len && data) {
2122+
req.dir_data_length = cpu_to_le32(data_len);
21242123

2125-
kmem = dma_alloc_coherent(&bp->pdev->dev, data_len, &dma_handle,
2126-
GFP_KERNEL);
2127-
if (!kmem) {
2128-
netdev_err(dev, "dma_alloc_coherent failure, length = %u\n",
2129-
(unsigned)data_len);
2130-
return -ENOMEM;
2124+
kmem = dma_alloc_coherent(&bp->pdev->dev, data_len, &dma_handle,
2125+
GFP_KERNEL);
2126+
if (!kmem)
2127+
return -ENOMEM;
2128+
2129+
memcpy(kmem, data, data_len);
2130+
req.host_src_addr = cpu_to_le64(dma_handle);
21312131
}
2132-
memcpy(kmem, data, data_len);
2133-
req.host_src_addr = cpu_to_le64(dma_handle);
21342132

2135-
rc = hwrm_send_message(bp, &req, sizeof(req), FLASH_NVRAM_TIMEOUT);
2136-
dma_free_coherent(&bp->pdev->dev, data_len, kmem, dma_handle);
2133+
rc = _hwrm_send_message(bp, &req, sizeof(req), FLASH_NVRAM_TIMEOUT);
2134+
if (kmem)
2135+
dma_free_coherent(&bp->pdev->dev, data_len, kmem, dma_handle);
21372136

21382137
if (rc == -EACCES)
21392138
bnxt_print_admin_err(bp);
21402139
return rc;
21412140
}
21422141

2142+
static int bnxt_flash_nvram(struct net_device *dev, u16 dir_type,
2143+
u16 dir_ordinal, u16 dir_ext, u16 dir_attr,
2144+
const u8 *data, size_t data_len)
2145+
{
2146+
struct bnxt *bp = netdev_priv(dev);
2147+
int rc;
2148+
2149+
mutex_lock(&bp->hwrm_cmd_lock);
2150+
rc = __bnxt_flash_nvram(dev, dir_type, dir_ordinal, dir_ext, dir_attr,
2151+
0, data, data_len);
2152+
mutex_unlock(&bp->hwrm_cmd_lock);
2153+
return rc;
2154+
}
2155+
21432156
static int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type,
21442157
u8 self_reset, u8 flags)
21452158
{
@@ -2419,90 +2432,141 @@ static int bnxt_flash_firmware_from_file(struct net_device *dev,
24192432
return rc;
24202433
}
24212434

2435+
#define BNXT_PKG_DMA_SIZE 0x40000
2436+
#define BNXT_NVM_MORE_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE))
2437+
#define BNXT_NVM_LAST_FLAG (cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST))
2438+
24222439
int bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw,
24232440
u32 install_type)
24242441
{
2425-
struct bnxt *bp = netdev_priv(dev);
2426-
struct hwrm_nvm_install_update_output *resp = bp->hwrm_cmd_resp_addr;
24272442
struct hwrm_nvm_install_update_input install = {0};
2443+
struct hwrm_nvm_install_update_output resp = {0};
2444+
struct hwrm_nvm_modify_input modify = {0};
2445+
struct bnxt *bp = netdev_priv(dev);
2446+
bool defrag_attempted = false;
2447+
dma_addr_t dma_handle;
2448+
u8 *kmem = NULL;
2449+
u32 modify_len;
24282450
u32 item_len;
24292451
int rc = 0;
24302452
u16 index;
24312453

24322454
bnxt_hwrm_fw_set_time(bp);
24332455

2434-
rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE,
2435-
BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE,
2436-
&index, &item_len, NULL);
2437-
if (rc) {
2438-
netdev_err(dev, "PKG update area not created in nvram\n");
2439-
return rc;
2456+
bnxt_hwrm_cmd_hdr_init(bp, &modify, HWRM_NVM_MODIFY, -1, -1);
2457+
2458+
/* Try allocating a large DMA buffer first. Older fw will
2459+
* cause excessive NVRAM erases when using small blocks.
2460+
*/
2461+
modify_len = roundup_pow_of_two(fw->size);
2462+
modify_len = min_t(u32, modify_len, BNXT_PKG_DMA_SIZE);
2463+
while (1) {
2464+
kmem = dma_alloc_coherent(&bp->pdev->dev, modify_len,
2465+
&dma_handle, GFP_KERNEL);
2466+
if (!kmem && modify_len > PAGE_SIZE)
2467+
modify_len /= 2;
2468+
else
2469+
break;
24402470
}
2471+
if (!kmem)
2472+
return -ENOMEM;
24412473

2442-
if (fw->size > item_len) {
2443-
netdev_err(dev, "PKG insufficient update area in nvram: %lu\n",
2444-
(unsigned long)fw->size);
2445-
rc = -EFBIG;
2446-
} else {
2447-
dma_addr_t dma_handle;
2448-
u8 *kmem;
2449-
struct hwrm_nvm_modify_input modify = {0};
2474+
modify.host_src_addr = cpu_to_le64(dma_handle);
24502475

2451-
bnxt_hwrm_cmd_hdr_init(bp, &modify, HWRM_NVM_MODIFY, -1, -1);
2476+
bnxt_hwrm_cmd_hdr_init(bp, &install, HWRM_NVM_INSTALL_UPDATE, -1, -1);
2477+
if ((install_type & 0xffff) == 0)
2478+
install_type >>= 16;
2479+
install.install_type = cpu_to_le32(install_type);
2480+
2481+
do {
2482+
u32 copied = 0, len = modify_len;
2483+
2484+
rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE,
2485+
BNX_DIR_ORDINAL_FIRST,
2486+
BNX_DIR_EXT_NONE,
2487+
&index, &item_len, NULL);
2488+
if (rc) {
2489+
netdev_err(dev, "PKG update area not created in nvram\n");
2490+
break;
2491+
}
2492+
if (fw->size > item_len) {
2493+
netdev_err(dev, "PKG insufficient update area in nvram: %lu\n",
2494+
(unsigned long)fw->size);
2495+
rc = -EFBIG;
2496+
break;
2497+
}
24522498

24532499
modify.dir_idx = cpu_to_le16(index);
2454-
modify.len = cpu_to_le32(fw->size);
24552500

2456-
kmem = dma_alloc_coherent(&bp->pdev->dev, fw->size,
2457-
&dma_handle, GFP_KERNEL);
2458-
if (!kmem) {
2459-
netdev_err(dev,
2460-
"dma_alloc_coherent failure, length = %u\n",
2461-
(unsigned int)fw->size);
2462-
rc = -ENOMEM;
2463-
} else {
2464-
memcpy(kmem, fw->data, fw->size);
2465-
modify.host_src_addr = cpu_to_le64(dma_handle);
2501+
if (fw->size > modify_len)
2502+
modify.flags = BNXT_NVM_MORE_FLAG;
2503+
while (copied < fw->size) {
2504+
u32 balance = fw->size - copied;
24662505

2506+
if (balance <= modify_len) {
2507+
len = balance;
2508+
if (copied)
2509+
modify.flags |= BNXT_NVM_LAST_FLAG;
2510+
}
2511+
memcpy(kmem, fw->data + copied, len);
2512+
modify.len = cpu_to_le32(len);
2513+
modify.offset = cpu_to_le32(copied);
24672514
rc = hwrm_send_message(bp, &modify, sizeof(modify),
24682515
FLASH_PACKAGE_TIMEOUT);
2469-
dma_free_coherent(&bp->pdev->dev, fw->size, kmem,
2470-
dma_handle);
2516+
if (rc)
2517+
goto pkg_abort;
2518+
copied += len;
24712519
}
2472-
}
2473-
if (rc)
2474-
goto err_exit;
2475-
2476-
if ((install_type & 0xffff) == 0)
2477-
install_type >>= 16;
2478-
bnxt_hwrm_cmd_hdr_init(bp, &install, HWRM_NVM_INSTALL_UPDATE, -1, -1);
2479-
install.install_type = cpu_to_le32(install_type);
2520+
mutex_lock(&bp->hwrm_cmd_lock);
2521+
rc = _hwrm_send_message_silent(bp, &install, sizeof(install),
2522+
INSTALL_PACKAGE_TIMEOUT);
2523+
memcpy(&resp, bp->hwrm_cmd_resp_addr, sizeof(resp));
24802524

2481-
mutex_lock(&bp->hwrm_cmd_lock);
2482-
rc = _hwrm_send_message(bp, &install, sizeof(install),
2483-
INSTALL_PACKAGE_TIMEOUT);
2484-
if (rc) {
2485-
u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err;
2525+
if (defrag_attempted) {
2526+
/* We have tried to defragment already in the previous
2527+
* iteration. Return with the result for INSTALL_UPDATE
2528+
*/
2529+
mutex_unlock(&bp->hwrm_cmd_lock);
2530+
break;
2531+
}
24862532

2487-
if (resp->error_code && error_code ==
2533+
if (rc && ((struct hwrm_err_output *)&resp)->cmd_err ==
24882534
NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) {
2489-
install.flags |= cpu_to_le16(
2490-
NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG);
2491-
rc = _hwrm_send_message(bp, &install, sizeof(install),
2492-
INSTALL_PACKAGE_TIMEOUT);
2535+
install.flags |=
2536+
cpu_to_le16(NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG);
2537+
2538+
rc = _hwrm_send_message_silent(bp, &install,
2539+
sizeof(install),
2540+
INSTALL_PACKAGE_TIMEOUT);
2541+
memcpy(&resp, bp->hwrm_cmd_resp_addr, sizeof(resp));
2542+
2543+
if (rc && ((struct hwrm_err_output *)&resp)->cmd_err ==
2544+
NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE) {
2545+
/* FW has cleared NVM area, driver will create
2546+
* UPDATE directory and try the flash again
2547+
*/
2548+
defrag_attempted = true;
2549+
rc = __bnxt_flash_nvram(bp->dev,
2550+
BNX_DIR_TYPE_UPDATE,
2551+
BNX_DIR_ORDINAL_FIRST,
2552+
0, 0, item_len, NULL,
2553+
0);
2554+
} else if (rc) {
2555+
netdev_err(dev, "HWRM_NVM_INSTALL_UPDATE failure rc :%x\n", rc);
2556+
}
2557+
} else if (rc) {
2558+
netdev_err(dev, "HWRM_NVM_INSTALL_UPDATE failure rc :%x\n", rc);
24932559
}
2494-
if (rc)
2495-
goto flash_pkg_exit;
2496-
}
2560+
mutex_unlock(&bp->hwrm_cmd_lock);
2561+
} while (defrag_attempted && !rc);
24972562

2498-
if (resp->result) {
2563+
pkg_abort:
2564+
dma_free_coherent(&bp->pdev->dev, modify_len, kmem, dma_handle);
2565+
if (resp.result) {
24992566
netdev_err(dev, "PKG install error = %d, problem_item = %d\n",
2500-
(s8)resp->result, (int)resp->problem_item);
2567+
(s8)resp.result, (int)resp.problem_item);
25012568
rc = -ENOPKG;
25022569
}
2503-
flash_pkg_exit:
2504-
mutex_unlock(&bp->hwrm_cmd_lock);
2505-
err_exit:
25062570
if (rc == -EACCES)
25072571
bnxt_print_admin_err(bp);
25082572
return rc;

0 commit comments

Comments
 (0)