Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff440e5d authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "UPSTREAM: ath10k: detach coredump.c from debug.c"

parents 81876bc8 c8607bb0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
ath10k_core-$(CONFIG_THERMAL) += thermal.o
ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o
ath10k_core-$(CONFIG_PM) += wow.o
ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o

obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
ath10k_pci-y += pci.o \
+117 −77
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include "htt.h"
#include "testmode.h"
#include "wmi-ops.h"
#include "coredump.h"

unsigned int ath10k_debug_mask;
static unsigned int ath10k_cryptmode_param;
@@ -471,6 +472,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
	[ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST] = "allows-mesh-bcast",
	[ATH10K_FW_FEATURE_NO_PS] = "no-ps",
	[ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference",
	[ATH10K_FW_FEATURE_NON_BMI] = "non-bmi",
};

static unsigned int ath10k_core_get_fw_feature_str(char *buf,
@@ -1550,8 +1552,8 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
		data += ie_len;
	}

	if (!fw_file->firmware_data ||
	    !fw_file->firmware_len) {
	if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, fw_file->fw_features) &&
	    (!fw_file->firmware_data || !fw_file->firmware_len)) {
		ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
			    ar->hw_params.fw.dir, name);
		ret = -ENOMEDIUM;
@@ -1577,6 +1579,7 @@ static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name,
		break;
	case ATH10K_BUS_PCI:
	case ATH10K_BUS_AHB:
	case ATH10K_BUS_SNOC:
		scnprintf(fw_name, fw_name_len, "%s-%d.bin",
			  ATH10K_FW_FILE_BASE, fw_api);
		break;
@@ -1862,7 +1865,7 @@ static void ath10k_core_restart(struct work_struct *work)

	mutex_unlock(&ar->conf_mutex);

	ret = ath10k_debug_fw_devcoredump(ar);
	ret = ath10k_coredump_submit(ar);
	if (ret)
		ath10k_warn(ar, "failed to send firmware crash dump via devcoredump: %d",
			    ret);
@@ -2104,6 +2107,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,

	ar->running_fw = fw;

	if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
		      ar->running_fw->fw_file.fw_features)) {
		ath10k_bmi_start(ar);

		if (ath10k_init_configure_target(ar)) {
@@ -2118,8 +2123,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
		/* Some of 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 needed
	 * to set the clock source once the target is initialized.
		 * fixing the problem. Corresponding firmware change is also
		 * needed to set the clock source once the target is
		 * initialized.
		 */
		if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
			     ar->running_fw->fw_file.fw_features)) {
@@ -2141,6 +2147,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,

		if (ar->hif.bus == ATH10K_BUS_SDIO)
			ath10k_init_sdio(ar);
	}

	ar->htc.htc_ops.target_send_suspend_complete =
		ath10k_send_suspend_complete;
@@ -2151,9 +2158,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
		goto err;
	}

	if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
		      ar->running_fw->fw_file.fw_features)) {
		status = ath10k_bmi_done(ar);
		if (status)
			goto err;
	}

	status = ath10k_wmi_attach(ar);
	if (status) {
@@ -2396,18 +2406,33 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
		return ret;
	}

	switch (ar->hif.bus) {
	case ATH10K_BUS_SDIO:
		memset(&target_info, 0, sizeof(target_info));
	if (ar->hif.bus == ATH10K_BUS_SDIO)
		ret = ath10k_bmi_get_target_info_sdio(ar, &target_info);
	else
		if (ret) {
			ath10k_err(ar, "could not get target info (%d)\n", ret);
			goto err_power_down;
		}
		ar->target_version = target_info.version;
		ar->hw->wiphy->hw_version = target_info.version;
		break;
	case ATH10K_BUS_PCI:
	case ATH10K_BUS_AHB:
		memset(&target_info, 0, sizeof(target_info));
		ret = ath10k_bmi_get_target_info(ar, &target_info);
		if (ret) {
			ath10k_err(ar, "could not get target info (%d)\n", ret);
			goto err_power_down;
		}

		ar->target_version = target_info.version;
		ar->hw->wiphy->hw_version = target_info.version;
		break;
	case ATH10K_BUS_SNOC:
		break;
	default:
		ath10k_err(ar, "incorrect hif bus type: %d\n", ar->hif.bus);
	}

	ret = ath10k_init_hw_params(ar);
	if (ret) {
@@ -2428,6 +2453,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar)

	ath10k_debug_print_hwfw_info(ar);

	if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
		      ar->normal_mode_fw.fw_file.fw_features)) {
		ret = ath10k_core_pre_cal_download(ar);
		if (ret) {
			/* pre calibration data download is not necessary
@@ -2459,6 +2486,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
		}

		ath10k_debug_print_board_info(ar);
	}

	ret = ath10k_core_init_firmware_features(ar);
	if (ret) {
@@ -2467,12 +2495,16 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
		goto err_free_firmware_files;
	}

	ret = ath10k_swap_code_seg_init(ar, &ar->normal_mode_fw.fw_file);
	if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
		      ar->normal_mode_fw.fw_file.fw_features)) {
		ret = ath10k_swap_code_seg_init(ar,
						&ar->normal_mode_fw.fw_file);
		if (ret) {
			ath10k_err(ar, "failed to initialize code swap segment: %d\n",
				   ret);
			goto err_free_firmware_files;
		}
	}

	mutex_lock(&ar->conf_mutex);

@@ -2703,12 +2735,19 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,

	init_dummy_netdev(&ar->napi_dev);

	ret = ath10k_debug_create(ar);
	ret = ath10k_coredump_create(ar);
	if (ret)
		goto err_free_aux_wq;

	ret = ath10k_debug_create(ar);
	if (ret)
		goto err_free_coredump;

	return ar;

err_free_coredump:
	ath10k_coredump_destroy(ar);

err_free_aux_wq:
	destroy_workqueue(ar->workqueue_aux);
err_free_wq:
@@ -2730,6 +2769,7 @@ void ath10k_core_destroy(struct ath10k *ar)
	destroy_workqueue(ar->workqueue_aux);

	ath10k_debug_destroy(ar);
	ath10k_coredump_destroy(ar);
	ath10k_htt_tx_destroy(&ar->htt);
	ath10k_wmi_free_host_mem(ar);
	ath10k_mac_destroy(ar);
+13 −4
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ enum ath10k_bus {
	ATH10K_BUS_AHB,
	ATH10K_BUS_SDIO,
	ATH10K_BUS_USB,
	ATH10K_BUS_SNOC,
};

static inline const char *ath10k_bus_str(enum ath10k_bus bus)
@@ -105,6 +106,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
		return "sdio";
	case ATH10K_BUS_USB:
		return "usb";
	case ATH10K_BUS_SNOC:
		return "snoc";
	}

	return "unknown";
@@ -459,8 +462,6 @@ struct ath10k_ce_crash_hdr {

/* used for crash-dump storage, protected by data-lock */
struct ath10k_fw_crash_data {
	bool crashed_since_read;

	guid_t guid;
	struct timespec64 timestamp;
	__le32 registers[REG_DUMP_COUNT_QCA988X];
@@ -490,8 +491,6 @@ struct ath10k_debug {
	u32 reg_addr;
	u32 nf_cal_period;
	void *cal_data;

	struct ath10k_fw_crash_data *fw_crash_data;
};

enum ath10k_state {
@@ -616,6 +615,9 @@ enum ath10k_fw_features {
	/* Firmware allows management tx by reference instead of by value. */
	ATH10K_FW_FEATURE_MGMT_TX_BY_REF = 18,

	/* Firmware load is done externally, not by bmi */
	ATH10K_FW_FEATURE_NON_BMI = 19,

	/* keep last */
	ATH10K_FW_FEATURE_COUNT,
};
@@ -965,6 +967,13 @@ struct ath10k {
#endif

	u32 pktlog_filter;

#ifdef CONFIG_DEV_COREDUMP
	struct {
		struct ath10k_fw_crash_data *fw_crash_data;
	} coredump;
#endif

	struct {
		/* protected by conf_mutex */
		struct ath10k_fw_components utf_mode_fw;
+148 −0
Original line number Diff line number Diff line
/*
 * 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 "coredump.h"

#include <linux/devcoredump.h>
#include <linux/utsname.h>

#include "debug.h"

struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar)
{
	struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data;

	lockdep_assert_held(&ar->data_lock);

	guid_gen(&crash_data->guid);
	ktime_get_real_ts64(&crash_data->timestamp);

	return crash_data;
}
EXPORT_SYMBOL(ath10k_coredump_new);

static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar)
{
	struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data;
	struct ath10k_ce_crash_hdr *ce_hdr;
	struct ath10k_dump_file_data *dump_data;
	struct ath10k_tlv_dump_data *dump_tlv;
	size_t hdr_len = sizeof(*dump_data);
	size_t len, sofar = 0;
	unsigned char *buf;

	len = hdr_len;
	len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
	len += sizeof(*dump_tlv) + sizeof(*ce_hdr) +
		CE_COUNT * sizeof(ce_hdr->entries[0]);

	sofar += hdr_len;

	/* This is going to get big when we start dumping FW RAM and such,
	 * so go ahead and use vmalloc.
	 */
	buf = vzalloc(len);
	if (!buf)
		return NULL;

	spin_lock_bh(&ar->data_lock);

	dump_data = (struct ath10k_dump_file_data *)(buf);
	strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP",
		sizeof(dump_data->df_magic));
	dump_data->len = cpu_to_le32(len);

	dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION);

	guid_copy(&dump_data->guid, &crash_data->guid);
	dump_data->chip_id = cpu_to_le32(ar->chip_id);
	dump_data->bus_type = cpu_to_le32(0);
	dump_data->target_version = cpu_to_le32(ar->target_version);
	dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major);
	dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor);
	dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release);
	dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build);
	dump_data->phy_capability = cpu_to_le32(ar->phy_capability);
	dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power);
	dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power);
	dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
	dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
	dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);

	strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
		sizeof(dump_data->fw_ver));

	dump_data->kernel_ver_code = 0;
	strlcpy(dump_data->kernel_ver, init_utsname()->release,
		sizeof(dump_data->kernel_ver));

	dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec);
	dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec);

	/* Gather crash-dump */
	dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
	dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS);
	dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers));
	memcpy(dump_tlv->tlv_data, &crash_data->registers,
	       sizeof(crash_data->registers));
	sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);

	dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
	dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_CE_DATA);
	dump_tlv->tlv_len = cpu_to_le32(sizeof(*ce_hdr) +
					CE_COUNT * sizeof(ce_hdr->entries[0]));
	ce_hdr = (struct ath10k_ce_crash_hdr *)(dump_tlv->tlv_data);
	ce_hdr->ce_count = cpu_to_le32(CE_COUNT);
	memset(ce_hdr->reserved, 0, sizeof(ce_hdr->reserved));
	memcpy(ce_hdr->entries, crash_data->ce_crash_data,
	       CE_COUNT * sizeof(ce_hdr->entries[0]));
	sofar += sizeof(*dump_tlv) + sizeof(*ce_hdr) +
		 CE_COUNT * sizeof(ce_hdr->entries[0]);

	spin_unlock_bh(&ar->data_lock);

	return dump_data;
}

int ath10k_coredump_submit(struct ath10k *ar)
{
	struct ath10k_dump_file_data *dump;

	dump = ath10k_coredump_build(ar);
	if (!dump) {
		ath10k_warn(ar, "no crash dump data found for devcoredump");
		return -ENODATA;
	}

	dev_coredumpv(ar->dev, dump, le32_to_cpu(dump->len), GFP_KERNEL);

	return 0;
}

int ath10k_coredump_create(struct ath10k *ar)
{
	ar->coredump.fw_crash_data = vzalloc(sizeof(*ar->coredump.fw_crash_data));
	if (!ar->coredump.fw_crash_data)
		return -ENOMEM;

	return 0;
}

void ath10k_coredump_destroy(struct ath10k *ar)
{
	vfree(ar->coredump.fw_crash_data);
	ar->coredump.fw_crash_data = NULL;
}
+132 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#ifndef _COREDUMP_H_
#define _COREDUMP_H_

#include "core.h"

#define ATH10K_FW_CRASH_DUMP_VERSION 1

/**
 * enum ath10k_fw_crash_dump_type - types of data in the dump file
 * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
 */
enum ath10k_fw_crash_dump_type {
	ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
	ATH10K_FW_CRASH_DUMP_CE_DATA = 1,

	ATH10K_FW_CRASH_DUMP_MAX,
};

struct ath10k_tlv_dump_data {
	/* see ath10k_fw_crash_dump_type above */
	__le32 type;

	/* in bytes */
	__le32 tlv_len;

	/* pad to 32-bit boundaries as needed */
	u8 tlv_data[];
} __packed;

struct ath10k_dump_file_data {
	/* dump file information */

	/* "ATH10K-FW-DUMP" */
	char df_magic[16];

	__le32 len;

	/* file dump version */
	__le32 version;

	/* some info we can get from ath10k struct that might help */

	guid_t guid;

	__le32 chip_id;

	/* 0 for now, in place for later hardware */
	__le32 bus_type;

	__le32 target_version;
	__le32 fw_version_major;
	__le32 fw_version_minor;
	__le32 fw_version_release;
	__le32 fw_version_build;
	__le32 phy_capability;
	__le32 hw_min_tx_power;
	__le32 hw_max_tx_power;
	__le32 ht_cap_info;
	__le32 vht_cap_info;
	__le32 num_rf_chains;

	/* firmware version string */
	char fw_ver[ETHTOOL_FWVERS_LEN];

	/* Kernel related information */

	/* time-of-day stamp */
	__le64 tv_sec;

	/* time-of-day stamp, nano-seconds */
	__le64 tv_nsec;

	/* LINUX_VERSION_CODE */
	__le32 kernel_ver_code;

	/* VERMAGIC_STRING */
	char kernel_ver[64];

	/* room for growth w/out changing binary format */
	u8 unused[128];

	/* struct ath10k_tlv_dump_data + more */
	u8 data[0];
} __packed;

#ifdef CONFIG_DEV_COREDUMP

int ath10k_coredump_submit(struct ath10k *ar);
struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar);
int ath10k_coredump_create(struct ath10k *ar);
void ath10k_coredump_destroy(struct ath10k *ar);

#else /* CONFIG_DEV_COREDUMP */

static inline int ath10k_coredump_submit(struct ath10k *ar)
{
	return 0;
}

static inline struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar)
{
	return NULL;
}

static inline int ath10k_coredump_create(struct ath10k *ar)
{
	return 0;
}

static inline void ath10k_coredump_destroy(struct ath10k *ar)
{
}

#endif /* CONFIG_DEV_COREDUMP */

#endif /* _COREDUMP_H_ */
Loading