Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4651ed7 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "cnss_pci: fix the race condition in firmware file setup"

parents d57c4325 973424e7
Loading
Loading
Loading
Loading
+56 −6
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ static DEFINE_SPINLOCK(pci_link_down_lock);
#define FW_IMAGE_MISSION	(0x02)
#define FW_IMAGE_BDATA		(0x03)
#define FW_IMAGE_PRINT		(0x04)
#define FW_SETUP_DELAY		2000

#define SEG_METADATA		(0x01)
#define SEG_NON_PAGED		(0x02)
@@ -244,7 +245,7 @@ static struct cnss_data {
	struct pci_saved_state *saved_state;
	u16 revision_id;
	bool recovery_in_progress;
	bool fw_available;
	atomic_t fw_available;
	struct codeswap_codeseg_info *cnss_seg_info;
	/* Virtual Address of the DMA page */
	void *codeseg_cpuaddr[CODESWAP_MAX_CODESEGS];
@@ -273,6 +274,10 @@ static struct cnss_data {
	u32 fw_dma_size;
	u32 fw_seg_count;
	struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS];
	atomic_t fw_store_in_progress;
	/* Firmware setup complete lock */
	struct mutex fw_setup_stat_lock;
	struct completion fw_setup_complete;
	void *bdata_cpu;
	dma_addr_t bdata_dma;
	u32 bdata_dma_size;
@@ -1369,10 +1374,21 @@ int cnss_get_fw_image(struct image_desc_info *image_desc_info)
	    !penv->fw_seg_count || !penv->bdata_seg_count)
		return -EINVAL;

	/* Check for firmware setup trigger by usersapce is in progress
	 * and wait for complition of firmware setup.
	 */

	if (atomic_read(&penv->fw_store_in_progress)) {
		wait_for_completion_timeout(&penv->fw_setup_complete,
					    msecs_to_jiffies(FW_SETUP_DELAY));
	}

	mutex_lock(&penv->fw_setup_stat_lock);
	image_desc_info->fw_addr = penv->fw_dma;
	image_desc_info->fw_size = penv->fw_dma_size;
	image_desc_info->bdata_addr = penv->bdata_dma;
	image_desc_info->bdata_size = penv->bdata_dma_size;
	mutex_unlock(&penv->fw_setup_stat_lock);

	return 0;
}
@@ -1552,7 +1568,7 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev,

	penv->pdev = pdev;
	penv->id = id;
	penv->fw_available = false;
	atomic_set(&penv->fw_available, 0);
	penv->device_id = pdev->device;

	if (penv->smmu_iova_len) {
@@ -1858,8 +1874,19 @@ static ssize_t fw_image_setup_store(struct device *dev,
	if (!penv)
		return -ENODEV;

	if (sscanf(buf, "%d", &val) != 1)
	if (atomic_read(&penv->fw_store_in_progress)) {
		pr_info("%s: Firmware setup in progress\n", __func__);
		return 0;
	}

	atomic_set(&penv->fw_store_in_progress, 1);
	init_completion(&penv->fw_setup_complete);

	if (kstrtoint(buf, 0, &val)) {
		atomic_set(&penv->fw_store_in_progress, 0);
		complete(&penv->fw_setup_complete);
		return -EINVAL;
	}

	if (val == FW_IMAGE_FTM || val == FW_IMAGE_MISSION
	    || val == FW_IMAGE_BDATA) {
@@ -1868,6 +1895,8 @@ static ssize_t fw_image_setup_store(struct device *dev,
		if (ret != 0) {
			pr_err("%s: Invalid parsing of FW image files %d",
			       __func__, ret);
			atomic_set(&penv->fw_store_in_progress, 0);
			complete(&penv->fw_setup_complete);
			return -EINVAL;
		}
		penv->fw_image_setup = val;
@@ -1877,6 +1906,9 @@ static ssize_t fw_image_setup_store(struct device *dev,
		penv->bmi_test = val;
	}

	atomic_set(&penv->fw_store_in_progress, 0);
	complete(&penv->fw_setup_complete);

	return count;
}

@@ -1979,7 +2011,7 @@ int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg)
		swap_seg = NULL;
		return -ENOENT;
	}
	if (!penv->fw_available) {
	if (!atomic_read(&penv->fw_available)) {
		pr_debug("%s: fw is not available\n", __func__);
		return -ENOENT;
	}
@@ -2003,6 +2035,16 @@ static void cnss_wlan_memory_expansion(void)
	u_int32_t total_length = 0;
	struct pci_dev *pdev;

	/* Check for firmware setup trigger by usersapce is in progress
	 * and wait for complition of firmware setup.
	 */

	if (atomic_read(&penv->fw_store_in_progress)) {
		wait_for_completion_timeout(&penv->fw_setup_complete,
					    msecs_to_jiffies(FW_SETUP_DELAY));
	}

	mutex_lock(&penv->fw_setup_stat_lock);
	filename = cnss_wlan_get_evicted_data_file();
	pdev = penv->pdev;
	dev = &pdev->dev;
@@ -2010,21 +2052,25 @@ static void cnss_wlan_memory_expansion(void)

	if (!cnss_seg_info) {
		pr_debug("cnss: cnss_seg_info is NULL\n");
		mutex_unlock(&penv->fw_setup_stat_lock);
		goto end;
	}

	if (penv->fw_available) {
	if (atomic_read(&penv->fw_available)) {
		pr_debug("cnss: fw code already copied to host memory\n");
		mutex_unlock(&penv->fw_setup_stat_lock);
		goto end;
	}

	if (request_firmware(&fw_entry, filename, dev) != 0) {
		pr_debug("cnss: failed to get fw: %s\n", filename);
		mutex_unlock(&penv->fw_setup_stat_lock);
		goto end;
	}

	if (!fw_entry || !fw_entry->data) {
		pr_err("%s: INVALID FW entries\n", __func__);
		mutex_unlock(&penv->fw_setup_stat_lock);
		goto release_fw;
	}

@@ -2059,7 +2105,9 @@ static void cnss_wlan_memory_expansion(void)
	}
	pr_debug("cnss: total_bytes copied: %d\n", total_length);
	cnss_seg_info->codeseg_total_bytes = total_length;
	penv->fw_available = 1;

	atomic_set(&penv->fw_available, 1);
	mutex_unlock(&penv->fw_setup_stat_lock);

release_fw:
	release_firmware(fw_entry);
@@ -2968,6 +3016,8 @@ skip_ramdump:
	memset(phys_to_virt(0), 0, SZ_4K);
#endif

	atomic_set(&penv->fw_store_in_progress, 0);
	mutex_init(&penv->fw_setup_stat_lock);
	ret = device_create_file(dev, &dev_attr_fw_image_setup);
	if (ret) {
		pr_err("cnss: fw_image_setup sys file creation failed\n");