ath10k: fix dma_mapping_error() handling
[deliverable/linux.git] / drivers / net / wireless / ath / ath10k / pci.c
index ea656e011a96e195d4513e41a482a40bab07df42..826220f795c7082e1d64588e6492e8afd799e374 100644 (file)
@@ -59,10 +59,12 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
 
 #define QCA988X_2_0_DEVICE_ID  (0x003c)
 #define QCA6174_2_1_DEVICE_ID  (0x003e)
+#define QCA99X0_2_0_DEVICE_ID  (0x0040)
 
 static const struct pci_device_id ath10k_pci_id_table[] = {
        { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */
        { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */
+       { PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */
        {0}
 };
 
@@ -77,11 +79,12 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
        { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV },
        { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV },
        { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV },
+       { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV },
 };
 
 static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
 static int ath10k_pci_cold_reset(struct ath10k *ar);
-static int ath10k_pci_warm_reset(struct ath10k *ar);
+static int ath10k_pci_safe_chip_reset(struct ath10k *ar);
 static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
 static int ath10k_pci_init_irq(struct ath10k *ar);
 static int ath10k_pci_deinit_irq(struct ath10k *ar);
@@ -90,6 +93,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar);
 static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
                               struct ath10k_ce_pipe *rx_pipe,
                               struct bmi_xfer *xfer);
+static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar);
 
 static const struct ce_attr host_ce_config_wlan[] = {
        /* CE0: host->target HTC control and raw streams */
@@ -155,6 +159,38 @@ static const struct ce_attr host_ce_config_wlan[] = {
                .src_sz_max = DIAG_TRANSFER_LIMIT,
                .dest_nentries = 2,
        },
+
+       /* CE8: target->host pktlog */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 2048,
+               .dest_nentries = 128,
+       },
+
+       /* CE9 target autonomous qcache memcpy */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 0,
+               .dest_nentries = 0,
+       },
+
+       /* CE10: target autonomous hif memcpy */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 0,
+               .dest_nentries = 0,
+       },
+
+       /* CE11: target autonomous hif memcpy */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 0,
+               .dest_nentries = 0,
+       },
 };
 
 /* Target firmware's Copy Engine configuration. */
@@ -232,6 +268,38 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {
        },
 
        /* CE7 used only by Host */
+       {
+               .pipenum = __cpu_to_le32(7),
+               .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+               .nentries = __cpu_to_le32(0),
+               .nbytes_max = __cpu_to_le32(0),
+               .flags = __cpu_to_le32(0),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE8 target->host packtlog */
+       {
+               .pipenum = __cpu_to_le32(8),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),
+               .nentries = __cpu_to_le32(64),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE9 target autonomous qcache memcpy */
+       {
+               .pipenum = __cpu_to_le32(9),
+               .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* It not necessary to send target wlan configuration for CE10 & CE11
+        * as these CEs are not actively used in target.
+        */
 };
 
 /*
@@ -479,6 +547,12 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int ret;
 
+       if (unlikely(offset + sizeof(value) > ar_pci->mem_len)) {
+               ath10k_warn(ar, "refusing to write mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n",
+                           offset, offset + sizeof(value), ar_pci->mem_len);
+               return;
+       }
+
        ret = ath10k_pci_wake(ar);
        if (ret) {
                ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n",
@@ -496,6 +570,12 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
        u32 val;
        int ret;
 
+       if (unlikely(offset + sizeof(val) > ar_pci->mem_len)) {
+               ath10k_warn(ar, "refusing to read mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n",
+                           offset, offset + sizeof(val), ar_pci->mem_len);
+               return 0;
+       }
+
        ret = ath10k_pci_wake(ar);
        if (ret) {
                ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n",
@@ -678,6 +758,26 @@ static void ath10k_pci_rx_replenish_retry(unsigned long ptr)
        ath10k_pci_rx_post(ar);
 }
 
+static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
+{
+       u32 val = 0;
+
+       switch (ar->hw_rev) {
+       case ATH10K_HW_QCA988X:
+       case ATH10K_HW_QCA6174:
+               val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+                                         CORE_CTRL_ADDRESS) &
+                      0x7ff) << 21;
+               break;
+       case ATH10K_HW_QCA99X0:
+               val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS);
+               break;
+       }
+
+       val |= 0x100000 | (addr & 0xfffff);
+       return val;
+}
+
 /*
  * Diagnostic read/write access is provided for startup/config/debug usage.
  * Caller must guarantee proper alignment, when applicable, and single user
@@ -740,8 +840,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
                 * convert it from Target CPU virtual address space
                 * to CE address space
                 */
-               address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem,
-                                                    address);
+               address = ath10k_pci_targ_cpu_to_ce_addr(ar, address);
 
                ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0,
                                            0);
@@ -899,7 +998,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
         * to
         *    CE address space
         */
-       address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address);
+       address = ath10k_pci_targ_cpu_to_ce_addr(ar, address);
 
        remaining_bytes = orig_nbytes;
        ce_data = ce_data_base;
@@ -1331,20 +1430,42 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
 {
        u32 val;
 
-       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
-       val &= ~CORE_CTRL_PCIE_REG_31_MASK;
-
-       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
+       switch (ar->hw_rev) {
+       case ATH10K_HW_QCA988X:
+       case ATH10K_HW_QCA6174:
+               val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+                                       CORE_CTRL_ADDRESS);
+               val &= ~CORE_CTRL_PCIE_REG_31_MASK;
+               ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+                                  CORE_CTRL_ADDRESS, val);
+               break;
+       case ATH10K_HW_QCA99X0:
+               /* TODO: Find appropriate register configuration for QCA99X0
+                *  to mask irq/MSI.
+                */
+                break;
+       }
 }
 
 static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
 {
        u32 val;
 
-       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
-       val |= CORE_CTRL_PCIE_REG_31_MASK;
-
-       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
+       switch (ar->hw_rev) {
+       case ATH10K_HW_QCA988X:
+       case ATH10K_HW_QCA6174:
+               val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+                                       CORE_CTRL_ADDRESS);
+               val |= CORE_CTRL_PCIE_REG_31_MASK;
+               ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+                                  CORE_CTRL_ADDRESS, val);
+               break;
+       case ATH10K_HW_QCA99X0:
+               /* TODO: Find appropriate register configuration for QCA99X0
+                *  to unmask irq/MSI.
+                */
+               break;
+       }
 }
 
 static void ath10k_pci_irq_disable(struct ath10k *ar)
@@ -1506,7 +1627,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
         * masked. To prevent the device from asserting the interrupt reset it
         * before proceeding with cleanup.
         */
-       ath10k_pci_warm_reset(ar);
+       ath10k_pci_safe_chip_reset(ar);
 
        ath10k_pci_irq_disable(ar);
        ath10k_pci_irq_sync(ar);
@@ -1546,8 +1667,10 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
 
        req_paddr = dma_map_single(ar->dev, treq, req_len, DMA_TO_DEVICE);
        ret = dma_mapping_error(ar->dev, req_paddr);
-       if (ret)
+       if (ret) {
+               ret = -EIO;
                goto err_dma;
+       }
 
        if (resp && resp_len) {
                tresp = kzalloc(*resp_len, GFP_KERNEL);
@@ -1559,8 +1682,10 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
                resp_paddr = dma_map_single(ar->dev, tresp, *resp_len,
                                            DMA_FROM_DEVICE);
                ret = dma_mapping_error(ar->dev, resp_paddr);
-               if (ret)
+               if (ret) {
+                       ret = EIO;
                        goto err_req;
+               }
 
                xfer.wait_for_resp = true;
                xfer.resp_len = 0;
@@ -1687,6 +1812,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
 
        switch (ar_pci->pdev->device) {
        case QCA988X_2_0_DEVICE_ID:
+       case QCA99X0_2_0_DEVICE_ID:
                return 1;
        case QCA6174_2_1_DEVICE_ID:
                switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) {
@@ -1757,7 +1883,8 @@ static int ath10k_pci_init_config(struct ath10k *ar)
 
        ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr,
                                        target_ce_config_wlan,
-                                       sizeof(target_ce_config_wlan));
+                                       sizeof(struct ce_pipe_config) *
+                                       NUM_TARGET_CE_CONFIG_WLAN);
 
        if (ret != 0) {
                ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret);
@@ -1871,7 +1998,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar)
                }
 
                /* Last CE is Diagnostic Window */
-               if (i == CE_COUNT - 1) {
+               if (i == CE_DIAG_PIPE) {
                        ar_pci->ce_diag = pipe->ce_hdl;
                        continue;
                }
@@ -2016,6 +2143,18 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
        return 0;
 }
 
+static int ath10k_pci_safe_chip_reset(struct ath10k *ar)
+{
+       if (QCA_REV_988X(ar) || QCA_REV_6174(ar)) {
+               return ath10k_pci_warm_reset(ar);
+       } else if (QCA_REV_99X0(ar)) {
+               ath10k_pci_irq_disable(ar);
+               return ath10k_pci_qca99x0_chip_reset(ar);
+       } else {
+               return -ENOTSUPP;
+       }
+}
+
 static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar)
 {
        int i, ret;
@@ -2122,12 +2261,38 @@ static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar)
        return 0;
 }
 
+static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar)
+{
+       int ret;
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset\n");
+
+       ret = ath10k_pci_cold_reset(ar);
+       if (ret) {
+               ath10k_warn(ar, "failed to cold reset: %d\n", ret);
+               return ret;
+       }
+
+       ret = ath10k_pci_wait_for_target_init(ar);
+       if (ret) {
+               ath10k_warn(ar, "failed to wait for target after cold reset: %d\n",
+                           ret);
+               return ret;
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset complete (cold)\n");
+
+       return 0;
+}
+
 static int ath10k_pci_chip_reset(struct ath10k *ar)
 {
        if (QCA_REV_988X(ar))
                return ath10k_pci_qca988x_chip_reset(ar);
        else if (QCA_REV_6174(ar))
                return ath10k_pci_qca6174_chip_reset(ar);
+       else if (QCA_REV_99X0(ar))
+               return ath10k_pci_qca99x0_chip_reset(ar);
        else
                return -ENOTSUPP;
 }
@@ -2602,7 +2767,6 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 
 static int ath10k_pci_cold_reset(struct ath10k *ar)
 {
-       int i;
        u32 val;
 
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
@@ -2618,23 +2782,18 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)
        val |= 1;
        ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
 
-       for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
-               if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
-                                         RTC_STATE_COLD_RESET_MASK)
-                       break;
-               msleep(1);
-       }
+       /* After writing into SOC_GLOBAL_RESET to put device into
+        * reset and pulling out of reset pcie may not be stable
+        * for any immediate pcie register access and cause bus error,
+        * add delay before any pcie access request to fix this issue.
+        */
+       msleep(20);
 
        /* Pull Target, including PCIe, out of RESET. */
        val &= ~1;
        ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
 
-       for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
-               if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
-                                           RTC_STATE_COLD_RESET_MASK))
-                       break;
-               msleep(1);
-       }
+       msleep(20);
 
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n");
 
@@ -2679,6 +2838,7 @@ static int ath10k_pci_claim(struct ath10k *ar)
        pci_set_master(pdev);
 
        /* Arrange for access to Target SoC registers. */
+       ar_pci->mem_len = pci_resource_len(pdev, BAR_NUM);
        ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);
        if (!ar_pci->mem) {
                ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM);
@@ -2745,6 +2905,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        case QCA6174_2_1_DEVICE_ID:
                hw_rev = ATH10K_HW_QCA6174;
                break;
+       case QCA99X0_2_0_DEVICE_ID:
+               hw_rev = ATH10K_HW_QCA99X0;
+               break;
        default:
                WARN_ON(1);
                return -ENOTSUPP;
This page took 0.030798 seconds and 5 git commands to generate.