Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'eth-fbnic-add-devlink-dev-flash-support'

Lee Trager says:

====================
eth: fbnic: Add devlink dev flash support

fbnic supports updating firmware using signed PLDM images. PLDM images are
written into the flash. Flashing does not interrupt the operation of the
device.

V4: https://lore.kernel.org/netdev/20250510002851.3247880-1-lee@trager.us/T/#t
V3: https://lore.kernel.org/lkml/20241111043058.1251632-1-lee@trager.us/T/
V2: https://lore.kernel.org/all/20241022013941.3764567-1-lee@trager.us/
====================

Link: https://patch.msgid.link/20250512190109.2475614-1-lee@trager.us
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+616 -23
+11
Documentation/networking/device_drivers/ethernet/meta/fbnic.rst
··· 28 28 addition to the version the hg commit hash of the build is included as a 29 29 separate entry. 30 30 31 + Upgrading Firmware 32 + ------------------ 33 + 34 + fbnic supports updating firmware using signed PLDM images with devlink dev 35 + flash. PLDM images are written into the flash. Flashing does not interrupt 36 + the operation of the device. 37 + 38 + On host boot the latest UEFI driver is always used, no explicit activation 39 + is required. Firmware activation is required to run new control firmware. cmrt 40 + firmware can only be activated by power cycling the NIC. 41 + 31 42 Statistics 32 43 ---------- 33 44
+1
drivers/net/ethernet/meta/Kconfig
··· 27 27 select NET_DEVLINK 28 28 select PAGE_POOL 29 29 select PHYLINK 30 + select PLDMFW 30 31 help 31 32 This driver supports Meta Platforms Host Network Interface. 32 33
+2 -1
drivers/net/ethernet/meta/fbnic/fbnic.h
··· 19 19 struct fbnic_napi_vector; 20 20 21 21 #define FBNIC_MAX_NAPI_VECTORS 128u 22 + #define FBNIC_MBX_CMPL_SLOTS 4 22 23 23 24 struct fbnic_dev { 24 25 struct device *dev; ··· 43 42 44 43 struct fbnic_fw_mbx mbx[FBNIC_IPC_MBX_INDICES]; 45 44 struct fbnic_fw_cap fw_cap; 46 - struct fbnic_fw_completion *cmpl_data; 45 + struct fbnic_fw_completion *cmpl_data[FBNIC_MBX_CMPL_SLOTS]; 47 46 /* Lock protecting Tx Mailbox queue to prevent possible races */ 48 47 spinlock_t fw_tx_lock; 49 48
+259 -1
drivers/net/ethernet/meta/fbnic/fbnic_devlink.c
··· 3 3 4 4 #include <linux/unaligned.h> 5 5 #include <linux/pci.h> 6 + #include <linux/pldmfw.h> 6 7 #include <linux/types.h> 7 8 #include <net/devlink.h> 8 9 9 10 #include "fbnic.h" 11 + #include "fbnic_tlv.h" 10 12 11 13 #define FBNIC_SN_STR_LEN 24 12 14 ··· 111 109 return 0; 112 110 } 113 111 112 + static bool 113 + fbnic_pldm_match_record(struct pldmfw *context, struct pldmfw_record *record) 114 + { 115 + struct pldmfw_desc_tlv *desc; 116 + u32 anti_rollback_ver = 0; 117 + struct devlink *devlink; 118 + struct fbnic_dev *fbd; 119 + struct pci_dev *pdev; 120 + 121 + /* First, use the standard PCI matching function */ 122 + if (!pldmfw_op_pci_match_record(context, record)) 123 + return false; 124 + 125 + pdev = to_pci_dev(context->dev); 126 + fbd = pci_get_drvdata(pdev); 127 + devlink = priv_to_devlink(fbd); 128 + 129 + /* If PCI match is successful, check for vendor-specific descriptors */ 130 + list_for_each_entry(desc, &record->descs, entry) { 131 + if (desc->type != PLDM_DESC_ID_VENDOR_DEFINED) 132 + continue; 133 + 134 + if (desc->size < 21 || desc->data[0] != 1 || 135 + desc->data[1] != 15) 136 + continue; 137 + 138 + if (memcmp(desc->data + 2, "AntiRollbackVer", 15) != 0) 139 + continue; 140 + 141 + anti_rollback_ver = get_unaligned_le32(desc->data + 17); 142 + break; 143 + } 144 + 145 + /* Compare versions and return error if they do not match */ 146 + if (anti_rollback_ver < fbd->fw_cap.anti_rollback_version) { 147 + char buf[128]; 148 + 149 + snprintf(buf, sizeof(buf), 150 + "New firmware anti-rollback version (0x%x) is older than device version (0x%x)!", 151 + anti_rollback_ver, fbd->fw_cap.anti_rollback_version); 152 + devlink_flash_update_status_notify(devlink, buf, 153 + "Anti-Rollback", 0, 0); 154 + 155 + return false; 156 + } 157 + 158 + return true; 159 + } 160 + 161 + static int 162 + fbnic_flash_start(struct fbnic_dev *fbd, struct pldmfw_component *component) 163 + { 164 + struct fbnic_fw_completion *cmpl; 165 + int err; 166 + 167 + cmpl = kzalloc(sizeof(*cmpl), GFP_KERNEL); 168 + if (!cmpl) 169 + return -ENOMEM; 170 + 171 + fbnic_fw_init_cmpl(cmpl, FBNIC_TLV_MSG_ID_FW_START_UPGRADE_REQ); 172 + err = fbnic_fw_xmit_fw_start_upgrade(fbd, cmpl, 173 + component->identifier, 174 + component->component_size); 175 + if (err) 176 + goto cmpl_free; 177 + 178 + /* Wait for firmware to ack firmware upgrade start */ 179 + if (wait_for_completion_timeout(&cmpl->done, 10 * HZ)) 180 + err = cmpl->result; 181 + else 182 + err = -ETIMEDOUT; 183 + 184 + fbnic_fw_clear_cmpl(fbd, cmpl); 185 + cmpl_free: 186 + fbnic_fw_put_cmpl(cmpl); 187 + 188 + return err; 189 + } 190 + 191 + static int 192 + fbnic_flash_component(struct pldmfw *context, 193 + struct pldmfw_component *component) 194 + { 195 + const u8 *data = component->component_data; 196 + const u32 size = component->component_size; 197 + struct fbnic_fw_completion *cmpl; 198 + const char *component_name; 199 + struct devlink *devlink; 200 + struct fbnic_dev *fbd; 201 + struct pci_dev *pdev; 202 + u32 offset = 0; 203 + u32 length = 0; 204 + char buf[32]; 205 + int err; 206 + 207 + pdev = to_pci_dev(context->dev); 208 + fbd = pci_get_drvdata(pdev); 209 + devlink = priv_to_devlink(fbd); 210 + 211 + switch (component->identifier) { 212 + case QSPI_SECTION_CMRT: 213 + component_name = "boot1"; 214 + break; 215 + case QSPI_SECTION_CONTROL_FW: 216 + component_name = "boot2"; 217 + break; 218 + case QSPI_SECTION_OPTION_ROM: 219 + component_name = "option-rom"; 220 + break; 221 + default: 222 + snprintf(buf, sizeof(buf), "Unknown component ID %u!", 223 + component->identifier); 224 + devlink_flash_update_status_notify(devlink, buf, NULL, 0, 225 + size); 226 + return -EINVAL; 227 + } 228 + 229 + /* Once firmware receives the request to start upgrading it responds 230 + * with two messages: 231 + * 1. An ACK that it received the message and possible error code 232 + * indicating that an upgrade is not currently possible. 233 + * 2. A request for the first chunk of data 234 + * 235 + * Setup completions for write before issuing the start message so 236 + * the driver can catch both messages. 237 + */ 238 + cmpl = kzalloc(sizeof(*cmpl), GFP_KERNEL); 239 + if (!cmpl) 240 + return -ENOMEM; 241 + 242 + fbnic_fw_init_cmpl(cmpl, FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_REQ); 243 + err = fbnic_mbx_set_cmpl(fbd, cmpl); 244 + if (err) 245 + goto cmpl_free; 246 + 247 + devlink_flash_update_timeout_notify(devlink, "Initializing", 248 + component_name, 15); 249 + err = fbnic_flash_start(fbd, component); 250 + if (err) 251 + goto err_no_msg; 252 + 253 + while (offset < size) { 254 + if (!wait_for_completion_timeout(&cmpl->done, 15 * HZ)) { 255 + err = -ETIMEDOUT; 256 + break; 257 + } 258 + 259 + err = cmpl->result; 260 + if (err) 261 + break; 262 + 263 + /* Verify firmware is requesting the next chunk in the seq. */ 264 + if (cmpl->u.fw_update.offset != offset + length) { 265 + err = -EFAULT; 266 + break; 267 + } 268 + 269 + offset = cmpl->u.fw_update.offset; 270 + length = cmpl->u.fw_update.length; 271 + 272 + if (length > TLV_MAX_DATA || offset + length > size) { 273 + err = -EFAULT; 274 + break; 275 + } 276 + 277 + devlink_flash_update_status_notify(devlink, "Flashing", 278 + component_name, 279 + offset, size); 280 + 281 + /* Mailbox will set length to 0 once it receives the finish 282 + * message. 283 + */ 284 + if (!length) 285 + continue; 286 + 287 + reinit_completion(&cmpl->done); 288 + err = fbnic_fw_xmit_fw_write_chunk(fbd, data, offset, length, 289 + 0); 290 + if (err) 291 + break; 292 + } 293 + 294 + if (err) { 295 + fbnic_fw_xmit_fw_write_chunk(fbd, NULL, 0, 0, err); 296 + err_no_msg: 297 + snprintf(buf, sizeof(buf), "Mailbox encountered error %d!", 298 + err); 299 + devlink_flash_update_status_notify(devlink, buf, 300 + component_name, 0, 0); 301 + } 302 + 303 + fbnic_fw_clear_cmpl(fbd, cmpl); 304 + cmpl_free: 305 + fbnic_fw_put_cmpl(cmpl); 306 + 307 + return err; 308 + } 309 + 310 + static const struct pldmfw_ops fbnic_pldmfw_ops = { 311 + .match_record = fbnic_pldm_match_record, 312 + .flash_component = fbnic_flash_component, 313 + }; 314 + 315 + static int 316 + fbnic_devlink_flash_update(struct devlink *devlink, 317 + struct devlink_flash_update_params *params, 318 + struct netlink_ext_ack *extack) 319 + { 320 + struct fbnic_dev *fbd = devlink_priv(devlink); 321 + const struct firmware *fw = params->fw; 322 + struct device *dev = fbd->dev; 323 + struct pldmfw context; 324 + char *err_msg; 325 + int err; 326 + 327 + context.ops = &fbnic_pldmfw_ops; 328 + context.dev = dev; 329 + 330 + err = pldmfw_flash_image(&context, fw); 331 + if (err) { 332 + switch (err) { 333 + case -EINVAL: 334 + err_msg = "Invalid image"; 335 + break; 336 + case -EOPNOTSUPP: 337 + err_msg = "Unsupported image"; 338 + break; 339 + case -ENOMEM: 340 + err_msg = "Out of memory"; 341 + break; 342 + case -EFAULT: 343 + err_msg = "Invalid header"; 344 + break; 345 + case -ENOENT: 346 + err_msg = "No matching record"; 347 + break; 348 + case -ENODEV: 349 + err_msg = "No matching device"; 350 + break; 351 + case -ETIMEDOUT: 352 + err_msg = "Timed out waiting for reply"; 353 + break; 354 + default: 355 + err_msg = "Unknown error"; 356 + break; 357 + } 358 + 359 + NL_SET_ERR_MSG_FMT_MOD(extack, 360 + "Failed to flash PLDM Image: %s (error: %d)", 361 + err_msg, err); 362 + } 363 + 364 + return err; 365 + } 366 + 114 367 static const struct devlink_ops fbnic_devlink_ops = { 115 - .info_get = fbnic_devlink_info_get, 368 + .info_get = fbnic_devlink_info_get, 369 + .flash_update = fbnic_devlink_flash_update, 116 370 }; 117 371 118 372 void fbnic_devlink_free(struct fbnic_dev *fbd)
+275 -19
drivers/net/ethernet/meta/fbnic/fbnic_fw.c
··· 237 237 return err; 238 238 } 239 239 240 + static int fbnic_mbx_set_cmpl_slot(struct fbnic_dev *fbd, 241 + struct fbnic_fw_completion *cmpl_data) 242 + { 243 + struct fbnic_fw_mbx *tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX]; 244 + int free = -EXFULL; 245 + int i; 246 + 247 + if (!tx_mbx->ready) 248 + return -ENODEV; 249 + 250 + for (i = 0; i < FBNIC_MBX_CMPL_SLOTS; i++) { 251 + if (!fbd->cmpl_data[i]) 252 + free = i; 253 + else if (fbd->cmpl_data[i]->msg_type == cmpl_data->msg_type) 254 + return -EEXIST; 255 + } 256 + 257 + if (free == -EXFULL) 258 + return -EXFULL; 259 + 260 + fbd->cmpl_data[free] = cmpl_data; 261 + 262 + return 0; 263 + } 264 + 265 + static void fbnic_mbx_clear_cmpl_slot(struct fbnic_dev *fbd, 266 + struct fbnic_fw_completion *cmpl_data) 267 + { 268 + int i; 269 + 270 + for (i = 0; i < FBNIC_MBX_CMPL_SLOTS; i++) { 271 + if (fbd->cmpl_data[i] == cmpl_data) { 272 + fbd->cmpl_data[i] = NULL; 273 + break; 274 + } 275 + } 276 + } 277 + 240 278 static void fbnic_mbx_process_tx_msgs(struct fbnic_dev *fbd) 241 279 { 242 280 struct fbnic_fw_mbx *tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX]; ··· 296 258 tx_mbx->head = head; 297 259 } 298 260 261 + int fbnic_mbx_set_cmpl(struct fbnic_dev *fbd, 262 + struct fbnic_fw_completion *cmpl_data) 263 + { 264 + unsigned long flags; 265 + int err; 266 + 267 + spin_lock_irqsave(&fbd->fw_tx_lock, flags); 268 + err = fbnic_mbx_set_cmpl_slot(fbd, cmpl_data); 269 + spin_unlock_irqrestore(&fbd->fw_tx_lock, flags); 270 + 271 + return err; 272 + } 273 + 299 274 static int fbnic_mbx_map_req_w_cmpl(struct fbnic_dev *fbd, 300 275 struct fbnic_tlv_msg *msg, 301 276 struct fbnic_fw_completion *cmpl_data) ··· 317 266 int err; 318 267 319 268 spin_lock_irqsave(&fbd->fw_tx_lock, flags); 320 - 321 - /* If we are already waiting on a completion then abort */ 322 - if (cmpl_data && fbd->cmpl_data) { 323 - err = -EBUSY; 324 - goto unlock_mbx; 269 + if (cmpl_data) { 270 + err = fbnic_mbx_set_cmpl_slot(fbd, cmpl_data); 271 + if (err) 272 + goto unlock_mbx; 325 273 } 326 - 327 - /* Record completion location and submit request */ 328 - if (cmpl_data) 329 - fbd->cmpl_data = cmpl_data; 330 274 331 275 err = fbnic_mbx_map_msg(fbd, FBNIC_IPC_MBX_TX_IDX, msg, 332 276 le16_to_cpu(msg->hdr.len) * sizeof(u32), 1); 333 277 334 - /* If msg failed then clear completion data for next caller */ 278 + /* If we successfully reserved a completion and msg failed 279 + * then clear completion data for next caller 280 + */ 335 281 if (err && cmpl_data) 336 - fbd->cmpl_data = NULL; 282 + fbnic_mbx_clear_cmpl_slot(fbd, cmpl_data); 337 283 338 284 unlock_mbx: 339 285 spin_unlock_irqrestore(&fbd->fw_tx_lock, flags); ··· 352 304 { 353 305 struct fbnic_fw_completion *cmpl_data = NULL; 354 306 unsigned long flags; 307 + int i; 355 308 356 309 spin_lock_irqsave(&fbd->fw_tx_lock, flags); 357 - if (fbd->cmpl_data && fbd->cmpl_data->msg_type == msg_type) { 358 - cmpl_data = fbd->cmpl_data; 359 - kref_get(&fbd->cmpl_data->ref_count); 310 + for (i = 0; i < FBNIC_MBX_CMPL_SLOTS; i++) { 311 + if (fbd->cmpl_data[i] && 312 + fbd->cmpl_data[i]->msg_type == msg_type) { 313 + cmpl_data = fbd->cmpl_data[i]; 314 + kref_get(&cmpl_data->ref_count); 315 + break; 316 + } 360 317 } 318 + 361 319 spin_unlock_irqrestore(&fbd->fw_tx_lock, flags); 362 320 363 321 return cmpl_data; ··· 518 464 FBNIC_TLV_ATTR_U32(FBNIC_FW_CAP_RESP_UEFI_VERSION), 519 465 FBNIC_TLV_ATTR_STRING(FBNIC_FW_CAP_RESP_UEFI_COMMIT_STR, 520 466 FBNIC_FW_CAP_RESP_COMMIT_MAX_SIZE), 467 + FBNIC_TLV_ATTR_U32(FBNIC_FW_CAP_RESP_ANTI_ROLLBACK_VERSION), 521 468 FBNIC_TLV_ATTR_LAST 522 469 }; 523 470 ··· 640 585 641 586 if (results[FBNIC_FW_CAP_RESP_BMC_ALL_MULTI] || !bmc_present) 642 587 fbd->fw_cap.all_multi = all_multi; 588 + 589 + fbd->fw_cap.anti_rollback_version = 590 + fta_get_uint(results, FBNIC_FW_CAP_RESP_ANTI_ROLLBACK_VERSION); 643 591 644 592 return 0; 645 593 } ··· 766 708 dev_warn(fbd->dev, "Failed to send heartbeat message\n"); 767 709 } 768 710 711 + int fbnic_fw_xmit_fw_start_upgrade(struct fbnic_dev *fbd, 712 + struct fbnic_fw_completion *cmpl_data, 713 + unsigned int id, unsigned int len) 714 + { 715 + struct fbnic_tlv_msg *msg; 716 + int err; 717 + 718 + if (!fbnic_fw_present(fbd)) 719 + return -ENODEV; 720 + 721 + if (!len) 722 + return -EINVAL; 723 + 724 + msg = fbnic_tlv_msg_alloc(FBNIC_TLV_MSG_ID_FW_START_UPGRADE_REQ); 725 + if (!msg) 726 + return -ENOMEM; 727 + 728 + err = fbnic_tlv_attr_put_int(msg, FBNIC_FW_START_UPGRADE_SECTION, id); 729 + if (err) 730 + goto free_message; 731 + 732 + err = fbnic_tlv_attr_put_int(msg, FBNIC_FW_START_UPGRADE_IMAGE_LENGTH, 733 + len); 734 + if (err) 735 + goto free_message; 736 + 737 + err = fbnic_mbx_map_req_w_cmpl(fbd, msg, cmpl_data); 738 + if (err) 739 + goto free_message; 740 + 741 + return 0; 742 + 743 + free_message: 744 + free_page((unsigned long)msg); 745 + return err; 746 + } 747 + 748 + static const struct fbnic_tlv_index fbnic_fw_start_upgrade_resp_index[] = { 749 + FBNIC_TLV_ATTR_S32(FBNIC_FW_START_UPGRADE_ERROR), 750 + FBNIC_TLV_ATTR_LAST 751 + }; 752 + 753 + static int fbnic_fw_parse_fw_start_upgrade_resp(void *opaque, 754 + struct fbnic_tlv_msg **results) 755 + { 756 + struct fbnic_fw_completion *cmpl_data; 757 + struct fbnic_dev *fbd = opaque; 758 + u32 msg_type; 759 + s32 err; 760 + 761 + /* Verify we have a completion pointer */ 762 + msg_type = FBNIC_TLV_MSG_ID_FW_START_UPGRADE_REQ; 763 + cmpl_data = fbnic_fw_get_cmpl_by_type(fbd, msg_type); 764 + if (!cmpl_data) 765 + return -ENOSPC; 766 + 767 + /* Check for errors */ 768 + err = fta_get_sint(results, FBNIC_FW_START_UPGRADE_ERROR); 769 + 770 + cmpl_data->result = err; 771 + complete(&cmpl_data->done); 772 + fbnic_fw_put_cmpl(cmpl_data); 773 + 774 + return 0; 775 + } 776 + 777 + int fbnic_fw_xmit_fw_write_chunk(struct fbnic_dev *fbd, 778 + const u8 *data, u32 offset, u16 length, 779 + int cancel_error) 780 + { 781 + struct fbnic_tlv_msg *msg; 782 + int err; 783 + 784 + msg = fbnic_tlv_msg_alloc(FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_RESP); 785 + if (!msg) 786 + return -ENOMEM; 787 + 788 + /* Report error to FW to cancel upgrade */ 789 + if (cancel_error) { 790 + err = fbnic_tlv_attr_put_int(msg, FBNIC_FW_WRITE_CHUNK_ERROR, 791 + cancel_error); 792 + if (err) 793 + goto free_message; 794 + } 795 + 796 + if (data) { 797 + err = fbnic_tlv_attr_put_int(msg, FBNIC_FW_WRITE_CHUNK_OFFSET, 798 + offset); 799 + if (err) 800 + goto free_message; 801 + 802 + err = fbnic_tlv_attr_put_int(msg, FBNIC_FW_WRITE_CHUNK_LENGTH, 803 + length); 804 + if (err) 805 + goto free_message; 806 + 807 + err = fbnic_tlv_attr_put_value(msg, FBNIC_FW_WRITE_CHUNK_DATA, 808 + data + offset, length); 809 + if (err) 810 + goto free_message; 811 + } 812 + 813 + err = fbnic_mbx_map_tlv_msg(fbd, msg); 814 + if (err) 815 + goto free_message; 816 + 817 + return 0; 818 + 819 + free_message: 820 + free_page((unsigned long)msg); 821 + return err; 822 + } 823 + 824 + static const struct fbnic_tlv_index fbnic_fw_write_chunk_req_index[] = { 825 + FBNIC_TLV_ATTR_U32(FBNIC_FW_WRITE_CHUNK_OFFSET), 826 + FBNIC_TLV_ATTR_U32(FBNIC_FW_WRITE_CHUNK_LENGTH), 827 + FBNIC_TLV_ATTR_LAST 828 + }; 829 + 830 + static int fbnic_fw_parse_fw_write_chunk_req(void *opaque, 831 + struct fbnic_tlv_msg **results) 832 + { 833 + struct fbnic_fw_completion *cmpl_data; 834 + struct fbnic_dev *fbd = opaque; 835 + u32 msg_type; 836 + u32 offset; 837 + u32 length; 838 + 839 + /* Verify we have a completion pointer */ 840 + msg_type = FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_REQ; 841 + cmpl_data = fbnic_fw_get_cmpl_by_type(fbd, msg_type); 842 + if (!cmpl_data) 843 + return -ENOSPC; 844 + 845 + /* Pull length/offset pair and mark it as complete */ 846 + offset = fta_get_uint(results, FBNIC_FW_WRITE_CHUNK_OFFSET); 847 + length = fta_get_uint(results, FBNIC_FW_WRITE_CHUNK_LENGTH); 848 + cmpl_data->u.fw_update.offset = offset; 849 + cmpl_data->u.fw_update.length = length; 850 + 851 + complete(&cmpl_data->done); 852 + fbnic_fw_put_cmpl(cmpl_data); 853 + 854 + return 0; 855 + } 856 + 857 + static const struct fbnic_tlv_index fbnic_fw_finish_upgrade_req_index[] = { 858 + FBNIC_TLV_ATTR_S32(FBNIC_FW_FINISH_UPGRADE_ERROR), 859 + FBNIC_TLV_ATTR_LAST 860 + }; 861 + 862 + static int fbnic_fw_parse_fw_finish_upgrade_req(void *opaque, 863 + struct fbnic_tlv_msg **results) 864 + { 865 + struct fbnic_fw_completion *cmpl_data; 866 + struct fbnic_dev *fbd = opaque; 867 + u32 msg_type; 868 + s32 err; 869 + 870 + /* Verify we have a completion pointer */ 871 + msg_type = FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_REQ; 872 + cmpl_data = fbnic_fw_get_cmpl_by_type(fbd, msg_type); 873 + if (!cmpl_data) 874 + return -ENOSPC; 875 + 876 + /* Check for errors */ 877 + err = fta_get_sint(results, FBNIC_FW_FINISH_UPGRADE_ERROR); 878 + 879 + /* Close out update by incrementing offset by length which should 880 + * match the total size of the component. Set length to 0 since no 881 + * new chunks will be requested. 882 + */ 883 + cmpl_data->u.fw_update.offset += cmpl_data->u.fw_update.length; 884 + cmpl_data->u.fw_update.length = 0; 885 + 886 + cmpl_data->result = err; 887 + complete(&cmpl_data->done); 888 + fbnic_fw_put_cmpl(cmpl_data); 889 + 890 + return 0; 891 + } 892 + 769 893 /** 770 894 * fbnic_fw_xmit_tsene_read_msg - Create and transmit a sensor read request 771 895 * @fbd: FBNIC device structure ··· 1032 792 fbnic_fw_parse_ownership_resp), 1033 793 FBNIC_TLV_PARSER(HEARTBEAT_RESP, fbnic_heartbeat_resp_index, 1034 794 fbnic_fw_parse_heartbeat_resp), 795 + FBNIC_TLV_PARSER(FW_START_UPGRADE_RESP, 796 + fbnic_fw_start_upgrade_resp_index, 797 + fbnic_fw_parse_fw_start_upgrade_resp), 798 + FBNIC_TLV_PARSER(FW_WRITE_CHUNK_REQ, 799 + fbnic_fw_write_chunk_req_index, 800 + fbnic_fw_parse_fw_write_chunk_req), 801 + FBNIC_TLV_PARSER(FW_FINISH_UPGRADE_REQ, 802 + fbnic_fw_finish_upgrade_req_index, 803 + fbnic_fw_parse_fw_finish_upgrade_req), 1035 804 FBNIC_TLV_PARSER(TSENE_READ_RESP, 1036 805 fbnic_tsene_read_resp_index, 1037 806 fbnic_fw_parse_tsene_read_resp), ··· 1170 921 1171 922 static void fbnic_mbx_evict_all_cmpl(struct fbnic_dev *fbd) 1172 923 { 1173 - if (fbd->cmpl_data) { 1174 - __fbnic_fw_evict_cmpl(fbd->cmpl_data); 1175 - fbd->cmpl_data = NULL; 924 + int i; 925 + 926 + for (i = 0; i < FBNIC_MBX_CMPL_SLOTS; i++) { 927 + struct fbnic_fw_completion *cmpl_data = fbd->cmpl_data[i]; 928 + 929 + if (cmpl_data) 930 + __fbnic_fw_evict_cmpl(cmpl_data); 1176 931 } 932 + 933 + memset(fbd->cmpl_data, 0, sizeof(fbd->cmpl_data)); 1177 934 } 1178 935 1179 936 void fbnic_mbx_flush_tx(struct fbnic_dev *fbd) ··· 1240 985 kref_init(&fw_cmpl->ref_count); 1241 986 } 1242 987 1243 - void fbnic_fw_clear_compl(struct fbnic_dev *fbd) 988 + void fbnic_fw_clear_cmpl(struct fbnic_dev *fbd, 989 + struct fbnic_fw_completion *fw_cmpl) 1244 990 { 1245 991 unsigned long flags; 1246 992 1247 993 spin_lock_irqsave(&fbd->fw_tx_lock, flags); 1248 - fbd->cmpl_data = NULL; 994 + fbnic_mbx_clear_cmpl_slot(fbd, fw_cmpl); 1249 995 spin_unlock_irqrestore(&fbd->fw_tx_lock, flags); 1250 996 } 1251 997
+52 -1
drivers/net/ethernet/meta/fbnic/fbnic_fw.h
··· 42 42 u8 all_multi : 1; 43 43 u8 link_speed; 44 44 u8 link_fec; 45 + u32 anti_rollback_version; 45 46 }; 46 47 47 48 struct fbnic_fw_completion { ··· 52 51 int result; 53 52 union { 54 53 struct { 54 + u32 offset; 55 + u32 length; 56 + } fw_update; 57 + struct { 55 58 s32 millivolts; 56 59 s32 millidegrees; 57 60 } tsene; ··· 64 59 65 60 void fbnic_mbx_init(struct fbnic_dev *fbd); 66 61 void fbnic_mbx_clean(struct fbnic_dev *fbd); 62 + int fbnic_mbx_set_cmpl(struct fbnic_dev *fbd, 63 + struct fbnic_fw_completion *cmpl_data); 67 64 void fbnic_mbx_poll(struct fbnic_dev *fbd); 68 65 int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd); 69 66 void fbnic_mbx_flush_tx(struct fbnic_dev *fbd); 70 67 int fbnic_fw_xmit_ownership_msg(struct fbnic_dev *fbd, bool take_ownership); 71 68 int fbnic_fw_init_heartbeat(struct fbnic_dev *fbd, bool poll); 72 69 void fbnic_fw_check_heartbeat(struct fbnic_dev *fbd); 70 + int fbnic_fw_xmit_fw_start_upgrade(struct fbnic_dev *fbd, 71 + struct fbnic_fw_completion *cmpl_data, 72 + unsigned int id, unsigned int len); 73 + int fbnic_fw_xmit_fw_write_chunk(struct fbnic_dev *fbd, 74 + const u8 *data, u32 offset, u16 length, 75 + int cancel_error); 73 76 int fbnic_fw_xmit_tsene_read_msg(struct fbnic_dev *fbd, 74 77 struct fbnic_fw_completion *cmpl_data); 75 78 void fbnic_fw_init_cmpl(struct fbnic_fw_completion *cmpl_data, 76 79 u32 msg_type); 77 - void fbnic_fw_clear_compl(struct fbnic_dev *fbd); 80 + void fbnic_fw_clear_cmpl(struct fbnic_dev *fbd, 81 + struct fbnic_fw_completion *cmpl_data); 78 82 void fbnic_fw_put_cmpl(struct fbnic_fw_completion *cmpl_data); 79 83 80 84 #define fbnic_mk_full_fw_ver_str(_rev_id, _delim, _commit, _str, _str_sz) \ ··· 100 86 #define fbnic_mk_fw_ver_str(_rev_id, _str) \ 101 87 fbnic_mk_full_fw_ver_str(_rev_id, "", "", _str, sizeof(_str)) 102 88 89 + enum { 90 + QSPI_SECTION_CMRT = 0, 91 + QSPI_SECTION_CONTROL_FW = 1, 92 + QSPI_SECTION_UCODE = 2, 93 + QSPI_SECTION_OPTION_ROM = 3, 94 + QSPI_SECTION_USER = 4, 95 + QSPI_SECTION_INVALID, 96 + }; 97 + 103 98 #define FW_HEARTBEAT_PERIOD (10 * HZ) 104 99 105 100 enum { ··· 118 95 FBNIC_TLV_MSG_ID_OWNERSHIP_RESP = 0x13, 119 96 FBNIC_TLV_MSG_ID_HEARTBEAT_REQ = 0x14, 120 97 FBNIC_TLV_MSG_ID_HEARTBEAT_RESP = 0x15, 98 + FBNIC_TLV_MSG_ID_FW_START_UPGRADE_REQ = 0x22, 99 + FBNIC_TLV_MSG_ID_FW_START_UPGRADE_RESP = 0x23, 100 + FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_REQ = 0x24, 101 + FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_RESP = 0x25, 102 + FBNIC_TLV_MSG_ID_FW_FINISH_UPGRADE_REQ = 0x28, 103 + FBNIC_TLV_MSG_ID_FW_FINISH_UPGRADE_RESP = 0x29, 121 104 FBNIC_TLV_MSG_ID_TSENE_READ_REQ = 0x3C, 122 105 FBNIC_TLV_MSG_ID_TSENE_READ_RESP = 0x3D, 123 106 }; ··· 151 122 FBNIC_FW_CAP_RESP_STORED_CMRT_COMMIT_STR = 0x10, 152 123 FBNIC_FW_CAP_RESP_UEFI_VERSION = 0x11, 153 124 FBNIC_FW_CAP_RESP_UEFI_COMMIT_STR = 0x12, 125 + FBNIC_FW_CAP_RESP_ANTI_ROLLBACK_VERSION = 0x15, 154 126 FBNIC_FW_CAP_RESP_MSG_MAX 155 127 }; 156 128 ··· 179 149 FBNIC_FW_OWNERSHIP_FLAG = 0x0, 180 150 FBNIC_FW_OWNERSHIP_MSG_MAX 181 151 }; 152 + 153 + enum { 154 + FBNIC_FW_START_UPGRADE_ERROR = 0x0, 155 + FBNIC_FW_START_UPGRADE_SECTION = 0x1, 156 + FBNIC_FW_START_UPGRADE_IMAGE_LENGTH = 0x2, 157 + FBNIC_FW_START_UPGRADE_MSG_MAX 158 + }; 159 + 160 + enum { 161 + FBNIC_FW_WRITE_CHUNK_OFFSET = 0x0, 162 + FBNIC_FW_WRITE_CHUNK_LENGTH = 0x1, 163 + FBNIC_FW_WRITE_CHUNK_DATA = 0x2, 164 + FBNIC_FW_WRITE_CHUNK_ERROR = 0x3, 165 + FBNIC_FW_WRITE_CHUNK_MSG_MAX 166 + }; 167 + 168 + enum { 169 + FBNIC_FW_FINISH_UPGRADE_ERROR = 0x0, 170 + FBNIC_FW_FINISH_UPGRADE_MSG_MAX 171 + }; 172 + 182 173 #endif /* _FBNIC_FW_H_ */
+1 -1
drivers/net/ethernet/meta/fbnic/fbnic_mac.c
··· 744 744 745 745 *val = *sensor; 746 746 exit_cleanup: 747 - fbnic_fw_clear_compl(fbd); 747 + fbnic_fw_clear_cmpl(fbd, fw_cmpl); 748 748 exit_free: 749 749 fbnic_fw_put_cmpl(fw_cmpl); 750 750
+9
drivers/net/ethernet/meta/fbnic/fbnic_pci.c
··· 6 6 #include <linux/pci.h> 7 7 #include <linux/rtnetlink.h> 8 8 #include <linux/types.h> 9 + #include <net/devlink.h> 9 10 10 11 #include "fbnic.h" 11 12 #include "fbnic_drvinfo.h" ··· 389 388 rtnl_unlock(); 390 389 391 390 null_uc_addr: 391 + devl_lock(priv_to_devlink(fbd)); 392 + 392 393 fbnic_fw_free_mbx(fbd); 394 + 395 + devl_unlock(priv_to_devlink(fbd)); 393 396 394 397 /* Free the IRQs so they aren't trying to occupy sleeping CPUs */ 395 398 fbnic_free_irqs(fbd); ··· 425 420 426 421 fbd->mac->init_regs(fbd); 427 422 423 + devl_lock(priv_to_devlink(fbd)); 424 + 428 425 /* Re-enable mailbox */ 429 426 err = fbnic_fw_request_mbx(fbd); 430 427 if (err) 431 428 goto err_free_irqs; 429 + 430 + devl_unlock(priv_to_devlink(fbd)); 432 431 433 432 /* No netdev means there isn't a network interface to bring up */ 434 433 if (fbnic_init_failure(fbd))
+6
lib/pldmfw/pldmfw.c
··· 728 728 struct pldmfw_record *record = data->matching_record; 729 729 const struct pldmfw_ops *ops = data->context->ops; 730 730 731 + if (!ops->send_package_data) 732 + return 0; 733 + 731 734 return ops->send_package_data(data->context, record->package_data, 732 735 record->package_data_len); 733 736 } ··· 756 753 757 754 /* Skip components which are not intended for this device */ 758 755 if (!test_bit(index, bitmap)) 756 + continue; 757 + 758 + if (!data->context->ops->send_component_table) 759 759 continue; 760 760 761 761 /* determine whether this is the start, middle, end, or both