18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Qualcomm Technologies HIDMA debug file
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
98c2ecf20Sopenharmony_ci#include <linux/device.h>
108c2ecf20Sopenharmony_ci#include <linux/list.h>
118c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "hidma.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic void hidma_ll_chstats(struct seq_file *s, void *llhndl, u32 tre_ch)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	struct hidma_lldev *lldev = llhndl;
188c2ecf20Sopenharmony_ci	struct hidma_tre *tre;
198c2ecf20Sopenharmony_ci	u32 length;
208c2ecf20Sopenharmony_ci	dma_addr_t src_start;
218c2ecf20Sopenharmony_ci	dma_addr_t dest_start;
228c2ecf20Sopenharmony_ci	u32 *tre_local;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	if (tre_ch >= lldev->nr_tres) {
258c2ecf20Sopenharmony_ci		dev_err(lldev->dev, "invalid TRE number in chstats:%d", tre_ch);
268c2ecf20Sopenharmony_ci		return;
278c2ecf20Sopenharmony_ci	}
288c2ecf20Sopenharmony_ci	tre = &lldev->trepool[tre_ch];
298c2ecf20Sopenharmony_ci	seq_printf(s, "------Channel %d -----\n", tre_ch);
308c2ecf20Sopenharmony_ci	seq_printf(s, "allocated=%d\n", atomic_read(&tre->allocated));
318c2ecf20Sopenharmony_ci	seq_printf(s, "queued = 0x%x\n", tre->queued);
328c2ecf20Sopenharmony_ci	seq_printf(s, "err_info = 0x%x\n", tre->err_info);
338c2ecf20Sopenharmony_ci	seq_printf(s, "err_code = 0x%x\n", tre->err_code);
348c2ecf20Sopenharmony_ci	seq_printf(s, "status = 0x%x\n", tre->status);
358c2ecf20Sopenharmony_ci	seq_printf(s, "idx = 0x%x\n", tre->idx);
368c2ecf20Sopenharmony_ci	seq_printf(s, "dma_sig = 0x%x\n", tre->dma_sig);
378c2ecf20Sopenharmony_ci	seq_printf(s, "dev_name=%s\n", tre->dev_name);
388c2ecf20Sopenharmony_ci	seq_printf(s, "callback=%p\n", tre->callback);
398c2ecf20Sopenharmony_ci	seq_printf(s, "data=%p\n", tre->data);
408c2ecf20Sopenharmony_ci	seq_printf(s, "tre_index = 0x%x\n", tre->tre_index);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	tre_local = &tre->tre_local[0];
438c2ecf20Sopenharmony_ci	src_start = tre_local[HIDMA_TRE_SRC_LOW_IDX];
448c2ecf20Sopenharmony_ci	src_start = ((u64) (tre_local[HIDMA_TRE_SRC_HI_IDX]) << 32) + src_start;
458c2ecf20Sopenharmony_ci	dest_start = tre_local[HIDMA_TRE_DEST_LOW_IDX];
468c2ecf20Sopenharmony_ci	dest_start += ((u64) (tre_local[HIDMA_TRE_DEST_HI_IDX]) << 32);
478c2ecf20Sopenharmony_ci	length = tre_local[HIDMA_TRE_LEN_IDX];
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	seq_printf(s, "src=%pap\n", &src_start);
508c2ecf20Sopenharmony_ci	seq_printf(s, "dest=%pap\n", &dest_start);
518c2ecf20Sopenharmony_ci	seq_printf(s, "length = 0x%x\n", length);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic void hidma_ll_devstats(struct seq_file *s, void *llhndl)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct hidma_lldev *lldev = llhndl;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	seq_puts(s, "------Device -----\n");
598c2ecf20Sopenharmony_ci	seq_printf(s, "lldev init = 0x%x\n", lldev->initialized);
608c2ecf20Sopenharmony_ci	seq_printf(s, "trch_state = 0x%x\n", lldev->trch_state);
618c2ecf20Sopenharmony_ci	seq_printf(s, "evch_state = 0x%x\n", lldev->evch_state);
628c2ecf20Sopenharmony_ci	seq_printf(s, "chidx = 0x%x\n", lldev->chidx);
638c2ecf20Sopenharmony_ci	seq_printf(s, "nr_tres = 0x%x\n", lldev->nr_tres);
648c2ecf20Sopenharmony_ci	seq_printf(s, "trca=%p\n", lldev->trca);
658c2ecf20Sopenharmony_ci	seq_printf(s, "tre_ring=%p\n", lldev->tre_ring);
668c2ecf20Sopenharmony_ci	seq_printf(s, "tre_ring_handle=%pap\n", &lldev->tre_dma);
678c2ecf20Sopenharmony_ci	seq_printf(s, "tre_ring_size = 0x%x\n", lldev->tre_ring_size);
688c2ecf20Sopenharmony_ci	seq_printf(s, "tre_processed_off = 0x%x\n", lldev->tre_processed_off);
698c2ecf20Sopenharmony_ci	seq_printf(s, "pending_tre_count=%d\n",
708c2ecf20Sopenharmony_ci			atomic_read(&lldev->pending_tre_count));
718c2ecf20Sopenharmony_ci	seq_printf(s, "evca=%p\n", lldev->evca);
728c2ecf20Sopenharmony_ci	seq_printf(s, "evre_ring=%p\n", lldev->evre_ring);
738c2ecf20Sopenharmony_ci	seq_printf(s, "evre_ring_handle=%pap\n", &lldev->evre_dma);
748c2ecf20Sopenharmony_ci	seq_printf(s, "evre_ring_size = 0x%x\n", lldev->evre_ring_size);
758c2ecf20Sopenharmony_ci	seq_printf(s, "evre_processed_off = 0x%x\n", lldev->evre_processed_off);
768c2ecf20Sopenharmony_ci	seq_printf(s, "tre_write_offset = 0x%x\n", lldev->tre_write_offset);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/*
808c2ecf20Sopenharmony_ci * hidma_chan_show: display HIDMA channel statistics
818c2ecf20Sopenharmony_ci *
828c2ecf20Sopenharmony_ci * Display the statistics for the current HIDMA virtual channel device.
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_cistatic int hidma_chan_show(struct seq_file *s, void *unused)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct hidma_chan *mchan = s->private;
878c2ecf20Sopenharmony_ci	struct hidma_desc *mdesc;
888c2ecf20Sopenharmony_ci	struct hidma_dev *dmadev = mchan->dmadev;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	pm_runtime_get_sync(dmadev->ddev.dev);
918c2ecf20Sopenharmony_ci	seq_printf(s, "paused=%u\n", mchan->paused);
928c2ecf20Sopenharmony_ci	seq_printf(s, "dma_sig=%u\n", mchan->dma_sig);
938c2ecf20Sopenharmony_ci	seq_puts(s, "prepared\n");
948c2ecf20Sopenharmony_ci	list_for_each_entry(mdesc, &mchan->prepared, node)
958c2ecf20Sopenharmony_ci		hidma_ll_chstats(s, mchan->dmadev->lldev, mdesc->tre_ch);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	seq_puts(s, "active\n");
988c2ecf20Sopenharmony_ci	list_for_each_entry(mdesc, &mchan->active, node)
998c2ecf20Sopenharmony_ci		hidma_ll_chstats(s, mchan->dmadev->lldev, mdesc->tre_ch);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	seq_puts(s, "completed\n");
1028c2ecf20Sopenharmony_ci	list_for_each_entry(mdesc, &mchan->completed, node)
1038c2ecf20Sopenharmony_ci		hidma_ll_chstats(s, mchan->dmadev->lldev, mdesc->tre_ch);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	hidma_ll_devstats(s, mchan->dmadev->lldev);
1068c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(dmadev->ddev.dev);
1078c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(dmadev->ddev.dev);
1088c2ecf20Sopenharmony_ci	return 0;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/*
1128c2ecf20Sopenharmony_ci * hidma_dma_show: display HIDMA device info
1138c2ecf20Sopenharmony_ci *
1148c2ecf20Sopenharmony_ci * Display the info for the current HIDMA device.
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_cistatic int hidma_dma_show(struct seq_file *s, void *unused)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct hidma_dev *dmadev = s->private;
1198c2ecf20Sopenharmony_ci	resource_size_t sz;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	seq_printf(s, "nr_descriptors=%d\n", dmadev->nr_descriptors);
1228c2ecf20Sopenharmony_ci	seq_printf(s, "dev_trca=%p\n", &dmadev->dev_trca);
1238c2ecf20Sopenharmony_ci	seq_printf(s, "dev_trca_phys=%pa\n", &dmadev->trca_resource->start);
1248c2ecf20Sopenharmony_ci	sz = resource_size(dmadev->trca_resource);
1258c2ecf20Sopenharmony_ci	seq_printf(s, "dev_trca_size=%pa\n", &sz);
1268c2ecf20Sopenharmony_ci	seq_printf(s, "dev_evca=%p\n", &dmadev->dev_evca);
1278c2ecf20Sopenharmony_ci	seq_printf(s, "dev_evca_phys=%pa\n", &dmadev->evca_resource->start);
1288c2ecf20Sopenharmony_ci	sz = resource_size(dmadev->evca_resource);
1298c2ecf20Sopenharmony_ci	seq_printf(s, "dev_evca_size=%pa\n", &sz);
1308c2ecf20Sopenharmony_ci	return 0;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(hidma_chan);
1348c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(hidma_dma);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_civoid hidma_debug_uninit(struct hidma_dev *dmadev)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	debugfs_remove_recursive(dmadev->debugfs);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_civoid hidma_debug_init(struct hidma_dev *dmadev)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	int chidx = 0;
1448c2ecf20Sopenharmony_ci	struct list_head *position = NULL;
1458c2ecf20Sopenharmony_ci	struct dentry *dir;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	dmadev->debugfs = debugfs_create_dir(dev_name(dmadev->ddev.dev), NULL);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* walk through the virtual channel list */
1508c2ecf20Sopenharmony_ci	list_for_each(position, &dmadev->ddev.channels) {
1518c2ecf20Sopenharmony_ci		struct hidma_chan *chan;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci		chan = list_entry(position, struct hidma_chan,
1548c2ecf20Sopenharmony_ci				  chan.device_node);
1558c2ecf20Sopenharmony_ci		sprintf(chan->dbg_name, "chan%d", chidx);
1568c2ecf20Sopenharmony_ci		dir = debugfs_create_dir(chan->dbg_name,
1578c2ecf20Sopenharmony_ci						   dmadev->debugfs);
1588c2ecf20Sopenharmony_ci		debugfs_create_file("stats", S_IRUGO, dir, chan,
1598c2ecf20Sopenharmony_ci				    &hidma_chan_fops);
1608c2ecf20Sopenharmony_ci		chidx++;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	debugfs_create_file("stats", S_IRUGO, dmadev->debugfs, dmadev,
1648c2ecf20Sopenharmony_ci			    &hidma_dma_fops);
1658c2ecf20Sopenharmony_ci}
166