return ret;
}
-static void wl1271_fetch_nvs(struct wl1271 *wl)
-{
- const struct firmware *fw;
- int ret;
-
- ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
-
- if (ret < 0) {
- wl1271_debug(DEBUG_BOOT, "could not get nvs file %s: %d",
- WL12XX_NVS_NAME, ret);
- return;
- }
-
- wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
-
- if (!wl->nvs) {
- wl1271_error("could not allocate memory for the nvs file");
- goto out;
- }
-
- wl->nvs_len = fw->size;
-
-out:
- release_firmware(fw);
-}
-
void wl12xx_queue_recovery_work(struct wl1271 *wl)
{
WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
if (wl->mac80211_registered)
return 0;
- wl1271_fetch_nvs(wl);
- if (wl->nvs != NULL) {
+ if (wl->nvs_len >= 12) {
/* NOTE: The wl->nvs->nvs element must be first, in
* order to simplify the casting, we assume it is at
* the beginning of the wl->nvs structure.
wl->fw_type = WL12XX_FW_TYPE_NONE;
mutex_init(&wl->mutex);
mutex_init(&wl->flush_mutex);
+ init_completion(&wl->nvs_loading_complete);
order = get_order(aggr_buf_size);
wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
return IRQ_WAKE_THREAD;
}
-int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
+static void wlcore_nvs_cb(const struct firmware *fw, void *context)
{
+ struct wl1271 *wl = context;
+ struct platform_device *pdev = wl->pdev;
struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
unsigned long irqflags;
int ret;
- if (!wl->ops || !wl->ptable) {
- ret = -EINVAL;
- goto out;
+ if (fw) {
+ wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
+ if (!wl->nvs) {
+ wl1271_error("Could not allocate nvs data");
+ goto out;
+ }
+ wl->nvs_len = fw->size;
+ } else {
+ wl1271_debug(DEBUG_BOOT, "Could not get nvs file %s",
+ WL12XX_NVS_NAME);
+ wl->nvs = NULL;
+ wl->nvs_len = 0;
}
- wl->dev = &pdev->dev;
- wl->pdev = pdev;
- platform_set_drvdata(pdev, wl);
-
ret = wl->ops->setup(wl);
if (ret < 0)
- goto out;
+ goto out_free_nvs;
BUG_ON(wl->num_tx_desc > WLCORE_MAX_TX_DESCRIPTORS);
pdev->name, wl);
if (ret < 0) {
wl1271_error("request_irq() failed: %d", ret);
- goto out;
+ goto out_free_nvs;
}
#ifdef CONFIG_PM
goto out_hw_pg_ver;
}
+ wl->initialized = true;
goto out;
out_hw_pg_ver:
out_irq:
free_irq(wl->irq, wl);
+out_free_nvs:
+ kfree(wl->nvs);
+
out:
+ release_firmware(fw);
+ complete_all(&wl->nvs_loading_complete);
+}
+
+int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
+{
+ int ret;
+
+ if (!wl->ops || !wl->ptable)
+ return -EINVAL;
+
+ wl->dev = &pdev->dev;
+ wl->pdev = pdev;
+ platform_set_drvdata(pdev, wl);
+
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ WL12XX_NVS_NAME, &pdev->dev, GFP_KERNEL,
+ wl, wlcore_nvs_cb);
+ if (ret < 0) {
+ wl1271_error("request_firmware_nowait failed: %d", ret);
+ complete_all(&wl->nvs_loading_complete);
+ }
+
return ret;
}
EXPORT_SYMBOL_GPL(wlcore_probe);
{
struct wl1271 *wl = platform_get_drvdata(pdev);
+ wait_for_completion(&wl->nvs_loading_complete);
+ if (!wl->initialized)
+ return 0;
+
if (wl->irq_wake_enabled) {
device_init_wakeup(wl->dev, 0);
disable_irq_wake(wl->irq);