diff options
-rw-r--r-- | drivers/net/wireless/cnss/cnss_pci.c | 62 |
1 files changed, 56 insertions, 6 deletions
diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 48d358c4722a..22c59d8c3c45 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -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"); |