diff options
Diffstat (limited to 'drivers/net/ethernet/emulex/benet/be_cmds.c')
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.c | 756 |
1 files changed, 671 insertions, 85 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 1795c935ff02..b63d8ad2e115 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -308,8 +308,7 @@ static void be_async_grp5_cos_priority_process(struct be_adapter *adapter, if (evt->valid) { adapter->vlan_prio_bmap = evt->available_priority_bmap; - adapter->recommended_prio &= ~VLAN_PRIO_MASK; - adapter->recommended_prio = + adapter->recommended_prio_bits = evt->reco_default_priority << VLAN_PRIO_SHIFT; } } @@ -1713,49 +1712,40 @@ err: } /* Uses synchronous mcc */ -int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size) +int be_cmd_get_fat_dump_len(struct be_adapter *adapter, u32 *dump_size) { - struct be_mcc_wrb *wrb; + struct be_mcc_wrb wrb = {0}; struct be_cmd_req_get_fat *req; int status; - spin_lock_bh(&adapter->mcc_lock); - - wrb = wrb_from_mccq(adapter); - if (!wrb) { - status = -EBUSY; - goto err; - } - req = embedded_payload(wrb); + req = embedded_payload(&wrb); be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_MANAGE_FAT, sizeof(*req), wrb, - NULL); + OPCODE_COMMON_MANAGE_FAT, sizeof(*req), + &wrb, NULL); req->fat_operation = cpu_to_le32(QUERY_FAT); - status = be_mcc_notify_wait(adapter); + status = be_cmd_notify_wait(adapter, &wrb); if (!status) { - struct be_cmd_resp_get_fat *resp = embedded_payload(wrb); + struct be_cmd_resp_get_fat *resp = embedded_payload(&wrb); - if (log_size && resp->log_size) - *log_size = le32_to_cpu(resp->log_size) - + if (dump_size && resp->log_size) + *dump_size = le32_to_cpu(resp->log_size) - sizeof(u32); } -err: - spin_unlock_bh(&adapter->mcc_lock); return status; } -int be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) +int be_cmd_get_fat_dump(struct be_adapter *adapter, u32 buf_len, void *buf) { struct be_dma_mem get_fat_cmd; struct be_mcc_wrb *wrb; struct be_cmd_req_get_fat *req; u32 offset = 0, total_size, buf_size, log_offset = sizeof(u32), payload_len; - int status = 0; + int status; if (buf_len == 0) - return -EIO; + return 0; total_size = buf_len; @@ -1763,11 +1753,8 @@ int be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) get_fat_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, get_fat_cmd.size, &get_fat_cmd.dma, GFP_ATOMIC); - if (!get_fat_cmd.va) { - dev_err(&adapter->pdev->dev, - "Memory allocation failure while reading FAT data\n"); + if (!get_fat_cmd.va) return -ENOMEM; - } spin_lock_bh(&adapter->mcc_lock); @@ -2291,10 +2278,11 @@ err: return status; } -int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, - u32 data_size, u32 data_offset, - const char *obj_name, u32 *data_written, - u8 *change_status, u8 *addn_status) +static int lancer_cmd_write_object(struct be_adapter *adapter, + struct be_dma_mem *cmd, u32 data_size, + u32 data_offset, const char *obj_name, + u32 *data_written, u8 *change_status, + u8 *addn_status) { struct be_mcc_wrb *wrb; struct lancer_cmd_req_write_object *req; @@ -2410,7 +2398,8 @@ int be_cmd_query_sfp_info(struct be_adapter *adapter) return status; } -int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name) +static int lancer_cmd_delete_object(struct be_adapter *adapter, + const char *obj_name) { struct lancer_cmd_req_delete_object *req; struct be_mcc_wrb *wrb; @@ -2485,9 +2474,9 @@ err_unlock: return status; } -int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, - u32 flash_type, u32 flash_opcode, u32 img_offset, - u32 buf_size) +static int be_cmd_write_flashrom(struct be_adapter *adapter, + struct be_dma_mem *cmd, u32 flash_type, + u32 flash_opcode, u32 img_offset, u32 buf_size) { struct be_mcc_wrb *wrb; struct be_cmd_write_flashrom *req; @@ -2533,8 +2522,8 @@ err_unlock: return status; } -int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, - u16 img_optype, u32 img_offset, u32 crc_offset) +static int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, + u16 img_optype, u32 img_offset, u32 crc_offset) { struct be_cmd_read_flash_crc *req; struct be_mcc_wrb *wrb; @@ -2571,6 +2560,579 @@ err: return status; } +static char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "}; + +static bool phy_flashing_required(struct be_adapter *adapter) +{ + return (adapter->phy.phy_type == PHY_TYPE_TN_8022 && + adapter->phy.interface_type == PHY_TYPE_BASET_10GB); +} + +static bool is_comp_in_ufi(struct be_adapter *adapter, + struct flash_section_info *fsec, int type) +{ + int i = 0, img_type = 0; + struct flash_section_info_g2 *fsec_g2 = NULL; + + if (BE2_chip(adapter)) + fsec_g2 = (struct flash_section_info_g2 *)fsec; + + for (i = 0; i < MAX_FLASH_COMP; i++) { + if (fsec_g2) + img_type = le32_to_cpu(fsec_g2->fsec_entry[i].type); + else + img_type = le32_to_cpu(fsec->fsec_entry[i].type); + + if (img_type == type) + return true; + } + return false; +} + +static struct flash_section_info *get_fsec_info(struct be_adapter *adapter, + int header_size, + const struct firmware *fw) +{ + struct flash_section_info *fsec = NULL; + const u8 *p = fw->data; + + p += header_size; + while (p < (fw->data + fw->size)) { + fsec = (struct flash_section_info *)p; + if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) + return fsec; + p += 32; + } + return NULL; +} + +static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p, + u32 img_offset, u32 img_size, int hdr_size, + u16 img_optype, bool *crc_match) +{ + u32 crc_offset; + int status; + u8 crc[4]; + + status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_offset, + img_size - 4); + if (status) + return status; + + crc_offset = hdr_size + img_offset + img_size - 4; + + /* Skip flashing, if crc of flashed region matches */ + if (!memcmp(crc, p + crc_offset, 4)) + *crc_match = true; + else + *crc_match = false; + + return status; +} + +static int be_flash(struct be_adapter *adapter, const u8 *img, + struct be_dma_mem *flash_cmd, int optype, int img_size, + u32 img_offset) +{ + u32 flash_op, num_bytes, total_bytes = img_size, bytes_sent = 0; + struct be_cmd_write_flashrom *req = flash_cmd->va; + int status; + + while (total_bytes) { + num_bytes = min_t(u32, 32 * 1024, total_bytes); + + total_bytes -= num_bytes; + + if (!total_bytes) { + if (optype == OPTYPE_PHY_FW) + flash_op = FLASHROM_OPER_PHY_FLASH; + else + flash_op = FLASHROM_OPER_FLASH; + } else { + if (optype == OPTYPE_PHY_FW) + flash_op = FLASHROM_OPER_PHY_SAVE; + else + flash_op = FLASHROM_OPER_SAVE; + } + + memcpy(req->data_buf, img, num_bytes); + img += num_bytes; + status = be_cmd_write_flashrom(adapter, flash_cmd, optype, + flash_op, img_offset + + bytes_sent, num_bytes); + if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST && + optype == OPTYPE_PHY_FW) + break; + else if (status) + return status; + + bytes_sent += num_bytes; + } + return 0; +} + +/* For BE2, BE3 and BE3-R */ +static int be_flash_BEx(struct be_adapter *adapter, + const struct firmware *fw, + struct be_dma_mem *flash_cmd, int num_of_images) +{ + int img_hdrs_size = (num_of_images * sizeof(struct image_hdr)); + struct device *dev = &adapter->pdev->dev; + struct flash_section_info *fsec = NULL; + int status, i, filehdr_size, num_comp; + const struct flash_comp *pflashcomp; + bool crc_match; + const u8 *p; + + struct flash_comp gen3_flash_types[] = { + { BE3_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE, + BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI}, + { BE3_REDBOOT_START, OPTYPE_REDBOOT, + BE3_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE}, + { BE3_ISCSI_BIOS_START, OPTYPE_BIOS, + BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI}, + { BE3_PXE_BIOS_START, OPTYPE_PXE_BIOS, + BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE}, + { BE3_FCOE_BIOS_START, OPTYPE_FCOE_BIOS, + BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE}, + { BE3_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP, + BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI}, + { BE3_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE, + BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE}, + { BE3_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP, + BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE}, + { BE3_NCSI_START, OPTYPE_NCSI_FW, + BE3_NCSI_COMP_MAX_SIZE, IMAGE_NCSI}, + { BE3_PHY_FW_START, OPTYPE_PHY_FW, + BE3_PHY_FW_COMP_MAX_SIZE, IMAGE_FIRMWARE_PHY} + }; + + struct flash_comp gen2_flash_types[] = { + { BE2_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE, + BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI}, + { BE2_REDBOOT_START, OPTYPE_REDBOOT, + BE2_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE}, + { BE2_ISCSI_BIOS_START, OPTYPE_BIOS, + BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI}, + { BE2_PXE_BIOS_START, OPTYPE_PXE_BIOS, + BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE}, + { BE2_FCOE_BIOS_START, OPTYPE_FCOE_BIOS, + BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE}, + { BE2_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP, + BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI}, + { BE2_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE, + BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE}, + { BE2_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP, + BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE} + }; + + if (BE3_chip(adapter)) { + pflashcomp = gen3_flash_types; + filehdr_size = sizeof(struct flash_file_hdr_g3); + num_comp = ARRAY_SIZE(gen3_flash_types); + } else { + pflashcomp = gen2_flash_types; + filehdr_size = sizeof(struct flash_file_hdr_g2); + num_comp = ARRAY_SIZE(gen2_flash_types); + img_hdrs_size = 0; + } + + /* Get flash section info*/ + fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); + if (!fsec) { + dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); + return -1; + } + for (i = 0; i < num_comp; i++) { + if (!is_comp_in_ufi(adapter, fsec, pflashcomp[i].img_type)) + continue; + + if ((pflashcomp[i].optype == OPTYPE_NCSI_FW) && + memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0) + continue; + + if (pflashcomp[i].optype == OPTYPE_PHY_FW && + !phy_flashing_required(adapter)) + continue; + + if (pflashcomp[i].optype == OPTYPE_REDBOOT) { + status = be_check_flash_crc(adapter, fw->data, + pflashcomp[i].offset, + pflashcomp[i].size, + filehdr_size + + img_hdrs_size, + OPTYPE_REDBOOT, &crc_match); + if (status) { + dev_err(dev, + "Could not get CRC for 0x%x region\n", + pflashcomp[i].optype); + continue; + } + + if (crc_match) + continue; + } + + p = fw->data + filehdr_size + pflashcomp[i].offset + + img_hdrs_size; + if (p + pflashcomp[i].size > fw->data + fw->size) + return -1; + + status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype, + pflashcomp[i].size, 0); + if (status) { + dev_err(dev, "Flashing section type 0x%x failed\n", + pflashcomp[i].img_type); + return status; + } + } + return 0; +} + +static u16 be_get_img_optype(struct flash_section_entry fsec_entry) +{ + u32 img_type = le32_to_cpu(fsec_entry.type); + u16 img_optype = le16_to_cpu(fsec_entry.optype); + + if (img_optype != 0xFFFF) + return img_optype; + + switch (img_type) { + case IMAGE_FIRMWARE_ISCSI: + img_optype = OPTYPE_ISCSI_ACTIVE; + break; + case IMAGE_BOOT_CODE: + img_optype = OPTYPE_REDBOOT; + break; + case IMAGE_OPTION_ROM_ISCSI: + img_optype = OPTYPE_BIOS; + break; + case IMAGE_OPTION_ROM_PXE: + img_optype = OPTYPE_PXE_BIOS; + break; + case IMAGE_OPTION_ROM_FCOE: + img_optype = OPTYPE_FCOE_BIOS; + break; + case IMAGE_FIRMWARE_BACKUP_ISCSI: + img_optype = OPTYPE_ISCSI_BACKUP; + break; + case IMAGE_NCSI: + img_optype = OPTYPE_NCSI_FW; + break; + case IMAGE_FLASHISM_JUMPVECTOR: + img_optype = OPTYPE_FLASHISM_JUMPVECTOR; + break; + case IMAGE_FIRMWARE_PHY: + img_optype = OPTYPE_SH_PHY_FW; + break; + case IMAGE_REDBOOT_DIR: + img_optype = OPTYPE_REDBOOT_DIR; + break; + case IMAGE_REDBOOT_CONFIG: + img_optype = OPTYPE_REDBOOT_CONFIG; + break; + case IMAGE_UFI_DIR: + img_optype = OPTYPE_UFI_DIR; + break; + default: + break; + } + + return img_optype; +} + +static int be_flash_skyhawk(struct be_adapter *adapter, + const struct firmware *fw, + struct be_dma_mem *flash_cmd, int num_of_images) +{ + int img_hdrs_size = num_of_images * sizeof(struct image_hdr); + bool crc_match, old_fw_img, flash_offset_support = true; + struct device *dev = &adapter->pdev->dev; + struct flash_section_info *fsec = NULL; + u32 img_offset, img_size, img_type; + u16 img_optype, flash_optype; + int status, i, filehdr_size; + const u8 *p; + + filehdr_size = sizeof(struct flash_file_hdr_g3); + fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); + if (!fsec) { + dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); + return -EINVAL; + } + +retry_flash: + for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) { + img_offset = le32_to_cpu(fsec->fsec_entry[i].offset); + img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size); + img_type = le32_to_cpu(fsec->fsec_entry[i].type); + img_optype = be_get_img_optype(fsec->fsec_entry[i]); + old_fw_img = fsec->fsec_entry[i].optype == 0xFFFF; + + if (img_optype == 0xFFFF) + continue; + + if (flash_offset_support) + flash_optype = OPTYPE_OFFSET_SPECIFIED; + else + flash_optype = img_optype; + + /* Don't bother verifying CRC if an old FW image is being + * flashed + */ + if (old_fw_img) + goto flash; + + status = be_check_flash_crc(adapter, fw->data, img_offset, + img_size, filehdr_size + + img_hdrs_size, flash_optype, + &crc_match); + if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST || + base_status(status) == MCC_STATUS_ILLEGAL_FIELD) { + /* The current FW image on the card does not support + * OFFSET based flashing. Retry using older mechanism + * of OPTYPE based flashing + */ + if (flash_optype == OPTYPE_OFFSET_SPECIFIED) { + flash_offset_support = false; + goto retry_flash; + } + + /* The current FW image on the card does not recognize + * the new FLASH op_type. The FW download is partially + * complete. Reboot the server now to enable FW image + * to recognize the new FLASH op_type. To complete the + * remaining process, download the same FW again after + * the reboot. + */ + dev_err(dev, "Flash incomplete. Reset the server\n"); + dev_err(dev, "Download FW image again after reset\n"); + return -EAGAIN; + } else if (status) { + dev_err(dev, "Could not get CRC for 0x%x region\n", + img_optype); + return -EFAULT; + } + + if (crc_match) + continue; + +flash: + p = fw->data + filehdr_size + img_offset + img_hdrs_size; + if (p + img_size > fw->data + fw->size) + return -1; + + status = be_flash(adapter, p, flash_cmd, flash_optype, img_size, + img_offset); + + /* The current FW image on the card does not support OFFSET + * based flashing. Retry using older mechanism of OPTYPE based + * flashing + */ + if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD && + flash_optype == OPTYPE_OFFSET_SPECIFIED) { + flash_offset_support = false; + goto retry_flash; + } + + /* For old FW images ignore ILLEGAL_FIELD error or errors on + * UFI_DIR region + */ + if (old_fw_img && + (base_status(status) == MCC_STATUS_ILLEGAL_FIELD || + (img_optype == OPTYPE_UFI_DIR && + base_status(status) == MCC_STATUS_FAILED))) { + continue; + } else if (status) { + dev_err(dev, "Flashing section type 0x%x failed\n", + img_type); + + switch (addl_status(status)) { + case MCC_ADDL_STATUS_MISSING_SIGNATURE: + dev_err(dev, + "Digital signature missing in FW\n"); + return -EINVAL; + case MCC_ADDL_STATUS_INVALID_SIGNATURE: + dev_err(dev, + "Invalid digital signature in FW\n"); + return -EINVAL; + default: + return -EFAULT; + } + } + } + return 0; +} + +int lancer_fw_download(struct be_adapter *adapter, + const struct firmware *fw) +{ + struct device *dev = &adapter->pdev->dev; + struct be_dma_mem flash_cmd; + const u8 *data_ptr = NULL; + u8 *dest_image_ptr = NULL; + size_t image_size = 0; + u32 chunk_size = 0; + u32 data_written = 0; + u32 offset = 0; + int status = 0; + u8 add_status = 0; + u8 change_status; + + if (!IS_ALIGNED(fw->size, sizeof(u32))) { + dev_err(dev, "FW image size should be multiple of 4\n"); + return -EINVAL; + } + + flash_cmd.size = sizeof(struct lancer_cmd_req_write_object) + + LANCER_FW_DOWNLOAD_CHUNK; + flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size, + &flash_cmd.dma, GFP_KERNEL); + if (!flash_cmd.va) + return -ENOMEM; + + dest_image_ptr = flash_cmd.va + + sizeof(struct lancer_cmd_req_write_object); + image_size = fw->size; + data_ptr = fw->data; + + while (image_size) { + chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK); + + /* Copy the image chunk content. */ + memcpy(dest_image_ptr, data_ptr, chunk_size); + + status = lancer_cmd_write_object(adapter, &flash_cmd, + chunk_size, offset, + LANCER_FW_DOWNLOAD_LOCATION, + &data_written, &change_status, + &add_status); + if (status) + break; + + offset += data_written; + data_ptr += data_written; + image_size -= data_written; + } + + if (!status) { + /* Commit the FW written */ + status = lancer_cmd_write_object(adapter, &flash_cmd, + 0, offset, + LANCER_FW_DOWNLOAD_LOCATION, + &data_written, &change_status, + &add_status); + } + + dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); + if (status) { + dev_err(dev, "Firmware load error\n"); + return be_cmd_status(status); + } + + dev_info(dev, "Firmware flashed successfully\n"); + + if (change_status == LANCER_FW_RESET_NEEDED) { + dev_info(dev, "Resetting adapter to activate new FW\n"); + status = lancer_physdev_ctrl(adapter, + PHYSDEV_CONTROL_FW_RESET_MASK); + if (status) { + dev_err(dev, "Adapter busy, could not reset FW\n"); + dev_err(dev, "Reboot server to activate new FW\n"); + } + } else if (change_status != LANCER_NO_RESET_NEEDED) { + dev_info(dev, "Reboot server to activate new FW\n"); + } + + return 0; +} + +/* Check if the flash image file is compatible with the adapter that + * is being flashed. + */ +static bool be_check_ufi_compatibility(struct be_adapter *adapter, + struct flash_file_hdr_g3 *fhdr) +{ + if (!fhdr) { + dev_err(&adapter->pdev->dev, "Invalid FW UFI file"); + return false; + } + + /* First letter of the build version is used to identify + * which chip this image file is meant for. + */ + switch (fhdr->build[0]) { + case BLD_STR_UFI_TYPE_SH: + if (!skyhawk_chip(adapter)) + return false; + break; + case BLD_STR_UFI_TYPE_BE3: + if (!BE3_chip(adapter)) + return false; + break; + case BLD_STR_UFI_TYPE_BE2: + if (!BE2_chip(adapter)) + return false; + break; + default: + return false; + } + + /* In BE3 FW images the "asic_type_rev" field doesn't track the + * asic_rev of the chips it is compatible with. + * When asic_type_rev is 0 the image is compatible only with + * pre-BE3-R chips (asic_rev < 0x10) + */ + if (BEx_chip(adapter) && fhdr->asic_type_rev == 0) + return adapter->asic_rev < 0x10; + else + return (fhdr->asic_type_rev >= adapter->asic_rev); +} + +int be_fw_download(struct be_adapter *adapter, const struct firmware *fw) +{ + struct device *dev = &adapter->pdev->dev; + struct flash_file_hdr_g3 *fhdr3; + struct image_hdr *img_hdr_ptr; + int status = 0, i, num_imgs; + struct be_dma_mem flash_cmd; + + fhdr3 = (struct flash_file_hdr_g3 *)fw->data; + if (!be_check_ufi_compatibility(adapter, fhdr3)) { + dev_err(dev, "Flash image is not compatible with adapter\n"); + return -EINVAL; + } + + flash_cmd.size = sizeof(struct be_cmd_write_flashrom); + flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size, &flash_cmd.dma, + GFP_KERNEL); + if (!flash_cmd.va) + return -ENOMEM; + + num_imgs = le32_to_cpu(fhdr3->num_imgs); + for (i = 0; i < num_imgs; i++) { + img_hdr_ptr = (struct image_hdr *)(fw->data + + (sizeof(struct flash_file_hdr_g3) + + i * sizeof(struct image_hdr))); + if (!BE2_chip(adapter) && + le32_to_cpu(img_hdr_ptr->imageid) != 1) + continue; + + if (skyhawk_chip(adapter)) + status = be_flash_skyhawk(adapter, fw, &flash_cmd, + num_imgs); + else + status = be_flash_BEx(adapter, fw, &flash_cmd, + num_imgs); + } + + dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); + if (!status) + dev_info(dev, "Firmware flashed successfully\n"); + + return status; +} + int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, struct be_dma_mem *nonemb_cmd) { @@ -2892,7 +3454,6 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) if (!status) { attribs = attribs_cmd.va + sizeof(struct be_cmd_resp_hdr); adapter->hba_port_num = attribs->hba_attribs.phy_port; - adapter->pci_func_num = attribs->pci_func_num; serial_num = attribs->hba_attribs.controller_serial_number; for (i = 0; i < CNTL_SERIAL_NUM_WORDS; i++) adapter->serial_num[i] = le32_to_cpu(serial_num[i]) & @@ -3575,14 +4136,16 @@ int be_cmd_query_port_name(struct be_adapter *adapter) return status; } -/* Descriptor type */ -enum { - FUNC_DESC = 1, - VFT_DESC = 2 -}; - +/* When more than 1 NIC descriptor is present in the descriptor list, + * the caller must specify the pf_num to obtain the NIC descriptor + * corresponding to its pci function. + * get_vft must be true when the caller wants the VF-template desc of the + * PF-pool. + * The pf_num should be set to PF_NUM_IGNORE when the caller knows + * that only it's NIC descriptor is present in the descriptor list. + */ static struct be_nic_res_desc *be_get_nic_desc(u8 *buf, u32 desc_count, - int desc_type) + bool get_vft, u8 pf_num) { struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; struct be_nic_res_desc *nic; @@ -3592,40 +4155,42 @@ static struct be_nic_res_desc *be_get_nic_desc(u8 *buf, u32 desc_count, if (hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V0 || hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V1) { nic = (struct be_nic_res_desc *)hdr; - if (desc_type == FUNC_DESC || - (desc_type == VFT_DESC && - nic->flags & (1 << VFT_SHIFT))) + + if ((pf_num == PF_NUM_IGNORE || + nic->pf_num == pf_num) && + (!get_vft || nic->flags & BIT(VFT_SHIFT))) return nic; } - hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; hdr = (void *)hdr + hdr->desc_len; } return NULL; } -static struct be_nic_res_desc *be_get_vft_desc(u8 *buf, u32 desc_count) +static struct be_nic_res_desc *be_get_vft_desc(u8 *buf, u32 desc_count, + u8 pf_num) { - return be_get_nic_desc(buf, desc_count, VFT_DESC); + return be_get_nic_desc(buf, desc_count, true, pf_num); } -static struct be_nic_res_desc *be_get_func_nic_desc(u8 *buf, u32 desc_count) +static struct be_nic_res_desc *be_get_func_nic_desc(u8 *buf, u32 desc_count, + u8 pf_num) { - return be_get_nic_desc(buf, desc_count, FUNC_DESC); + return be_get_nic_desc(buf, desc_count, false, pf_num); } -static struct be_pcie_res_desc *be_get_pcie_desc(u8 devfn, u8 *buf, - u32 desc_count) +static struct be_pcie_res_desc *be_get_pcie_desc(u8 *buf, u32 desc_count, + u8 pf_num) { struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; struct be_pcie_res_desc *pcie; int i; for (i = 0; i < desc_count; i++) { - if ((hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V0 || - hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V1)) { - pcie = (struct be_pcie_res_desc *)hdr; - if (pcie->pf_num == devfn) + if (hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V0 || + hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V1) { + pcie = (struct be_pcie_res_desc *)hdr; + if (pcie->pf_num == pf_num) return pcie; } @@ -3710,13 +4275,23 @@ int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res) u32 desc_count = le32_to_cpu(resp->desc_count); struct be_nic_res_desc *desc; - desc = be_get_func_nic_desc(resp->func_param, desc_count); + /* GET_FUNC_CONFIG returns resource descriptors of the + * current function only. So, pf_num should be set to + * PF_NUM_IGNORE. + */ + desc = be_get_func_nic_desc(resp->func_param, desc_count, + PF_NUM_IGNORE); if (!desc) { status = -EINVAL; goto err; } - adapter->pf_number = desc->pf_num; - be_copy_nic_desc(res, desc); + + /* Store pf_num & vf_num for later use in GET_PROFILE_CONFIG */ + adapter->pf_num = desc->pf_num; + adapter->vf_num = desc->vf_num; + + if (res) + be_copy_nic_desc(res, desc); } err: mutex_unlock(&adapter->mbox_lock); @@ -3726,10 +4301,7 @@ err: return status; } -/* Will use MBOX only if MCCQ has not been created - * non-zero domain => a PF is querying this on behalf of a VF - * zero domain => a PF or a VF is querying this for itself - */ +/* Will use MBOX only if MCCQ has not been created */ int be_cmd_get_profile_config(struct be_adapter *adapter, struct be_resources *res, u8 query, u8 domain) { @@ -3759,12 +4331,7 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, if (!lancer_chip(adapter)) req->hdr.version = 1; req->type = ACTIVE_PROFILE_TYPE; - /* When a function is querying profile information relating to - * itself hdr.pf_number must be set to it's pci_func_num + 1 - */ req->hdr.domain = domain; - if (domain == 0) - req->hdr.pf_num = adapter->pci_func_num + 1; /* When QUERY_MODIFIABLE_FIELDS_TYPE bit is set, cmd returns the * descriptors with all bits set to "1" for the fields which can be @@ -3780,8 +4347,8 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, resp = cmd.va; desc_count = le16_to_cpu(resp->desc_count); - pcie = be_get_pcie_desc(adapter->pdev->devfn, resp->func_param, - desc_count); + pcie = be_get_pcie_desc(resp->func_param, desc_count, + adapter->pf_num); if (pcie) res->max_vfs = le16_to_cpu(pcie->num_vfs); @@ -3789,11 +4356,13 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, if (port) adapter->mc_type = port->mc_type; - nic = be_get_func_nic_desc(resp->func_param, desc_count); + nic = be_get_func_nic_desc(resp->func_param, desc_count, + adapter->pf_num); if (nic) be_copy_nic_desc(res, nic); - vf_res = be_get_vft_desc(resp->func_param, desc_count); + vf_res = be_get_vft_desc(resp->func_param, desc_count, + adapter->pf_num); if (vf_res) res->vf_if_cap_flags = vf_res->cap_flags; err: @@ -3883,7 +4452,7 @@ int be_cmd_config_qos(struct be_adapter *adapter, u32 max_rate, u16 link_speed, return be_cmd_set_qos(adapter, max_rate / 10, domain); be_reset_nic_desc(&nic_desc); - nic_desc.pf_num = adapter->pf_number; + nic_desc.pf_num = adapter->pf_num; nic_desc.vf_num = domain; nic_desc.bw_min = 0; if (lancer_chip(adapter)) { @@ -4260,16 +4829,13 @@ err: return status; } -int be_cmd_set_logical_link_config(struct be_adapter *adapter, - int link_state, u8 domain) +int __be_cmd_set_logical_link_config(struct be_adapter *adapter, + int link_state, int version, u8 domain) { struct be_mcc_wrb *wrb; struct be_cmd_req_set_ll_link *req; int status; - if (BEx_chip(adapter) || lancer_chip(adapter)) - return -EOPNOTSUPP; - spin_lock_bh(&adapter->mcc_lock); wrb = wrb_from_mccq(adapter); @@ -4284,14 +4850,15 @@ int be_cmd_set_logical_link_config(struct be_adapter *adapter, OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG, sizeof(*req), wrb, NULL); - req->hdr.version = 1; + req->hdr.version = version; req->hdr.domain = domain; - if (link_state == IFLA_VF_LINK_STATE_ENABLE) - req->link_config |= 1; + if (link_state == IFLA_VF_LINK_STATE_ENABLE || + link_state == IFLA_VF_LINK_STATE_AUTO) + req->link_config |= PLINK_ENABLE; if (link_state == IFLA_VF_LINK_STATE_AUTO) - req->link_config |= 1 << PLINK_TRACK_SHIFT; + req->link_config |= PLINK_TRACK; status = be_mcc_notify_wait(adapter); err: @@ -4299,6 +4866,25 @@ err: return status; } +int be_cmd_set_logical_link_config(struct be_adapter *adapter, + int link_state, u8 domain) +{ + int status; + + if (BEx_chip(adapter)) + return -EOPNOTSUPP; + + status = __be_cmd_set_logical_link_config(adapter, link_state, + 2, domain); + + /* Version 2 of the command will not be recognized by older FW. + * On such a failure issue version 1 of the command. + */ + if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST) + status = __be_cmd_set_logical_link_config(adapter, link_state, + 1, domain); + return status; +} int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload, int wrb_payload_size, u16 *cmd_status, u16 *ext_status) { |