From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
kernel/drivers/net/wireless/ath/ath10k/pci.c | 353 ++++++++++++++++++++++++++++++++++------------------------
1 files changed, 209 insertions(+), 144 deletions(-)
diff --git a/kernel/drivers/net/wireless/ath/ath10k/pci.c b/kernel/drivers/net/wireless/ath/ath10k/pci.c
index caece83..2c8f04b 100644
--- a/kernel/drivers/net/wireless/ath/ath10k/pci.c
+++ b/kernel/drivers/net/wireless/ath/ath10k/pci.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/pci.h>
@@ -127,7 +116,7 @@
static void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_pci_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);
-static struct ce_attr host_ce_config_wlan[] = {
+static const struct ce_attr pci_host_ce_config_wlan[] = {
/* CE0: host->target HTC control and raw streams */
{
.flags = CE_ATTR_FLAGS,
@@ -192,7 +181,7 @@
/* CE7: ce_diag, the Diagnostic Window */
{
- .flags = CE_ATTR_FLAGS,
+ .flags = CE_ATTR_FLAGS | CE_ATTR_POLL,
.src_nentries = 2,
.src_sz_max = DIAG_TRANSFER_LIMIT,
.dest_nentries = 2,
@@ -233,7 +222,7 @@
};
/* Target firmware's Copy Engine configuration. */
-static struct ce_pipe_config target_ce_config_wlan[] = {
+static const struct ce_pipe_config pci_target_ce_config_wlan[] = {
/* CE0: host->target HTC control and raw streams */
{
.pipenum = __cpu_to_le32(0),
@@ -346,7 +335,7 @@
* This table is derived from the CE_PCI TABLE, above.
* It is passed to the Target at startup for use by firmware.
*/
-static struct service_to_pipe target_service_to_ce_map_wlan[] = {
+static const struct ce_service_to_pipe pci_target_service_to_ce_map_wlan[] = {
{
__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
@@ -870,6 +859,21 @@
return val;
}
+/* Refactor from ath10k_pci_qca988x_targ_cpu_to_ce_addr.
+ * Support to access target space below 1M for qca6174 and qca9377.
+ * If target space is below 1M, the bit[20] of converted CE addr is 0.
+ * Otherwise bit[20] of converted CE addr is 1.
+ */
+static u32 ath10k_pci_qca6174_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
+{
+ u32 val = 0, region = addr & 0xfffff;
+
+ val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS)
+ & 0x7ff) << 21;
+ val |= ((addr >= 0x100000) ? 0x100000 : 0) | region;
+ return val;
+}
+
static u32 ath10k_pci_qca99x0_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
{
u32 val = 0, region = addr & 0xfffff;
@@ -898,7 +902,6 @@
int nbytes)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_ce *ce = ath10k_ce_priv(ar);
int ret = 0;
u32 *buf;
unsigned int completed_nbytes, alloc_nbytes, remaining_bytes;
@@ -906,11 +909,10 @@
/* Host buffer address in CE space */
u32 ce_data;
dma_addr_t ce_data_base = 0;
- void *data_buf = NULL;
+ void *data_buf;
int i;
- spin_lock_bh(&ce->ce_lock);
-
+ mutex_lock(&ar_pci->ce_diag_mutex);
ce_diag = ar_pci->ce_diag;
/*
@@ -921,15 +923,21 @@
*/
alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT);
- data_buf = (unsigned char *)dma_zalloc_coherent(ar->dev,
- alloc_nbytes,
- &ce_data_base,
- GFP_ATOMIC);
-
+ data_buf = dma_alloc_coherent(ar->dev, alloc_nbytes, &ce_data_base,
+ GFP_ATOMIC);
if (!data_buf) {
ret = -ENOMEM;
goto done;
}
+
+ /* The address supplied by the caller is in the
+ * Target CPU virtual address space.
+ *
+ * In order to use this address with the diagnostic CE,
+ * convert it from Target CPU virtual address space
+ * to CE address space
+ */
+ address = ath10k_pci_targ_cpu_to_ce_addr(ar, address);
remaining_bytes = nbytes;
ce_data = ce_data_base;
@@ -937,44 +945,33 @@
nbytes = min_t(unsigned int, remaining_bytes,
DIAG_TRANSFER_LIMIT);
- ret = ce_diag->ops->ce_rx_post_buf(ce_diag, &ce_data, ce_data);
+ ret = ath10k_ce_rx_post_buf(ce_diag, &ce_data, ce_data);
if (ret != 0)
goto done;
/* Request CE to send from Target(!) address to Host buffer */
- /*
- * The address supplied by the caller is in the
- * Target CPU virtual address space.
- *
- * In order to use this address with the diagnostic CE,
- * convert it from Target CPU virtual address space
- * to CE address space
- */
- address = ath10k_pci_targ_cpu_to_ce_addr(ar, address);
-
- ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0,
- 0);
+ ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0, 0);
if (ret)
goto done;
i = 0;
- while (ath10k_ce_completed_send_next_nolock(ce_diag,
- NULL) != 0) {
- mdelay(1);
- if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+ while (ath10k_ce_completed_send_next(ce_diag, NULL) != 0) {
+ udelay(DIAG_ACCESS_CE_WAIT_US);
+ i += DIAG_ACCESS_CE_WAIT_US;
+
+ if (i > DIAG_ACCESS_CE_TIMEOUT_US) {
ret = -EBUSY;
goto done;
}
}
i = 0;
- while (ath10k_ce_completed_recv_next_nolock(ce_diag,
- (void **)&buf,
- &completed_nbytes)
- != 0) {
- mdelay(1);
+ while (ath10k_ce_completed_recv_next(ce_diag, (void **)&buf,
+ &completed_nbytes) != 0) {
+ udelay(DIAG_ACCESS_CE_WAIT_US);
+ i += DIAG_ACCESS_CE_WAIT_US;
- if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+ if (i > DIAG_ACCESS_CE_TIMEOUT_US) {
ret = -EBUSY;
goto done;
}
@@ -1003,7 +1000,7 @@
dma_free_coherent(ar->dev, alloc_nbytes, data_buf,
ce_data_base);
- spin_unlock_bh(&ce->ce_lock);
+ mutex_unlock(&ar_pci->ce_diag_mutex);
return ret;
}
@@ -1051,17 +1048,15 @@
const void *data, int nbytes)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- struct ath10k_ce *ce = ath10k_ce_priv(ar);
int ret = 0;
u32 *buf;
unsigned int completed_nbytes, alloc_nbytes, remaining_bytes;
struct ath10k_ce_pipe *ce_diag;
- void *data_buf = NULL;
+ void *data_buf;
dma_addr_t ce_data_base = 0;
int i;
- spin_lock_bh(&ce->ce_lock);
-
+ mutex_lock(&ar_pci->ce_diag_mutex);
ce_diag = ar_pci->ce_diag;
/*
@@ -1072,10 +1067,8 @@
*/
alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT);
- data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
- alloc_nbytes,
- &ce_data_base,
- GFP_ATOMIC);
+ data_buf = dma_alloc_coherent(ar->dev, alloc_nbytes, &ce_data_base,
+ GFP_ATOMIC);
if (!data_buf) {
ret = -ENOMEM;
goto done;
@@ -1102,7 +1095,7 @@
memcpy(data_buf, data, nbytes);
/* Set up to receive directly into Target(!) address */
- ret = ce_diag->ops->ce_rx_post_buf(ce_diag, &address, address);
+ ret = ath10k_ce_rx_post_buf(ce_diag, &address, address);
if (ret != 0)
goto done;
@@ -1110,30 +1103,28 @@
* Request CE to send caller-supplied data that
* was copied to bounce buffer to Target(!) address.
*/
- ret = ath10k_ce_send_nolock(ce_diag, NULL, ce_data_base,
- nbytes, 0, 0);
+ ret = ath10k_ce_send(ce_diag, NULL, ce_data_base, nbytes, 0, 0);
if (ret != 0)
goto done;
i = 0;
- while (ath10k_ce_completed_send_next_nolock(ce_diag,
- NULL) != 0) {
- mdelay(1);
+ while (ath10k_ce_completed_send_next(ce_diag, NULL) != 0) {
+ udelay(DIAG_ACCESS_CE_WAIT_US);
+ i += DIAG_ACCESS_CE_WAIT_US;
- if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+ if (i > DIAG_ACCESS_CE_TIMEOUT_US) {
ret = -EBUSY;
goto done;
}
}
i = 0;
- while (ath10k_ce_completed_recv_next_nolock(ce_diag,
- (void **)&buf,
- &completed_nbytes)
- != 0) {
- mdelay(1);
+ while (ath10k_ce_completed_recv_next(ce_diag, (void **)&buf,
+ &completed_nbytes) != 0) {
+ udelay(DIAG_ACCESS_CE_WAIT_US);
+ i += DIAG_ACCESS_CE_WAIT_US;
- if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
+ if (i > DIAG_ACCESS_CE_TIMEOUT_US) {
ret = -EBUSY;
goto done;
}
@@ -1164,7 +1155,7 @@
ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n",
address, ret);
- spin_unlock_bh(&ce->ce_lock);
+ mutex_unlock(&ar_pci->ce_diag_mutex);
return ret;
}
@@ -1446,7 +1437,7 @@
__le32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
int i, ret;
- lockdep_assert_held(&ar->data_lock);
+ lockdep_assert_held(&ar->dump_mutex);
ret = ath10k_pci_diag_read_hi(ar, ®_dump_values[0],
hi_failure_state,
@@ -1587,7 +1578,7 @@
return 0;
}
-/* if an error happened returns < 0, otherwise the length */
+/* Always returns the length */
static int ath10k_pci_dump_memory_sram(struct ath10k *ar,
const struct ath10k_mem_region *region,
u8 *buf)
@@ -1672,7 +1663,7 @@
int ret, i;
u8 *buf;
- lockdep_assert_held(&ar->data_lock);
+ lockdep_assert_held(&ar->dump_mutex);
if (!crash_data)
return;
@@ -1754,14 +1745,19 @@
}
}
-static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+static void ath10k_pci_fw_dump_work(struct work_struct *work)
{
+ struct ath10k_pci *ar_pci = container_of(work, struct ath10k_pci,
+ dump_work);
struct ath10k_fw_crash_data *crash_data;
+ struct ath10k *ar = ar_pci->ar;
char guid[UUID_STRING_LEN + 1];
- spin_lock_bh(&ar->data_lock);
+ mutex_lock(&ar->dump_mutex);
+ spin_lock_bh(&ar->data_lock);
ar->stats.fw_crash_counter++;
+ spin_unlock_bh(&ar->data_lock);
crash_data = ath10k_coredump_new(ar);
@@ -1776,14 +1772,23 @@
ath10k_ce_dump_registers(ar, crash_data);
ath10k_pci_dump_memory(ar, crash_data);
- spin_unlock_bh(&ar->data_lock);
+ mutex_unlock(&ar->dump_mutex);
queue_work(ar->workqueue, &ar->restart_work);
+}
+
+static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+ queue_work(ar->workqueue, &ar_pci->dump_work);
}
void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
int force)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n");
if (!force) {
@@ -1801,7 +1806,7 @@
* If at least 50% of the total resources are still available,
* don't bother checking again yet.
*/
- if (resources > (host_ce_config_wlan[pipe].src_nentries >> 1))
+ if (resources > (ar_pci->attr[pipe].src_nentries >> 1))
return;
}
ath10k_ce_per_engine_service(ar, pipe);
@@ -1817,14 +1822,15 @@
int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
u8 *ul_pipe, u8 *dl_pipe)
{
- const struct service_to_pipe *entry;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+ const struct ce_service_to_pipe *entry;
bool ul_set = false, dl_set = false;
int i;
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n");
- for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
- entry = &target_service_to_ce_map_wlan[i];
+ for (i = 0; i < ARRAY_SIZE(pci_target_service_to_ce_map_wlan); i++) {
+ entry = &ar_pci->serv_to_pipe[i];
if (__le32_to_cpu(entry->service_id) != service_id)
continue;
@@ -1853,7 +1859,7 @@
}
}
- if (WARN_ON(!ul_set || !dl_set))
+ if (!ul_set || !dl_set)
return -ENOENT;
return 0;
@@ -1957,8 +1963,9 @@
ath10k_pci_irq_enable(ar);
ath10k_pci_rx_post(ar);
- pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
- ar_pci->link_ctl);
+ pcie_capability_clear_and_set_word(ar_pci->pdev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPMC,
+ ar_pci->link_ctl & PCI_EXP_LNKCTL_ASPMC);
return 0;
}
@@ -2071,6 +2078,7 @@
ath10k_pci_irq_sync(ar);
napi_synchronize(&ar->napi);
napi_disable(&ar->napi);
+ cancel_work_sync(&ar_pci->dump_work);
/* Most likely the device has HTT Rx ring configured. The only way to
* prevent the device from accessing (and possible corrupting) host
@@ -2177,7 +2185,7 @@
if (ret == 0 && resp_len) {
*resp_len = min(*resp_len, xfer.resp_len);
- memcpy(resp, tresp, xfer.resp_len);
+ memcpy(resp, tresp, *resp_len);
}
err_dma:
kfree(treq);
@@ -2281,7 +2289,7 @@
return 1;
case QCA6164_2_1_DEVICE_ID:
case QCA6174_2_1_DEVICE_ID:
- switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) {
+ switch (MS(ar->bus_param.chip_id, SOC_CHIP_ID_REV)) {
case QCA6174_HW_1_0_CHIP_ID_REV:
case QCA6174_HW_1_1_CHIP_ID_REV:
case QCA6174_HW_2_1_CHIP_ID_REV:
@@ -2312,6 +2320,7 @@
int ath10k_pci_init_config(struct ath10k *ar)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
u32 interconnect_targ_addr;
u32 pcie_state_targ_addr = 0;
u32 pipe_cfg_targ_addr = 0;
@@ -2357,7 +2366,7 @@
}
ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr,
- target_ce_config_wlan,
+ ar_pci->pipe_config,
sizeof(struct ce_pipe_config) *
NUM_TARGET_CE_CONFIG_WLAN);
@@ -2382,8 +2391,8 @@
}
ret = ath10k_pci_diag_write_mem(ar, svc_to_pipe_map,
- target_service_to_ce_map_wlan,
- sizeof(target_service_to_ce_map_wlan));
+ ar_pci->serv_to_pipe,
+ sizeof(pci_target_service_to_ce_map_wlan));
if (ret != 0) {
ath10k_err(ar, "Failed to write svc/pipe map: %d\n", ret);
return ret;
@@ -2455,23 +2464,24 @@
{
struct ce_attr *attr;
struct ce_pipe_config *config;
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
/* For QCA6174 we're overriding the Copy Engine 5 configuration,
* since it is currently used for other feature.
*/
/* Override Host's Copy Engine 5 configuration */
- attr = &host_ce_config_wlan[5];
+ attr = &ar_pci->attr[5];
attr->src_sz_max = 0;
attr->dest_nentries = 0;
/* Override Target firmware's Copy Engine configuration */
- config = &target_ce_config_wlan[5];
+ config = &ar_pci->pipe_config[5];
config->pipedir = __cpu_to_le32(PIPEDIR_OUT);
config->nbytes_max = __cpu_to_le32(2048);
/* Map from service/endpoint to Copy Engine */
- target_service_to_ce_map_wlan[15].pipenum = __cpu_to_le32(1);
+ ar_pci->serv_to_pipe[15].pipenum = __cpu_to_le32(1);
}
int ath10k_pci_alloc_pipes(struct ath10k *ar)
@@ -2487,7 +2497,7 @@
pipe->pipe_num = i;
pipe->hif_ce_state = ar;
- ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
+ ret = ath10k_ce_alloc_pipe(ar, i, &ar_pci->attr[i]);
if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
i, ret);
@@ -2500,7 +2510,7 @@
continue;
}
- pipe->buf_sz = (size_t)(host_ce_config_wlan[i].src_sz_max);
+ pipe->buf_sz = (size_t)(ar_pci->attr[i].src_sz_max);
}
return 0;
@@ -2516,10 +2526,11 @@
int ath10k_pci_init_pipes(struct ath10k *ar)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int i, ret;
for (i = 0; i < CE_COUNT; i++) {
- ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);
+ ret = ath10k_ce_init_pipe(ar, i, &ar_pci->attr[i]);
if (ret) {
ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
i, ret);
@@ -2579,35 +2590,31 @@
ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0);
- val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
- SOC_RESET_CONTROL_ADDRESS);
- ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
- val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK);
+ val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
+ ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
+ val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK);
}
static void ath10k_pci_warm_reset_ce(struct ath10k *ar)
{
u32 val;
- val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
- SOC_RESET_CONTROL_ADDRESS);
+ val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
- ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
- val | SOC_RESET_CONTROL_CE_RST_MASK);
+ ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
+ val | SOC_RESET_CONTROL_CE_RST_MASK);
msleep(10);
- ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
- val & ~SOC_RESET_CONTROL_CE_RST_MASK);
+ ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
+ val & ~SOC_RESET_CONTROL_CE_RST_MASK);
}
static void ath10k_pci_warm_reset_clear_lf(struct ath10k *ar)
{
u32 val;
- val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
- SOC_LF_TIMER_CONTROL0_ADDRESS);
- ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS +
- SOC_LF_TIMER_CONTROL0_ADDRESS,
- val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK);
+ val = ath10k_pci_soc_read32(ar, SOC_LF_TIMER_CONTROL0_ADDRESS);
+ ath10k_pci_soc_write32(ar, SOC_LF_TIMER_CONTROL0_ADDRESS,
+ val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK);
}
static int ath10k_pci_warm_reset(struct ath10k *ar)
@@ -2804,7 +2811,8 @@
return ar_pci->pci_hard_reset(ar);
}
-static int ath10k_pci_hif_power_up(struct ath10k *ar)
+static int ath10k_pci_hif_power_up(struct ath10k *ar,
+ enum ath10k_firmware_mode fw_mode)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret;
@@ -2813,8 +2821,8 @@
pcie_capability_read_word(ar_pci->pdev, PCI_EXP_LNKCTL,
&ar_pci->link_ctl);
- pcie_capability_write_word(ar_pci->pdev, PCI_EXP_LNKCTL,
- ar_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
+ pcie_capability_clear_word(ar_pci->pdev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPMC);
/*
* Bring the target up cleanly.
@@ -3460,8 +3468,33 @@
spin_lock_init(&ce->ce_lock);
spin_lock_init(&ar_pci->ps_lock);
+ mutex_init(&ar_pci->ce_diag_mutex);
+
+ INIT_WORK(&ar_pci->dump_work, ath10k_pci_fw_dump_work);
timer_setup(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry, 0);
+
+ ar_pci->attr = kmemdup(pci_host_ce_config_wlan,
+ sizeof(pci_host_ce_config_wlan),
+ GFP_KERNEL);
+ if (!ar_pci->attr)
+ return -ENOMEM;
+
+ ar_pci->pipe_config = kmemdup(pci_target_ce_config_wlan,
+ sizeof(pci_target_ce_config_wlan),
+ GFP_KERNEL);
+ if (!ar_pci->pipe_config) {
+ ret = -ENOMEM;
+ goto err_free_attr;
+ }
+
+ ar_pci->serv_to_pipe = kmemdup(pci_target_service_to_ce_map_wlan,
+ sizeof(pci_target_service_to_ce_map_wlan),
+ GFP_KERNEL);
+ if (!ar_pci->serv_to_pipe) {
+ ret = -ENOMEM;
+ goto err_free_pipe_config;
+ }
if (QCA_REV_6174(ar) || QCA_REV_9377(ar))
ath10k_pci_override_ce_config(ar);
@@ -3470,18 +3503,31 @@
if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
ret);
- return ret;
+ goto err_free_serv_to_pipe;
}
return 0;
+
+err_free_serv_to_pipe:
+ kfree(ar_pci->serv_to_pipe);
+err_free_pipe_config:
+ kfree(ar_pci->pipe_config);
+err_free_attr:
+ kfree(ar_pci->attr);
+ return ret;
}
void ath10k_pci_release_resource(struct ath10k *ar)
{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
ath10k_pci_rx_retry_sync(ar);
netif_napi_del(&ar->napi);
ath10k_pci_ce_deinit(ar);
ath10k_pci_free_pipes(ar);
+ kfree(ar_pci->attr);
+ kfree(ar_pci->pipe_config);
+ kfree(ar_pci->serv_to_pipe);
}
static const struct ath10k_bus_ops ath10k_pci_bus_ops = {
@@ -3497,8 +3543,8 @@
struct ath10k *ar;
struct ath10k_pci *ar_pci;
enum ath10k_hw_rev hw_rev;
- u32 chip_id;
- bool pci_ps;
+ struct ath10k_bus_params bus_params = {};
+ bool pci_ps, is_qca988x = false;
int (*pci_soft_reset)(struct ath10k *ar);
int (*pci_hard_reset)(struct ath10k *ar);
u32 (*targ_cpu_to_ce_addr)(struct ath10k *ar, u32 addr);
@@ -3508,6 +3554,7 @@
case QCA988X_2_0_DEVICE_ID:
hw_rev = ATH10K_HW_QCA988X;
pci_ps = false;
+ is_qca988x = true;
pci_soft_reset = ath10k_pci_warm_reset;
pci_hard_reset = ath10k_pci_qca988x_chip_reset;
targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr;
@@ -3525,7 +3572,7 @@
pci_ps = true;
pci_soft_reset = ath10k_pci_warm_reset;
pci_hard_reset = ath10k_pci_qca6174_chip_reset;
- targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr;
+ targ_cpu_to_ce_addr = ath10k_pci_qca6174_targ_cpu_to_ce_addr;
break;
case QCA99X0_2_0_DEVICE_ID:
hw_rev = ATH10K_HW_QCA99X0;
@@ -3551,9 +3598,9 @@
case QCA9377_1_0_DEVICE_ID:
hw_rev = ATH10K_HW_QCA9377;
pci_ps = true;
- pci_soft_reset = NULL;
+ pci_soft_reset = ath10k_pci_warm_reset;
pci_hard_reset = ath10k_pci_qca6174_chip_reset;
- targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr;
+ targ_cpu_to_ce_addr = ath10k_pci_qca6174_targ_cpu_to_ce_addr;
break;
default:
WARN_ON(1);
@@ -3627,25 +3674,42 @@
goto err_deinit_irq;
}
+ bus_params.dev_type = ATH10K_DEV_TYPE_LL;
+ bus_params.link_can_suspend = true;
+ /* Read CHIP_ID before reset to catch QCA9880-AR1A v1 devices that
+ * fall off the bus during chip_reset. These chips have the same pci
+ * device id as the QCA9880 BR4A or 2R4E. So that's why the check.
+ */
+ if (is_qca988x) {
+ bus_params.chip_id =
+ ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+ if (bus_params.chip_id != 0xffffffff) {
+ if (!ath10k_pci_chip_is_supported(pdev->device,
+ bus_params.chip_id)) {
+ ret = -ENODEV;
+ goto err_unsupported;
+ }
+ }
+ }
+
ret = ath10k_pci_chip_reset(ar);
if (ret) {
ath10k_err(ar, "failed to reset chip: %d\n", ret);
goto err_free_irq;
}
- chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
- if (chip_id == 0xffffffff) {
- ath10k_err(ar, "failed to get chip id\n");
- goto err_free_irq;
+ bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+ if (bus_params.chip_id == 0xffffffff) {
+ ret = -ENODEV;
+ goto err_unsupported;
}
- if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) {
- ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
- pdev->device, chip_id);
- goto err_free_irq;
+ if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) {
+ ret = -ENODEV;
+ goto err_unsupported;
}
- ret = ath10k_core_register(ar, chip_id);
+ ret = ath10k_core_register(ar, &bus_params);
if (ret) {
ath10k_err(ar, "failed to register driver core: %d\n", ret);
goto err_free_irq;
@@ -3653,12 +3717,15 @@
return 0;
+err_unsupported:
+ ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
+ pdev->device, bus_params.chip_id);
+
err_free_irq:
ath10k_pci_free_irq(ar);
- ath10k_pci_rx_retry_sync(ar);
err_deinit_irq:
- ath10k_pci_deinit_irq(ar);
+ ath10k_pci_release_resource(ar);
err_sleep:
ath10k_pci_sleep_sync(ar);
@@ -3676,16 +3743,10 @@
static void ath10k_pci_remove(struct pci_dev *pdev)
{
struct ath10k *ar = pci_get_drvdata(pdev);
- struct ath10k_pci *ar_pci;
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci remove\n");
if (!ar)
- return;
-
- ar_pci = ath10k_pci_priv(ar);
-
- if (!ar_pci)
return;
ath10k_core_unregister(ar);
@@ -3739,18 +3800,22 @@
static int __init ath10k_pci_init(void)
{
- int ret;
+ int ret1, ret2;
- ret = pci_register_driver(&ath10k_pci_driver);
- if (ret)
+ ret1 = pci_register_driver(&ath10k_pci_driver);
+ if (ret1)
printk(KERN_ERR "failed to register ath10k pci driver: %d\n",
- ret);
+ ret1);
- ret = ath10k_ahb_init();
- if (ret)
- printk(KERN_ERR "ahb init failed: %d\n", ret);
+ ret2 = ath10k_ahb_init();
+ if (ret2)
+ printk(KERN_ERR "ahb init failed: %d\n", ret2);
- return ret;
+ if (ret1 && ret2)
+ return ret1;
+
+ /* registered to at least one bus */
+ return 0;
}
module_init(ath10k_pci_init);
--
Gitblit v1.6.2