summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/ath10k/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/core.c')
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c139
1 files changed, 127 insertions, 12 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index d73ad60b571c..eeb6ff6aa2e1 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -651,6 +651,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
[ATH10K_FW_FEATURE_NON_BMI] = "non-bmi",
[ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL] = "single-chan-info-per-channel",
[ATH10K_FW_FEATURE_PEER_FIXED_RATE] = "peer-fixed-rate",
+ [ATH10K_FW_FEATURE_IRAM_RECOVERY] = "iram-recovery",
};
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
@@ -1349,7 +1350,8 @@ out:
static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
const char *boardname,
- const char *fallback_boardname,
+ const char *fallback_boardname1,
+ const char *fallback_boardname2,
const char *filename)
{
size_t len, magic_len;
@@ -1398,8 +1400,11 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
ret = ath10k_core_search_bd(ar, boardname, data, len);
/* if we didn't find it and have a fallback name, try that */
- if (ret == -ENOENT && fallback_boardname)
- ret = ath10k_core_search_bd(ar, fallback_boardname, data, len);
+ if (ret == -ENOENT && fallback_boardname1)
+ ret = ath10k_core_search_bd(ar, fallback_boardname1, data, len);
+
+ if (ret == -ENOENT && fallback_boardname2)
+ ret = ath10k_core_search_bd(ar, fallback_boardname2, data, len);
if (ret == -ENOENT) {
ath10k_err(ar,
@@ -1419,7 +1424,8 @@ err:
}
static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
- size_t name_len, bool with_variant)
+ size_t name_len, bool with_variant,
+ bool with_chip_id)
{
/* strlen(',variant=') + strlen(ar->id.bdf_ext) */
char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 };
@@ -1438,7 +1444,7 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
}
if (ar->id.qmi_ids_valid) {
- if (with_variant && ar->id.bdf_ext[0] != '\0')
+ if (with_chip_id)
scnprintf(name, name_len,
"bus=%s,qmi-board-id=%x,qmi-chip-id=%x%s",
ath10k_bus_str(ar->hif.bus),
@@ -1482,21 +1488,36 @@ static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name,
int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)
{
- char boardname[100], fallback_boardname[100];
+ char boardname[100], fallback_boardname1[100], fallback_boardname2[100];
int ret;
if (bd_ie_type == ATH10K_BD_IE_BOARD) {
+ /* With variant and chip id */
ret = ath10k_core_create_board_name(ar, boardname,
- sizeof(boardname), true);
+ sizeof(boardname), true,
+ true);
if (ret) {
ath10k_err(ar, "failed to create board name: %d", ret);
return ret;
}
- ret = ath10k_core_create_board_name(ar, fallback_boardname,
- sizeof(boardname), false);
+ /* Without variant and only chip-id */
+ ret = ath10k_core_create_board_name(ar, fallback_boardname1,
+ sizeof(boardname), false,
+ true);
+ if (ret) {
+ ath10k_err(ar, "failed to create 1st fallback board name: %d",
+ ret);
+ return ret;
+ }
+
+ /* Without variant and without chip-id */
+ ret = ath10k_core_create_board_name(ar, fallback_boardname2,
+ sizeof(boardname), false,
+ false);
if (ret) {
- ath10k_err(ar, "failed to create fallback board name: %d", ret);
+ ath10k_err(ar, "failed to create 2nd fallback board name: %d",
+ ret);
return ret;
}
} else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {
@@ -1510,7 +1531,8 @@ int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)
ar->bd_api = 2;
ret = ath10k_core_fetch_board_data_api_n(ar, boardname,
- fallback_boardname,
+ fallback_boardname1,
+ fallback_boardname2,
ATH10K_BOARD_API2_FILE);
if (!ret)
goto success;
@@ -2272,6 +2294,17 @@ static int ath10k_init_hw_params(struct ath10k *ar)
return 0;
}
+void ath10k_core_start_recovery(struct ath10k *ar)
+{
+ if (test_and_set_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags)) {
+ ath10k_warn(ar, "already restarting\n");
+ return;
+ }
+
+ queue_work(ar->workqueue, &ar->restart_work);
+}
+EXPORT_SYMBOL(ath10k_core_start_recovery);
+
static void ath10k_core_restart(struct work_struct *work)
{
struct ath10k *ar = container_of(work, struct ath10k, restart_work);
@@ -2604,6 +2637,78 @@ static int ath10k_core_compat_services(struct ath10k *ar)
return 0;
}
+#define TGT_IRAM_READ_PER_ITR (8 * 1024)
+
+static int ath10k_core_copy_target_iram(struct ath10k *ar)
+{
+ const struct ath10k_hw_mem_layout *hw_mem;
+ const struct ath10k_mem_region *tmp, *mem_region = NULL;
+ dma_addr_t paddr;
+ void *vaddr = NULL;
+ u8 num_read_itr;
+ int i, ret;
+ u32 len, remaining_len;
+
+ hw_mem = ath10k_coredump_get_mem_layout(ar);
+ if (!hw_mem)
+ return -ENOMEM;
+
+ for (i = 0; i < hw_mem->region_table.size; i++) {
+ tmp = &hw_mem->region_table.regions[i];
+ if (tmp->type == ATH10K_MEM_REGION_TYPE_REG) {
+ mem_region = tmp;
+ break;
+ }
+ }
+
+ if (!mem_region)
+ return -ENOMEM;
+
+ for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+ if (ar->wmi.mem_chunks[i].req_id ==
+ WMI_IRAM_RECOVERY_HOST_MEM_REQ_ID) {
+ vaddr = ar->wmi.mem_chunks[i].vaddr;
+ len = ar->wmi.mem_chunks[i].len;
+ break;
+ }
+ }
+
+ if (!vaddr || !len) {
+ ath10k_warn(ar, "No allocated memory for IRAM back up");
+ return -ENOMEM;
+ }
+
+ len = (len < mem_region->len) ? len : mem_region->len;
+ paddr = mem_region->start;
+ num_read_itr = len / TGT_IRAM_READ_PER_ITR;
+ remaining_len = len % TGT_IRAM_READ_PER_ITR;
+ for (i = 0; i < num_read_itr; i++) {
+ ret = ath10k_hif_diag_read(ar, paddr, vaddr,
+ TGT_IRAM_READ_PER_ITR);
+ if (ret) {
+ ath10k_warn(ar, "failed to copy firmware IRAM contents: %d",
+ ret);
+ return ret;
+ }
+
+ paddr += TGT_IRAM_READ_PER_ITR;
+ vaddr += TGT_IRAM_READ_PER_ITR;
+ }
+
+ if (remaining_len) {
+ ret = ath10k_hif_diag_read(ar, paddr, vaddr, remaining_len);
+ if (ret) {
+ ath10k_warn(ar, "failed to copy firmware IRAM contents: %d",
+ ret);
+ return ret;
+ }
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "target IRAM back up completed\n");
+
+ return 0;
+}
+
int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
const struct ath10k_fw_components *fw)
{
@@ -2636,7 +2741,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
if (status)
goto err;
- /* Some of of qca988x solutions are having global reset issue
+ /* Some of qca988x solutions are having global reset issue
* during target initialization. Bypassing PLL setting before
* downloading firmware and letting the SoC run on REF_CLK is
* fixing the problem. Corresponding firmware change is also
@@ -2765,6 +2870,16 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n",
ar->hw->wiphy->fw_version);
+ if (test_bit(ATH10K_FW_FEATURE_IRAM_RECOVERY,
+ ar->running_fw->fw_file.fw_features)) {
+ status = ath10k_core_copy_target_iram(ar);
+ if (status) {
+ ath10k_warn(ar, "failed to copy target iram contents: %d",
+ status);
+ goto err_hif_stop;
+ }
+ }
+
if (test_bit(WMI_SERVICE_EXT_RES_CFG_SUPPORT, ar->wmi.svc_map) &&
mode == ATH10K_FIRMWARE_MODE_NORMAL) {
val = 0;