]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/marvell/mwifiex/pcie.c
mwifiex: pcie: use posted write to wake up firmware
[karo-tx-linux.git] / drivers / net / wireless / marvell / mwifiex / pcie.c
index 4db07da81d8daaa862a64f660d710cfd323c3fd0..396cd4a9423a09187c762d47ba8240e71b74b835 100644 (file)
@@ -31,8 +31,6 @@
 #define PCIE_VERSION   "1.0"
 #define DRV_NAME        "Marvell mwifiex PCIe"
 
-static u8 user_rmmod;
-
 static struct mwifiex_if_ops pcie_ops;
 
 static const struct of_device_id mwifiex_pcie_of_match_table[] = {
@@ -51,6 +49,8 @@ static int mwifiex_pcie_probe_of(struct device *dev)
        return 0;
 }
 
+static void mwifiex_pcie_work(struct work_struct *work);
+
 static int
 mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
                       size_t size, int flags)
@@ -78,6 +78,42 @@ static void mwifiex_unmap_pci_memory(struct mwifiex_adapter *adapter,
        pci_unmap_single(card->dev, mapping.addr, mapping.len, flags);
 }
 
+/*
+ * This function writes data into PCIE card register.
+ */
+static int mwifiex_write_reg(struct mwifiex_adapter *adapter, int reg, u32 data)
+{
+       struct pcie_service_card *card = adapter->card;
+
+       iowrite32(data, card->pci_mmap1 + reg);
+
+       return 0;
+}
+
+/* This function reads data from PCIE card register.
+ */
+static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
+{
+       struct pcie_service_card *card = adapter->card;
+
+       *data = ioread32(card->pci_mmap1 + reg);
+       if (*data == 0xffffffff)
+               return 0xffffffff;
+
+       return 0;
+}
+
+/* This function reads u8 data from PCIE card register. */
+static int mwifiex_read_reg_byte(struct mwifiex_adapter *adapter,
+                                int reg, u8 *data)
+{
+       struct pcie_service_card *card = adapter->card;
+
+       *data = ioread8(card->pci_mmap1 + reg);
+
+       return 0;
+}
+
 /*
  * This function reads sleep cookie and checks if FW is ready
  */
@@ -219,6 +255,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
                card->pcie.mem_type_mapping_tbl = data->mem_type_mapping_tbl;
                card->pcie.num_mem_types = data->num_mem_types;
                card->pcie.can_ext_scan = data->can_ext_scan;
+               INIT_WORK(&card->work, mwifiex_pcie_work);
        }
 
        /* device tree node parsing and platform specific configuration*/
@@ -245,6 +282,9 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
        struct pcie_service_card *card;
        struct mwifiex_adapter *adapter;
        struct mwifiex_private *priv;
+       const struct mwifiex_pcie_card_reg *reg;
+       u32 fw_status;
+       int ret;
 
        card = pci_get_drvdata(pdev);
 
@@ -254,7 +294,15 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
        if (!adapter || !adapter->priv_num)
                return;
 
-       if (user_rmmod && !adapter->mfg_mode) {
+       cancel_work_sync(&card->work);
+
+       reg = card->pcie.reg;
+       if (reg)
+               ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
+       else
+               fw_status = -1;
+
+       if (fw_status == FIRMWARE_READY_PCIE && !adapter->mfg_mode) {
                mwifiex_deauthenticate_all(adapter);
 
                priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
@@ -269,7 +317,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
 
 static void mwifiex_pcie_shutdown(struct pci_dev *pdev)
 {
-       user_rmmod = 1;
        mwifiex_pcie_remove(pdev);
 
        return;
@@ -330,7 +377,7 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
                 * Cleanup all software without cleaning anything related to
                 * PCIe and HW.
                 */
-               mwifiex_do_flr(adapter, prepare);
+               mwifiex_shutdown_sw(adapter);
                adapter->surprise_removed = true;
        } else {
                /* Kernel stores and restores PCIe function context before and
@@ -338,7 +385,7 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
                 * and firmware including firmware redownload
                 */
                adapter->surprise_removed = false;
-               mwifiex_do_flr(adapter, prepare);
+               mwifiex_reinit_sw(adapter);
        }
        mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
 }
@@ -368,43 +415,6 @@ static struct pci_driver __refdata mwifiex_pcie = {
        .err_handler = mwifiex_pcie_err_handler,
 };
 
-/*
- * This function writes data into PCIE card register.
- */
-static int mwifiex_write_reg(struct mwifiex_adapter *adapter, int reg, u32 data)
-{
-       struct pcie_service_card *card = adapter->card;
-
-       iowrite32(data, card->pci_mmap1 + reg);
-
-       return 0;
-}
-
-/*
- * This function reads data from PCIE card register.
- */
-static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
-{
-       struct pcie_service_card *card = adapter->card;
-
-       *data = ioread32(card->pci_mmap1 + reg);
-       if (*data == 0xffffffff)
-               return 0xffffffff;
-
-       return 0;
-}
-
-/* This function reads u8 data from PCIE card register. */
-static int mwifiex_read_reg_byte(struct mwifiex_adapter *adapter,
-                                int reg, u8 *data)
-{
-       struct pcie_service_card *card = adapter->card;
-
-       *data = ioread8(card->pci_mmap1 + reg);
-
-       return 0;
-}
-
 /*
  * This function adds delay loop to ensure FW is awake before proceeding.
  */
@@ -450,7 +460,6 @@ static void mwifiex_delay_for_sleep_cookie(struct mwifiex_adapter *adapter,
 /* This function wakes up the card by reading fw_status register. */
 static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
 {
-       u32 fw_status;
        struct pcie_service_card *card = adapter->card;
        const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
@@ -460,10 +469,10 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
        if (reg->sleep_cookie)
                mwifiex_pcie_dev_wakeup_delay(adapter);
 
-       /* Reading fw_status register will wakeup device */
-       if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status)) {
+       /* Accessing fw_status register will wakeup device */
+       if (mwifiex_write_reg(adapter, reg->fw_status, FIRMWARE_READY_PCIE)) {
                mwifiex_dbg(adapter, ERROR,
-                           "Reading fw_status register failed\n");
+                           "Writing fw_status register failed\n");
                return -1;
        }
 
@@ -2715,31 +2724,35 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
 
 static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter)
 {
-       mwifiex_drv_info_dump(adapter);
+       int drv_info_size;
+       void *drv_info;
+
+       drv_info_size = mwifiex_drv_info_dump(adapter, &drv_info);
        mwifiex_pcie_fw_dump(adapter);
-       mwifiex_upload_device_dump(adapter);
+       mwifiex_upload_device_dump(adapter, drv_info, drv_info_size);
 }
 
-static unsigned long iface_work_flags;
-static struct mwifiex_adapter *save_adapter;
 static void mwifiex_pcie_work(struct work_struct *work)
 {
+       struct pcie_service_card *card =
+               container_of(work, struct pcie_service_card, work);
+
        if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
-                              &iface_work_flags))
-               mwifiex_pcie_device_dump_work(save_adapter);
+                              &card->work_flags))
+               mwifiex_pcie_device_dump_work(card->adapter);
 }
 
-static DECLARE_WORK(pcie_work, mwifiex_pcie_work);
 /* This function dumps FW information */
 static void mwifiex_pcie_device_dump(struct mwifiex_adapter *adapter)
 {
-       save_adapter = adapter;
-       if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags))
+       struct pcie_service_card *card = adapter->card;
+
+       if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags))
                return;
 
-       set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags);
+       set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
 
-       schedule_work(&pcie_work);
+       schedule_work(&card->work);
 }
 
 /*
@@ -2752,7 +2765,7 @@ static void mwifiex_pcie_device_dump(struct mwifiex_adapter *adapter)
  *      - Allocate command response ring buffer
  *      - Allocate sleep cookie buffer
  */
-static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
+static int mwifiex_init_pcie(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card = adapter->card;
        int ret;
@@ -2861,13 +2874,16 @@ err_enable_dev:
  *      - Command response ring buffer
  *      - Sleep cookie buffer
  */
-static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
+static void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card = adapter->card;
        struct pci_dev *pdev = card->dev;
        const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+       int ret;
+       u32 fw_status;
 
-       if (user_rmmod) {
+       ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
+       if (fw_status == FIRMWARE_READY_PCIE) {
                mwifiex_dbg(adapter, INFO,
                            "Clearing driver ready signature\n");
                if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
@@ -3058,7 +3074,7 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
  *      - Allocate event BD ring buffers
  *      - Allocate command response ring buffer
  *      - Allocate sleep cookie buffer
- * Part of mwifiex_pcie_init(), not reset the PCIE registers
+ * Part of mwifiex_init_pcie(), not reset the PCIE registers
  */
 static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter)
 {
@@ -3067,6 +3083,17 @@ static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter)
        struct pci_dev *pdev = card->dev;
        const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
+       /* Bluetooth is not on pcie interface. Download Wifi only firmware
+        * during pcie FLR, so that bluetooth part of firmware which is
+        * already running doesn't get affected.
+        */
+       strcpy(adapter->fw_name, PCIE8997_DEFAULT_WIFIFW_NAME);
+
+       /* tx_buf_size might be changed to 3584 by firmware during
+        * data transfer, we should reset it to default size.
+        */
+       adapter->tx_buf_size = card->pcie.tx_buf_size;
+
        card->cmdrsp_buf = NULL;
        ret = mwifiex_pcie_create_txbd_ring(adapter);
        if (ret) {
@@ -3128,7 +3155,6 @@ static void mwifiex_pcie_down_dev(struct mwifiex_adapter *adapter)
                mwifiex_dbg(adapter, ERROR, "Failed to write driver not-ready signature\n");
 
        adapter->seq_num = 0;
-       adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
 
        if (reg->sleep_cookie)
                mwifiex_pcie_delete_sleep_cookie_buf(adapter);
@@ -3141,8 +3167,8 @@ static void mwifiex_pcie_down_dev(struct mwifiex_adapter *adapter)
 }
 
 static struct mwifiex_if_ops pcie_ops = {
-       .init_if =                      mwifiex_pcie_init,
-       .cleanup_if =                   mwifiex_pcie_cleanup,
+       .init_if =                      mwifiex_init_pcie,
+       .cleanup_if =                   mwifiex_cleanup_pcie,
        .check_fw_status =              mwifiex_check_fw_status,
        .check_winner_status =          mwifiex_check_winner_status,
        .prog_fw =                      mwifiex_prog_fw_w_helper,
@@ -3168,49 +3194,7 @@ static struct mwifiex_if_ops pcie_ops = {
        .up_dev =                       mwifiex_pcie_up_dev,
 };
 
-/*
- * This function initializes the PCIE driver module.
- *
- * This registers the device with PCIE bus.
- */
-static int mwifiex_pcie_init_module(void)
-{
-       int ret;
-
-       pr_debug("Marvell PCIe Driver\n");
-
-       /* Clear the flag in case user removes the card. */
-       user_rmmod = 0;
-
-       ret = pci_register_driver(&mwifiex_pcie);
-       if (ret)
-               pr_err("Driver register failed!\n");
-       else
-               pr_debug("info: Driver registered successfully!\n");
-
-       return ret;
-}
-
-/*
- * This function cleans up the PCIE driver.
- *
- * The following major steps are followed for cleanup -
- *      - Resume the device if its suspended
- *      - Disconnect the device if connected
- *      - Shutdown the firmware
- *      - Unregister the device from PCIE bus.
- */
-static void mwifiex_pcie_cleanup_module(void)
-{
-       /* Set the flag as user is removing this module. */
-       user_rmmod = 1;
-
-       cancel_work_sync(&pcie_work);
-       pci_unregister_driver(&mwifiex_pcie);
-}
-
-module_init(mwifiex_pcie_init_module);
-module_exit(mwifiex_pcie_cleanup_module);
+module_pci_driver(mwifiex_pcie);
 
 MODULE_AUTHOR("Marvell International Ltd.");
 MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION);