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

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

Merge "cnss2: Add mini dump support"

parents eb89b7dd d49cdb0a
Loading
Loading
Loading
Loading
+60 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/rwsem.h>
#include <linux/suspend.h>
#include <linux/timer.h>
#include <soc/qcom/minidump.h>
#include <soc/qcom/ramdump.h>
#include <soc/qcom/subsystem_notif.h>

@@ -1558,6 +1559,25 @@ static void cnss_driver_event_work(struct work_struct *work)
	cnss_pm_relax(plat_priv);
}

int cnss_va_to_pa(struct device *dev, size_t size, void *va, dma_addr_t dma,
		  phys_addr_t *pa, unsigned long attrs)
{
	struct sg_table sgt;
	int ret;

	ret = dma_get_sgtable_attrs(dev, &sgt, va, dma, size, attrs);
	if (ret) {
		cnss_pr_err("Failed to get sgtable for va: 0x%pK, dma: %pa, size: 0x%zx, attrs: 0x%x\n",
			    va, &dma, size, attrs);
		return -EINVAL;
	}

	*pa = page_to_phys(sg_page(sgt.sgl));
	sg_free_table(&sgt);

	return 0;
}

int cnss_register_subsys(struct cnss_plat_data *plat_priv)
{
	int ret = 0;
@@ -1808,6 +1828,46 @@ void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
	}
}

int cnss_minidump_add_region(struct cnss_plat_data *plat_priv,
			     enum cnss_fw_dump_type type, int seg_no,
			     void *va, phys_addr_t pa, size_t size)
{
	struct md_region md_entry;
	int ret;

	switch (type) {
	case CNSS_FW_IMAGE:
		snprintf(md_entry.name, sizeof(md_entry.name), "FBC_%X",
			 seg_no);
		break;
	case CNSS_FW_RDDM:
		snprintf(md_entry.name, sizeof(md_entry.name), "RDDM_%X",
			 seg_no);
		break;
	case CNSS_FW_REMOTE_HEAP:
		snprintf(md_entry.name, sizeof(md_entry.name), "RHEAP_%X",
			 seg_no);
		break;
	default:
		cnss_pr_err("Unknown dump type ID: %d\n", type);
		return -EINVAL;
	}

	md_entry.phys_addr = pa;
	md_entry.virt_addr = (uintptr_t)va;
	md_entry.size = size;
	md_entry.id = MSM_DUMP_DATA_CNSS_WLAN;

	cnss_pr_dbg("Mini dump region: %s, va: %pK, pa: %pa, size: 0x%zx\n",
		    md_entry.name, va, &pa, size);

	ret = msm_minidump_add_region(&md_entry);
	if (ret)
		cnss_pr_err("Failed to add mini dump region, err = %d\n", ret);

	return ret;
}

static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv)
{
	int ret = 0;
+6 −0
Original line number Diff line number Diff line
@@ -129,6 +129,7 @@ struct cnss_fw_mem {
	phys_addr_t pa;
	u8 valid;
	u32 type;
	unsigned long attrs;
};

struct wlfw_rf_chip_info {
@@ -406,5 +407,10 @@ void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv);
void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv);
int cnss_get_cpr_info(struct cnss_plat_data *plat_priv);
int cnss_update_cpr_info(struct cnss_plat_data *plat_priv);
int cnss_va_to_pa(struct device *dev, size_t size, void *va, dma_addr_t dma,
		  phys_addr_t *pa, unsigned long attrs);
int cnss_minidump_add_region(struct cnss_plat_data *plat_priv,
			     enum cnss_fw_dump_type type, int seg_no,
			     void *va, phys_addr_t pa, size_t size);

#endif /* _CNSS_MAIN_H */
+79 −52
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */

#include <linux/cma.h>
#include <linux/firmware.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_reserved_mem.h>
#include <linux/pm_runtime.h>
#include <linux/memblock.h>
#include <linux/completion.h>
@@ -2738,14 +2740,16 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
	struct device *dev = &pci_priv->pci_dev->dev;
	int i;

	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
		if (!fw_mem[i].va && fw_mem[i].size) {
			fw_mem[i].va =
				dma_alloc_coherent(&pci_priv->pci_dev->dev,
						   fw_mem[i].size,
						   &fw_mem[i].pa, GFP_KERNEL);
				dma_alloc_attrs(dev, fw_mem[i].size,
						&fw_mem[i].pa, GFP_KERNEL,
						fw_mem[i].attrs);

			if (!fw_mem[i].va) {
				cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx, type: %u\n",
					    fw_mem[i].size, fw_mem[i].type);
@@ -2758,6 +2762,31 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv)
	return 0;
}

static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
	struct device *dev = &pci_priv->pci_dev->dev;
	int i;

	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
		if (fw_mem[i].va && fw_mem[i].size) {
			cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
				    fw_mem[i].va, &fw_mem[i].pa,
				    fw_mem[i].size, fw_mem[i].type);
			dma_free_attrs(dev, fw_mem[i].size,
				       fw_mem[i].va, fw_mem[i].pa,
				       fw_mem[i].attrs);
			fw_mem[i].va = NULL;
			fw_mem[i].pa = 0;
			fw_mem[i].size = 0;
			fw_mem[i].type = 0;
		}
	}

	plat_priv->fw_mem_seg_len = 0;
}

int cnss_pci_alloc_qdss_mem(struct cnss_pci_data *pci_priv)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
@@ -2815,30 +2844,6 @@ void cnss_pci_free_qdss_mem(struct cnss_pci_data *pci_priv)
	plat_priv->qdss_mem_seg_len = 0;
}

static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
	int i;

	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
		if (fw_mem[i].va && fw_mem[i].size) {
			cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
				    fw_mem[i].va, &fw_mem[i].pa,
				    fw_mem[i].size, fw_mem[i].type);
			dma_free_coherent(&pci_priv->pci_dev->dev,
					  fw_mem[i].size, fw_mem[i].va,
					  fw_mem[i].pa);
			fw_mem[i].va = NULL;
			fw_mem[i].pa = 0;
			fw_mem[i].size = 0;
			fw_mem[i].type = 0;
		}
	}

	plat_priv->fw_mem_seg_len = 0;
}

int cnss_pci_load_m3(struct cnss_pci_data *pci_priv)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
@@ -3458,6 +3463,29 @@ int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv)
	return 0;
}

static void cnss_pci_add_dump_seg(struct cnss_pci_data *pci_priv,
				  struct cnss_dump_seg *dump_seg,
				  enum cnss_fw_dump_type type, int seg_no,
				  void *va, dma_addr_t dma, size_t size)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	struct device *dev = &pci_priv->pci_dev->dev;
	phys_addr_t pa;

	dump_seg->address = dma;
	dump_seg->v_address = va;
	dump_seg->size = size;
	dump_seg->type = type;

	cnss_pr_dbg("Seg: %x, va: %pK, dma: %pa, size: 0x%zx\n",
		    seg_no, va, &dma, size);

	if (cnss_va_to_pa(dev, size, va, dma, &pa, DMA_ATTR_FORCE_CONTIGUOUS))
		return;

	cnss_minidump_add_region(plat_priv, type, seg_no, va, pa, size);
}

void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
@@ -3467,7 +3495,7 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)
		plat_priv->ramdump_info_v2.dump_data_vaddr;
	struct image_info *fw_image, *rddm_image;
	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
	int ret, i;
	int ret, i, j;

	if (test_bit(CNSS_MHI_RDDM_DONE, &pci_priv->mhi_state)) {
		cnss_pr_dbg("RAM dump is already collected, skip\n");
@@ -3496,13 +3524,10 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)
		    fw_image->entries);

	for (i = 0; i < fw_image->entries; i++) {
		dump_seg->address = fw_image->mhi_buf[i].dma_addr;
		dump_seg->v_address = fw_image->mhi_buf[i].buf;
		dump_seg->size = fw_image->mhi_buf[i].len;
		dump_seg->type = CNSS_FW_IMAGE;
		cnss_pr_dbg("seg-%d: address 0x%lx, v_address %pK, size 0x%lx\n",
			    i, dump_seg->address,
			    dump_seg->v_address, dump_seg->size);
		cnss_pci_add_dump_seg(pci_priv, dump_seg, CNSS_FW_IMAGE, i,
				      fw_image->mhi_buf[i].buf,
				      fw_image->mhi_buf[i].dma_addr,
				      fw_image->mhi_buf[i].len);
		dump_seg++;
	}

@@ -3512,13 +3537,10 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)
		    rddm_image->entries);

	for (i = 0; i < rddm_image->entries; i++) {
		dump_seg->address = rddm_image->mhi_buf[i].dma_addr;
		dump_seg->v_address = rddm_image->mhi_buf[i].buf;
		dump_seg->size = rddm_image->mhi_buf[i].len;
		dump_seg->type = CNSS_FW_RDDM;
		cnss_pr_dbg("seg-%d: address 0x%lx, v_address %pK, size 0x%lx\n",
			    i, dump_seg->address,
			    dump_seg->v_address, dump_seg->size);
		cnss_pci_add_dump_seg(pci_priv, dump_seg, CNSS_FW_RDDM, i,
				      rddm_image->mhi_buf[i].buf,
				      rddm_image->mhi_buf[i].dma_addr,
				      rddm_image->mhi_buf[i].len);
		dump_seg++;
	}

@@ -3526,17 +3548,15 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)

	cnss_pr_dbg("Collect remote heap dump segment\n");

	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
	for (i = 0, j = 0; i < plat_priv->fw_mem_seg_len; i++) {
		if (fw_mem[i].type == CNSS_MEM_TYPE_DDR) {
			dump_seg->address = fw_mem[i].pa;
			dump_seg->v_address = fw_mem[i].va;
			dump_seg->size = fw_mem[i].size;
			dump_seg->type = CNSS_FW_REMOTE_HEAP;
			cnss_pr_dbg("seg-%d: address 0x%lx, v_address %pK, size 0x%lx\n",
				    i, dump_seg->address, dump_seg->v_address,
				    dump_seg->size);
			cnss_pci_add_dump_seg(pci_priv, dump_seg,
					      CNSS_FW_REMOTE_HEAP, j,
					      fw_mem[i].va, fw_mem[i].pa,
					      fw_mem[i].size);
			dump_seg++;
			dump_data->nentries++;
			j++;
		}
	}

@@ -3828,12 +3848,12 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
	int ret = 0;
	struct cnss_pci_data *pci_priv;
	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
	struct device *dev = &pci_dev->dev;

	cnss_pr_dbg("PCI is probing, vendor ID: 0x%x, device ID: 0x%x\n",
		    id->vendor, pci_dev->device);

	pci_priv = devm_kzalloc(&pci_dev->dev, sizeof(*pci_priv),
				GFP_KERNEL);
	pci_priv = devm_kzalloc(dev, sizeof(*pci_priv), GFP_KERNEL);
	if (!pci_priv) {
		ret = -ENOMEM;
		goto out;
@@ -3852,6 +3872,13 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
		 DEFAULT_FW_FILE_NAME);
	mutex_init(&pci_priv->bus_lock);

	ret = of_reserved_mem_device_init(dev);
	if (ret)
		cnss_pr_err("Failed to init reserved mem device, err = %d\n",
			    ret);
	if (dev->cma_area)
		cnss_pr_dbg("CMA area is %s\n", cma_get_name(dev->cma_area));

	ret = cnss_register_subsys(plat_priv);
	if (ret)
		goto reset_ctx;
+3 −0
Original line number Diff line number Diff line
@@ -1560,6 +1560,9 @@ static void cnss_wlfw_request_mem_ind_cb(struct qmi_handle *qmi_wlfw,
			    ind_msg->mem_seg[i].size, ind_msg->mem_seg[i].type);
		plat_priv->fw_mem[i].type = ind_msg->mem_seg[i].type;
		plat_priv->fw_mem[i].size = ind_msg->mem_seg[i].size;
		if (plat_priv->fw_mem[i].type == CNSS_MEM_TYPE_DDR)
			plat_priv->fw_mem[i].attrs |=
				DMA_ATTR_FORCE_CONTIGUOUS;
	}

	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM,