in sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c [497:605]
int fpga_mgmt_load_local_image_sync_with_options(union fpga_mgmt_load_local_image_options *opt,
uint32_t timeout, uint32_t delay_msec,
struct fpga_mgmt_image_info *info)
{
struct fpga_mgmt_image_info tmp_info;
struct fpga_pci_resource_map app_map;
uint32_t prev_sh_version = 0;
uint32_t sh_version = 0;
uint32_t retries = 0;
bool done = false;
int status;
int ret;
fail_on_with_code(!fpga_mgmt_state.initialized, out, ret,
FPGA_ERR_SOFTWARE_PROBLEM,
"fpga_mgmt_init must be called before the library can be used");
/** Allow timeout adjustments that are greater than the defaults */
uint32_t timeout_tmp = (timeout > FPGA_MGMT_SYNC_TIMEOUT) ?
timeout : FPGA_MGMT_SYNC_TIMEOUT;
uint32_t delay_msec_tmp = (delay_msec > FPGA_MGMT_SYNC_DELAY_MSEC) ?
delay_msec : FPGA_MGMT_SYNC_DELAY_MSEC;
fail_on_with_code(opt->slot_id >= FPGA_SLOT_MAX, out, ret, -EINVAL, "invalid slot");
memset(&tmp_info, 0, sizeof(tmp_info));
/**
* Get the current SH version and PCI resource map for the app_pf
* that will be used after the load has completed.
*/
ret = fpga_mgmt_get_sh_version(opt->slot_id, &prev_sh_version);
fail_on(ret != 0, out, "fpga_mgmt_get_sh_version failed");
ret = fpga_pci_get_resource_map(opt->slot_id, FPGA_APP_PF, &app_map);
fail_on(ret != 0, out, "fpga_pci_get_resource_map failed");
/** Load the FPGA image (async completion) */
ret = fpga_mgmt_load_local_image_with_options(opt);
fail_on(ret, out, "fpga_mgmt_load_local_image failed");
/** Wait until the status is "loaded" or timeout */
while (!done) {
ret = fpga_mgmt_describe_cmd(opt->slot_id, &tmp_info, 0); /** flags==0 */
status = (ret == 0) ? tmp_info.status : FPGA_STATUS_END;
if (status == FPGA_STATUS_LOADED) {
/** Sanity check the afi_id */
ret = (strncmp(opt->afi_id, tmp_info.ids.afi_id, sizeof(tmp_info.ids.afi_id))) ?
FPGA_ERR_FAIL : 0;
fail_on(ret, out, "AFI ID mismatch: requested afi_id=%s, loaded afi_id=%s",
opt->afi_id, tmp_info.ids.afi_id);
done = true;
} else if (status == FPGA_STATUS_BUSY) {
fail_on(ret = (retries >= timeout_tmp) ? -ETIMEDOUT : 0, out,
"fpga_mgmt_describe_local_image timed out, status=%s(%d), retries=%u",
FPGA_STATUS2STR(status), status, retries);
retries++;
msleep(delay_msec_tmp);
} else {
/**
* Catch error status cases here.
* -the caller can then display the error status and cause upon return.
*/
ret = tmp_info.status_q;
goto out;
}
}
/**
* Do not perform a remove/rescan of the APP PF if the SH version and PCI IDs
* have not changed.
*/
struct afi_device_ids *afi_device_ids = &tmp_info.ids.afi_device_ids;
ret = fpga_mgmt_get_sh_version(opt->slot_id, &sh_version);
fail_on(ret != 0, out, "fpga_mgmt_get_sh_version failed");
if ((sh_version != prev_sh_version) ||
!((afi_device_ids->vendor_id == app_map.vendor_id) &&
(afi_device_ids->device_id == app_map.device_id) &&
(afi_device_ids->svid == app_map.subsystem_vendor_id) &&
(afi_device_ids->ssid == app_map.subsystem_device_id))) {
/**
* Perform a PCI device remove and recan in order to expose the unique AFI
* Vendor and Device Id.
*/
log_info("remove+rescan required, sh_version=0x%08x, prev_sh_version=0x%08x, "
"expected_ids={0x%04x, 0x%04x, 0x%04x, 0x%04x}, "
"sysfs_ids={0x%04x, 0x%04x, 0x%04x, 0x%04x}",
sh_version, prev_sh_version,
afi_device_ids->vendor_id, afi_device_ids->device_id,
afi_device_ids->svid, afi_device_ids->ssid,
app_map.vendor_id, app_map.device_id,
app_map.subsystem_vendor_id, app_map.subsystem_device_id);
ret = fpga_pci_rescan_slot_app_pfs(opt->slot_id);
fail_on(ret, out, "fpga_pci_rescan_slot_app_pfs failed");
}
/* now fill in the slot spec information after the rescan */
ret = fpga_pci_get_slot_spec(opt->slot_id, &tmp_info.spec);
fail_on(ret, out, "fpga_pci_get_slot_spec failed");
if (info) {
*info = tmp_info;
}
out:
return ret;
}