int fpga_mgmt_clear_local_image_sync()

in sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c [318:421]


int fpga_mgmt_clear_local_image_sync(int slot_id, 
		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(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 clear has completed.
	 */
	ret = fpga_mgmt_get_sh_version(slot_id, &prev_sh_version);
	fail_on(ret != 0, out, "fpga_mgmt_get_sh_version failed");

	ret = fpga_pci_get_resource_map(slot_id, FPGA_APP_PF, &app_map);
	fail_on(ret != 0, out, "fpga_pci_get_resource_map failed");

	/** Clear the FPGA image (async completion) */
	ret = fpga_mgmt_clear_local_image(slot_id);
	fail_on(ret, out, "fpga_mgmt_clear_local_image failed");

	/** Wait until the status is "cleared" or timeout */
	while (!done) {
		ret = fpga_mgmt_describe_cmd(slot_id, &tmp_info, 0); /** flags==0 */

		status = (ret == 0) ? tmp_info.status : FPGA_STATUS_END;
		if (status == FPGA_STATUS_CLEARED) {
			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(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 default 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(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(slot_id, &tmp_info.spec);
	fail_on(ret, out, "fpga_pci_get_slot_spec failed");

	if (info) {
		*info = tmp_info;
	}
out:
	return ret;
}