mwl8k: factor out firmware loading and hw init code
authorBrian Cavagnolo <brian@cozybit.com>
Sat, 13 Nov 2010 01:23:49 +0000 (17:23 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 16 Nov 2010 21:37:02 +0000 (16:37 -0500)
This is in preparation for supporting different fw images for
different interface types, and for supporting asynchronous
firmware loading.

Based on a patch from Pradeep Nemavat <pnemavat@marvell.com>
and Yogesh Powar <yogeshp@marvell.com>

Signed-off-by: Brian Cavagnolo <brian@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwl8k.c

index cfda87a595e3dbd26de37f6864fdf63fe9d91c7d..7bd8615869834c8d342ea244e76df2a940b549eb 100644 (file)
@@ -3942,73 +3942,10 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
 };
 MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
 
-static int __devinit mwl8k_probe(struct pci_dev *pdev,
-                                const struct pci_device_id *id)
+static int mwl8k_init_firmware(struct ieee80211_hw *hw)
 {
-       static int printed_version = 0;
-       struct ieee80211_hw *hw;
-       struct mwl8k_priv *priv;
+       struct mwl8k_priv *priv = hw->priv;
        int rc;
-       int i;
-
-       if (!printed_version) {
-               printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION);
-               printed_version = 1;
-       }
-
-
-       rc = pci_enable_device(pdev);
-       if (rc) {
-               printk(KERN_ERR "%s: Cannot enable new PCI device\n",
-                      MWL8K_NAME);
-               return rc;
-       }
-
-       rc = pci_request_regions(pdev, MWL8K_NAME);
-       if (rc) {
-               printk(KERN_ERR "%s: Cannot obtain PCI resources\n",
-                      MWL8K_NAME);
-               goto err_disable_device;
-       }
-
-       pci_set_master(pdev);
-
-
-       hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
-       if (hw == NULL) {
-               printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
-               rc = -ENOMEM;
-               goto err_free_reg;
-       }
-
-       SET_IEEE80211_DEV(hw, &pdev->dev);
-       pci_set_drvdata(pdev, hw);
-
-       priv = hw->priv;
-       priv->hw = hw;
-       priv->pdev = pdev;
-       priv->device_info = &mwl8k_info_tbl[id->driver_data];
-
-
-       priv->sram = pci_iomap(pdev, 0, 0x10000);
-       if (priv->sram == NULL) {
-               wiphy_err(hw->wiphy, "Cannot map device SRAM\n");
-               goto err_iounmap;
-       }
-
-       /*
-        * If BAR0 is a 32 bit BAR, the register BAR will be BAR1.
-        * If BAR0 is a 64 bit BAR, the register BAR will be BAR2.
-        */
-       priv->regs = pci_iomap(pdev, 1, 0x10000);
-       if (priv->regs == NULL) {
-               priv->regs = pci_iomap(pdev, 2, 0x10000);
-               if (priv->regs == NULL) {
-                       wiphy_err(hw->wiphy, "Cannot map device registers\n");
-                       goto err_iounmap;
-               }
-       }
-
 
        /* Reset firmware and hardware */
        mwl8k_hw_reset(priv);
@@ -4017,19 +3954,26 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
        rc = mwl8k_request_firmware(priv);
        if (rc) {
                wiphy_err(hw->wiphy, "Firmware files not found\n");
-               goto err_stop_firmware;
+               return rc;
        }
 
        /* Load firmware into hardware */
        rc = mwl8k_load_firmware(hw);
-       if (rc) {
+       if (rc)
                wiphy_err(hw->wiphy, "Cannot start firmware\n");
-               goto err_stop_firmware;
-       }
 
        /* Reclaim memory once firmware is successfully loaded */
        mwl8k_release_firmware(priv);
 
+       return rc;
+}
+
+/* initialize hw after successfully loading a firmware image */
+static int mwl8k_probe_hw(struct ieee80211_hw *hw)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       int rc = 0;
+       int i;
 
        if (priv->ap_fw) {
                priv->rxd_ops = priv->device_info->ap_rxd_ops;
@@ -4046,58 +3990,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
        priv->wmm_enabled = false;
        priv->pending_tx_pkts = 0;
 
-
-       /*
-        * Extra headroom is the size of the required DMA header
-        * minus the size of the smallest 802.11 frame (CTS frame).
-        */
-       hw->extra_tx_headroom =
-               sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts);
-
-       hw->channel_change_time = 10;
-
-       hw->queues = MWL8K_TX_QUEUES;
-
-       /* Set rssi values to dBm */
-       hw->flags |= IEEE80211_HW_SIGNAL_DBM;
-       hw->vif_data_size = sizeof(struct mwl8k_vif);
-       hw->sta_data_size = sizeof(struct mwl8k_sta);
-
-       priv->macids_used = 0;
-       INIT_LIST_HEAD(&priv->vif_list);
-
-       /* Set default radio state and preamble */
-       priv->radio_on = 0;
-       priv->radio_short_preamble = 0;
-
-       /* Finalize join worker */
-       INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
-
-       /* TX reclaim and RX tasklets.  */
-       tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
-       tasklet_disable(&priv->poll_tx_task);
-       tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw);
-       tasklet_disable(&priv->poll_rx_task);
-
-       /* Power management cookie */
-       priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
-       if (priv->cookie == NULL)
-               goto err_stop_firmware;
-
        rc = mwl8k_rxq_init(hw, 0);
        if (rc)
-               goto err_free_cookie;
+               goto err_stop_firmware;
        rxq_refill(hw, 0, INT_MAX);
 
-       mutex_init(&priv->fw_mutex);
-       priv->fw_mutex_owner = NULL;
-       priv->fw_mutex_depth = 0;
-       priv->hostcmd_wait = NULL;
-
-       spin_lock_init(&priv->tx_lock);
-
-       priv->tx_wait = NULL;
-
        for (i = 0; i < MWL8K_TX_QUEUES; i++) {
                rc = mwl8k_txq_init(hw, i);
                if (rc)
@@ -4137,13 +4034,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
                goto err_free_irq;
        }
 
-       hw->wiphy->interface_modes = 0;
-       if (priv->ap_macids_supported)
-               hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
-       if (priv->sta_macids_supported)
-               hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
-
-
        /* Turn radio off */
        rc = mwl8k_cmd_radio_disable(hw);
        if (rc) {
@@ -4162,12 +4052,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
        iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
        free_irq(priv->pdev->irq, hw);
 
-       rc = ieee80211_register_hw(hw);
-       if (rc) {
-               wiphy_err(hw->wiphy, "Cannot register device\n");
-               goto err_free_queues;
-       }
-
        wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n",
                   priv->device_info->part_name,
                   priv->hw_rev, hw->wiphy->perm_addr,
@@ -4186,14 +4070,213 @@ err_free_queues:
                mwl8k_txq_deinit(hw, i);
        mwl8k_rxq_deinit(hw, 0);
 
+err_stop_firmware:
+       mwl8k_hw_reset(priv);
+
+       return rc;
+}
+
+/*
+ * invoke mwl8k_reload_firmware to change the firmware image after the device
+ * has already been registered
+ */
+static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
+{
+       int i, rc = 0;
+       struct mwl8k_priv *priv = hw->priv;
+
+       mwl8k_stop(hw);
+       mwl8k_rxq_deinit(hw, 0);
+
+       for (i = 0; i < MWL8K_TX_QUEUES; i++)
+               mwl8k_txq_deinit(hw, i);
+
+       rc = mwl8k_init_firmware(hw, fw_image);
+       if (rc)
+               goto fail;
+
+       rc = mwl8k_probe_hw(hw);
+       if (rc)
+               goto fail;
+
+       rc = mwl8k_start(hw);
+       if (rc)
+               goto fail;
+
+       rc = mwl8k_config(hw, ~0);
+       if (rc)
+               goto fail;
+
+       for (i = 0; i < MWL8K_TX_QUEUES; i++) {
+               rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]);
+               if (rc)
+                       goto fail;
+       }
+
+       return rc;
+
+fail:
+       printk(KERN_WARNING "mwl8k: Failed to reload firmware image.\n");
+       return rc;
+}
+
+static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
+{
+       struct ieee80211_hw *hw = priv->hw;
+       int i, rc;
+
+       /*
+        * Extra headroom is the size of the required DMA header
+        * minus the size of the smallest 802.11 frame (CTS frame).
+        */
+       hw->extra_tx_headroom =
+               sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts);
+
+       hw->channel_change_time = 10;
+
+       hw->queues = MWL8K_TX_QUEUES;
+
+       /* Set rssi values to dBm */
+       hw->flags |= IEEE80211_HW_SIGNAL_DBM;
+       hw->vif_data_size = sizeof(struct mwl8k_vif);
+       hw->sta_data_size = sizeof(struct mwl8k_sta);
+
+       priv->macids_used = 0;
+       INIT_LIST_HEAD(&priv->vif_list);
+
+       /* Set default radio state and preamble */
+       priv->radio_on = 0;
+       priv->radio_short_preamble = 0;
+
+       /* Finalize join worker */
+       INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
+
+       /* TX reclaim and RX tasklets.  */
+       tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
+       tasklet_disable(&priv->poll_tx_task);
+       tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw);
+       tasklet_disable(&priv->poll_rx_task);
+
+       /* Power management cookie */
+       priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
+       if (priv->cookie == NULL)
+               return -ENOMEM;
+
+       mutex_init(&priv->fw_mutex);
+       priv->fw_mutex_owner = NULL;
+       priv->fw_mutex_depth = 0;
+       priv->hostcmd_wait = NULL;
+
+       spin_lock_init(&priv->tx_lock);
+
+       priv->tx_wait = NULL;
+
+       rc = mwl8k_probe_hw(hw);
+       if (rc)
+               goto err_free_cookie;
+
+       hw->wiphy->interface_modes = 0;
+       if (priv->ap_macids_supported || priv->device_info->fw_image_ap)
+               hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
+       if (priv->sta_macids_supported || priv->device_info->fw_image_sta)
+               hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
+
+       rc = ieee80211_register_hw(hw);
+       if (rc) {
+               wiphy_err(hw->wiphy, "Cannot register device\n");
+               goto err_unprobe_hw;
+       }
+
+       return 0;
+
+err_unprobe_hw:
+       for (i = 0; i < MWL8K_TX_QUEUES; i++)
+               mwl8k_txq_deinit(hw, i);
+       mwl8k_rxq_deinit(hw, 0);
+
 err_free_cookie:
        if (priv->cookie != NULL)
                pci_free_consistent(priv->pdev, 4,
                                priv->cookie, priv->cookie_dma);
 
+       return rc;
+}
+static int __devinit mwl8k_probe(struct pci_dev *pdev,
+                                const struct pci_device_id *id)
+{
+       static int printed_version;
+       struct ieee80211_hw *hw;
+       struct mwl8k_priv *priv;
+       int rc;
+
+       if (!printed_version) {
+               printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION);
+               printed_version = 1;
+       }
+
+
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               printk(KERN_ERR "%s: Cannot enable new PCI device\n",
+                      MWL8K_NAME);
+               return rc;
+       }
+
+       rc = pci_request_regions(pdev, MWL8K_NAME);
+       if (rc) {
+               printk(KERN_ERR "%s: Cannot obtain PCI resources\n",
+                      MWL8K_NAME);
+               goto err_disable_device;
+       }
+
+       pci_set_master(pdev);
+
+
+       hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
+       if (hw == NULL) {
+               printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
+               rc = -ENOMEM;
+               goto err_free_reg;
+       }
+
+       SET_IEEE80211_DEV(hw, &pdev->dev);
+       pci_set_drvdata(pdev, hw);
+
+       priv = hw->priv;
+       priv->hw = hw;
+       priv->pdev = pdev;
+       priv->device_info = &mwl8k_info_tbl[id->driver_data];
+
+
+       priv->sram = pci_iomap(pdev, 0, 0x10000);
+       if (priv->sram == NULL) {
+               wiphy_err(hw->wiphy, "Cannot map device SRAM\n");
+               goto err_iounmap;
+       }
+
+       /*
+        * If BAR0 is a 32 bit BAR, the register BAR will be BAR1.
+        * If BAR0 is a 64 bit BAR, the register BAR will be BAR2.
+        */
+       priv->regs = pci_iomap(pdev, 1, 0x10000);
+       if (priv->regs == NULL) {
+               priv->regs = pci_iomap(pdev, 2, 0x10000);
+               if (priv->regs == NULL) {
+                       wiphy_err(hw->wiphy, "Cannot map device registers\n");
+                       goto err_iounmap;
+               }
+       }
+
+       rc = mwl8k_init_firmware(hw);
+       if (rc)
+               goto err_stop_firmware;
+
+       rc = mwl8k_firmware_load_success(priv);
+       if (!rc)
+               return rc;
+
 err_stop_firmware:
        mwl8k_hw_reset(priv);
-       mwl8k_release_firmware(priv);
 
 err_iounmap:
        if (priv->regs != NULL)