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

Commit 7243a1af authored by Kalle Valo's avatar Kalle Valo
Browse files
ath.git patches for 4.11. Major changes:

wcn36xx

* convert to a proper QCOM_SMD driver (from the platform_driver interface)

ath10k

* VHT160 support
* dump Copy Engine registers during firmware crash
* search board file extension from SMBIOS

wil6210

* add disable_ap_sme module parameter
parents b1a4c9a1 f2593cb1
Loading
Loading
Loading
Loading
+40 −8
Original line number Diff line number Diff line
@@ -958,7 +958,7 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
	 * coherent DMA are unsupported
	 */
	dest_ring->base_addr_owner_space_unaligned =
		dma_alloc_coherent(ar->dev,
		dma_zalloc_coherent(ar->dev,
				   (nentries * sizeof(struct ce_desc) +
				    CE_DESC_RING_ALIGN),
				   &base_addr, GFP_KERNEL);
@@ -969,13 +969,6 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,

	dest_ring->base_addr_ce_space_unaligned = base_addr;

	/*
	 * Correctly initialize memory to 0 to prevent garbage
	 * data crashing system when download firmware
	 */
	memset(dest_ring->base_addr_owner_space_unaligned, 0,
	       nentries * sizeof(struct ce_desc) + CE_DESC_RING_ALIGN);

	dest_ring->base_addr_owner_space = PTR_ALIGN(
			dest_ring->base_addr_owner_space_unaligned,
			CE_DESC_RING_ALIGN);
@@ -1130,3 +1123,42 @@ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id)
	ce_state->src_ring = NULL;
	ce_state->dest_ring = NULL;
}

void ath10k_ce_dump_registers(struct ath10k *ar,
			      struct ath10k_fw_crash_data *crash_data)
{
	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
	struct ath10k_ce_crash_data ce;
	u32 addr, id;

	lockdep_assert_held(&ar->data_lock);

	ath10k_err(ar, "Copy Engine register dump:\n");

	spin_lock_bh(&ar_pci->ce_lock);
	for (id = 0; id < CE_COUNT; id++) {
		addr = ath10k_ce_base_address(ar, id);
		ce.base_addr = cpu_to_le32(addr);

		ce.src_wr_idx =
			cpu_to_le32(ath10k_ce_src_ring_write_index_get(ar, addr));
		ce.src_r_idx =
			cpu_to_le32(ath10k_ce_src_ring_read_index_get(ar, addr));
		ce.dst_wr_idx =
			cpu_to_le32(ath10k_ce_dest_ring_write_index_get(ar, addr));
		ce.dst_r_idx =
			cpu_to_le32(ath10k_ce_dest_ring_read_index_get(ar, addr));

		if (crash_data)
			crash_data->ce_crash_data[id] = ce;

		ath10k_err(ar, "[%02d]: 0x%08x %3u %3u %3u %3u", id,
			   le32_to_cpu(ce.base_addr),
			   le32_to_cpu(ce.src_wr_idx),
			   le32_to_cpu(ce.src_r_idx),
			   le32_to_cpu(ce.dst_wr_idx),
			   le32_to_cpu(ce.dst_r_idx));
	}

	spin_unlock_bh(&ar_pci->ce_lock);
}
+2 −2
Original line number Diff line number Diff line
@@ -20,8 +20,6 @@

#include "hif.h"

/* Maximum number of Copy Engine's supported */
#define CE_COUNT_MAX 12
#define CE_HTT_H2T_MSG_SRC_NENTRIES 8192

/* Descriptor rings must be aligned to this boundary */
@@ -228,6 +226,8 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar);
void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
int ath10k_ce_disable_interrupts(struct ath10k *ar);
void ath10k_ce_enable_interrupts(struct ath10k *ar);
void ath10k_ce_dump_registers(struct ath10k *ar,
			      struct ath10k_fw_crash_data *crash_data);

/* ce_attr.flags values */
/* Use NonSnooping PCIe accesses? */
+81 −3
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/of.h>
#include <linux/dmi.h>
#include <linux/ctype.h>
#include <asm/byteorder.h>

#include "core.h"
@@ -707,6 +709,72 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)
	return 0;
}

static void ath10k_core_check_bdfext(const struct dmi_header *hdr, void *data)
{
	struct ath10k *ar = data;
	const char *bdf_ext;
	const char *magic = ATH10K_SMBIOS_BDF_EXT_MAGIC;
	u8 bdf_enabled;
	int i;

	if (hdr->type != ATH10K_SMBIOS_BDF_EXT_TYPE)
		return;

	if (hdr->length != ATH10K_SMBIOS_BDF_EXT_LENGTH) {
		ath10k_dbg(ar, ATH10K_DBG_BOOT,
			   "wrong smbios bdf ext type length (%d).\n",
			   hdr->length);
		return;
	}

	bdf_enabled = *((u8 *)hdr + ATH10K_SMBIOS_BDF_EXT_OFFSET);
	if (!bdf_enabled) {
		ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not found.\n");
		return;
	}

	/* Only one string exists (per spec) */
	bdf_ext = (char *)hdr + hdr->length;

	if (memcmp(bdf_ext, magic, strlen(magic)) != 0) {
		ath10k_dbg(ar, ATH10K_DBG_BOOT,
			   "bdf variant magic does not match.\n");
		return;
	}

	for (i = 0; i < strlen(bdf_ext); i++) {
		if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) {
			ath10k_dbg(ar, ATH10K_DBG_BOOT,
				   "bdf variant name contains non ascii chars.\n");
			return;
		}
	}

	/* Copy extension name without magic suffix */
	if (strscpy(ar->id.bdf_ext, bdf_ext + strlen(magic),
		    sizeof(ar->id.bdf_ext)) < 0) {
		ath10k_dbg(ar, ATH10K_DBG_BOOT,
			   "bdf variant string is longer than the buffer can accommodate (variant: %s)\n",
			    bdf_ext);
		return;
	}

	ath10k_dbg(ar, ATH10K_DBG_BOOT,
		   "found and validated bdf variant smbios_type 0x%x bdf %s\n",
		   ATH10K_SMBIOS_BDF_EXT_TYPE, bdf_ext);
}

static int ath10k_core_check_smbios(struct ath10k *ar)
{
	ar->id.bdf_ext[0] = '\0';
	dmi_walk(ath10k_core_check_bdfext, ar);

	if (ar->id.bdf_ext[0] == '\0')
		return -ENODATA;

	return 0;
}

static int ath10k_download_and_run_otp(struct ath10k *ar)
{
	u32 result, address = ar->hw_params.patch_load_addr;
@@ -1053,6 +1121,9 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
					 size_t name_len)
{
	/* strlen(',variant=') + strlen(ar->id.bdf_ext) */
	char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH];

	if (ar->id.bmi_ids_valid) {
		scnprintf(name, name_len,
			  "bus=%s,bmi-chip-id=%d,bmi-board-id=%d",
@@ -1062,12 +1133,15 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
		goto out;
	}

	if (ar->id.bdf_ext[0] != '\0')
		scnprintf(variant, sizeof(variant), ",variant=%s",
			  ar->id.bdf_ext);

	scnprintf(name, name_len,
		  "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x",
		  "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s",
		  ath10k_bus_str(ar->hif.bus),
		  ar->id.vendor, ar->id.device,
		  ar->id.subsystem_vendor, ar->id.subsystem_device);

		  ar->id.subsystem_vendor, ar->id.subsystem_device, variant);
out:
	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using board name '%s'\n", name);

@@ -2128,6 +2202,10 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
		goto err_free_firmware_files;
	}

	ret = ath10k_core_check_smbios(ar);
	if (ret)
		ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not set.\n");

	ret = ath10k_core_fetch_board_file(ar);
	if (ret) {
		ath10k_err(ar, "failed to fetch board file: %d\n", ret);
+36 −0
Original line number Diff line number Diff line
@@ -69,6 +69,23 @@
#define ATH10K_NAPI_BUDGET      64
#define ATH10K_NAPI_QUOTA_LIMIT 60

/* SMBIOS type containing Board Data File Name Extension */
#define ATH10K_SMBIOS_BDF_EXT_TYPE 0xF8

/* SMBIOS type structure length (excluding strings-set) */
#define ATH10K_SMBIOS_BDF_EXT_LENGTH 0x9

/* Offset pointing to Board Data File Name Extension */
#define ATH10K_SMBIOS_BDF_EXT_OFFSET 0x8

/* Board Data File Name Extension string length.
 * String format: BDF_<Customer ID>_<Extension>\0
 */
#define ATH10K_SMBIOS_BDF_EXT_STR_LENGTH 0x20

/* The magic used by QCA spec */
#define ATH10K_SMBIOS_BDF_EXT_MAGIC "BDF_"

struct ath10k;

enum ath10k_bus {
@@ -314,6 +331,7 @@ struct ath10k_peer {
	struct ieee80211_vif *vif;
	struct ieee80211_sta *sta;

	bool removed;
	int vdev_id;
	u8 addr[ETH_ALEN];
	DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS);
@@ -419,6 +437,21 @@ struct ath10k_vif_iter {
	struct ath10k_vif *arvif;
};

/* Copy Engine register dump, protected by ce-lock */
struct ath10k_ce_crash_data {
	__le32 base_addr;
	__le32 src_wr_idx;
	__le32 src_r_idx;
	__le32 dst_wr_idx;
	__le32 dst_r_idx;
};

struct ath10k_ce_crash_hdr {
	__le32 ce_count;
	__le32 reserved[3]; /* for future use */
	struct ath10k_ce_crash_data entries[];
};

/* used for crash-dump storage, protected by data-lock */
struct ath10k_fw_crash_data {
	bool crashed_since_read;
@@ -426,6 +459,7 @@ struct ath10k_fw_crash_data {
	uuid_le uuid;
	struct timespec timestamp;
	__le32 registers[REG_DUMP_COUNT_QCA988X];
	struct ath10k_ce_crash_data ce_crash_data[CE_COUNT_MAX];
};

struct ath10k_debug {
@@ -781,6 +815,8 @@ struct ath10k {
		bool bmi_ids_valid;
		u8 bmi_board_id;
		u8 bmi_chip_id;

		char bdf_ext[ATH10K_SMBIOS_BDF_EXT_STR_LENGTH];
	} id;

	int fw_api;
+21 −2
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
 */
enum ath10k_fw_crash_dump_type {
	ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
	ATH10K_FW_CRASH_DUMP_CE_DATA = 1,

	ATH10K_FW_CRASH_DUMP_MAX,
};
@@ -400,6 +401,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
			 * prevent firmware from DoS-ing the host.
			 */
			ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
			ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);
			ath10k_warn(ar, "dropping fw peer stats\n");
			goto free;
		}
@@ -410,10 +412,12 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
			goto free;
		}

		list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
		list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
		if (!list_empty(&stats.peers))
			list_splice_tail_init(&stats.peers_extd,
					      &ar->debug.fw_stats.peers_extd);

		list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
		list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
	}

	complete(&ar->debug.fw_stats_complete);
@@ -726,6 +730,7 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar,
							    bool mark_read)
{
	struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
	struct ath10k_ce_crash_hdr *ce_hdr;
	struct ath10k_dump_file_data *dump_data;
	struct ath10k_tlv_dump_data *dump_tlv;
	int hdr_len = sizeof(*dump_data);
@@ -734,6 +739,8 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar,

	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;

@@ -792,6 +799,18 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar,
	       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]);

	ar->debug.fw_crash_data->crashed_since_read = !mark_read;

	spin_unlock_bh(&ar->data_lock);
Loading