1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Qualcomm Technologies HIDMA debug file |
4 | * |
5 | * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. |
6 | */ |
7 | |
8 | #include <linux/debugfs.h> |
9 | #include <linux/device.h> |
10 | #include <linux/list.h> |
11 | #include <linux/pm_runtime.h> |
12 | |
13 | #include "hidma.h" |
14 | |
15 | static void hidma_ll_chstats(struct seq_file *s, void *llhndl, u32 tre_ch) |
16 | { |
17 | struct hidma_lldev *lldev = llhndl; |
18 | struct hidma_tre *tre; |
19 | u32 length; |
20 | dma_addr_t src_start; |
21 | dma_addr_t dest_start; |
22 | u32 *tre_local; |
23 | |
24 | if (tre_ch >= lldev->nr_tres) { |
25 | dev_err(lldev->dev, "invalid TRE number in chstats:%d" , tre_ch); |
26 | return; |
27 | } |
28 | tre = &lldev->trepool[tre_ch]; |
29 | seq_printf(m: s, fmt: "------Channel %d -----\n" , tre_ch); |
30 | seq_printf(m: s, fmt: "allocated=%d\n" , atomic_read(v: &tre->allocated)); |
31 | seq_printf(m: s, fmt: "queued = 0x%x\n" , tre->queued); |
32 | seq_printf(m: s, fmt: "err_info = 0x%x\n" , tre->err_info); |
33 | seq_printf(m: s, fmt: "err_code = 0x%x\n" , tre->err_code); |
34 | seq_printf(m: s, fmt: "status = 0x%x\n" , tre->status); |
35 | seq_printf(m: s, fmt: "idx = 0x%x\n" , tre->idx); |
36 | seq_printf(m: s, fmt: "dma_sig = 0x%x\n" , tre->dma_sig); |
37 | seq_printf(m: s, fmt: "dev_name=%s\n" , tre->dev_name); |
38 | seq_printf(m: s, fmt: "callback=%p\n" , tre->callback); |
39 | seq_printf(m: s, fmt: "data=%p\n" , tre->data); |
40 | seq_printf(m: s, fmt: "tre_index = 0x%x\n" , tre->tre_index); |
41 | |
42 | tre_local = &tre->tre_local[0]; |
43 | src_start = tre_local[HIDMA_TRE_SRC_LOW_IDX]; |
44 | src_start = ((u64) (tre_local[HIDMA_TRE_SRC_HI_IDX]) << 32) + src_start; |
45 | dest_start = tre_local[HIDMA_TRE_DEST_LOW_IDX]; |
46 | dest_start += ((u64) (tre_local[HIDMA_TRE_DEST_HI_IDX]) << 32); |
47 | length = tre_local[HIDMA_TRE_LEN_IDX]; |
48 | |
49 | seq_printf(m: s, fmt: "src=%pap\n" , &src_start); |
50 | seq_printf(m: s, fmt: "dest=%pap\n" , &dest_start); |
51 | seq_printf(m: s, fmt: "length = 0x%x\n" , length); |
52 | } |
53 | |
54 | static void hidma_ll_devstats(struct seq_file *s, void *llhndl) |
55 | { |
56 | struct hidma_lldev *lldev = llhndl; |
57 | |
58 | seq_puts(m: s, s: "------Device -----\n" ); |
59 | seq_printf(m: s, fmt: "lldev init = 0x%x\n" , lldev->initialized); |
60 | seq_printf(m: s, fmt: "trch_state = 0x%x\n" , lldev->trch_state); |
61 | seq_printf(m: s, fmt: "evch_state = 0x%x\n" , lldev->evch_state); |
62 | seq_printf(m: s, fmt: "chidx = 0x%x\n" , lldev->chidx); |
63 | seq_printf(m: s, fmt: "nr_tres = 0x%x\n" , lldev->nr_tres); |
64 | seq_printf(m: s, fmt: "trca=%p\n" , lldev->trca); |
65 | seq_printf(m: s, fmt: "tre_ring=%p\n" , lldev->tre_ring); |
66 | seq_printf(m: s, fmt: "tre_ring_handle=%pap\n" , &lldev->tre_dma); |
67 | seq_printf(m: s, fmt: "tre_ring_size = 0x%x\n" , lldev->tre_ring_size); |
68 | seq_printf(m: s, fmt: "tre_processed_off = 0x%x\n" , lldev->tre_processed_off); |
69 | seq_printf(m: s, fmt: "pending_tre_count=%d\n" , |
70 | atomic_read(v: &lldev->pending_tre_count)); |
71 | seq_printf(m: s, fmt: "evca=%p\n" , lldev->evca); |
72 | seq_printf(m: s, fmt: "evre_ring=%p\n" , lldev->evre_ring); |
73 | seq_printf(m: s, fmt: "evre_ring_handle=%pap\n" , &lldev->evre_dma); |
74 | seq_printf(m: s, fmt: "evre_ring_size = 0x%x\n" , lldev->evre_ring_size); |
75 | seq_printf(m: s, fmt: "evre_processed_off = 0x%x\n" , lldev->evre_processed_off); |
76 | seq_printf(m: s, fmt: "tre_write_offset = 0x%x\n" , lldev->tre_write_offset); |
77 | } |
78 | |
79 | /* |
80 | * hidma_chan_show: display HIDMA channel statistics |
81 | * |
82 | * Display the statistics for the current HIDMA virtual channel device. |
83 | */ |
84 | static int hidma_chan_show(struct seq_file *s, void *unused) |
85 | { |
86 | struct hidma_chan *mchan = s->private; |
87 | struct hidma_desc *mdesc; |
88 | struct hidma_dev *dmadev = mchan->dmadev; |
89 | |
90 | pm_runtime_get_sync(dev: dmadev->ddev.dev); |
91 | seq_printf(m: s, fmt: "paused=%u\n" , mchan->paused); |
92 | seq_printf(m: s, fmt: "dma_sig=%u\n" , mchan->dma_sig); |
93 | seq_puts(m: s, s: "prepared\n" ); |
94 | list_for_each_entry(mdesc, &mchan->prepared, node) |
95 | hidma_ll_chstats(s, llhndl: mchan->dmadev->lldev, tre_ch: mdesc->tre_ch); |
96 | |
97 | seq_puts(m: s, s: "active\n" ); |
98 | list_for_each_entry(mdesc, &mchan->active, node) |
99 | hidma_ll_chstats(s, llhndl: mchan->dmadev->lldev, tre_ch: mdesc->tre_ch); |
100 | |
101 | seq_puts(m: s, s: "completed\n" ); |
102 | list_for_each_entry(mdesc, &mchan->completed, node) |
103 | hidma_ll_chstats(s, llhndl: mchan->dmadev->lldev, tre_ch: mdesc->tre_ch); |
104 | |
105 | hidma_ll_devstats(s, llhndl: mchan->dmadev->lldev); |
106 | pm_runtime_mark_last_busy(dev: dmadev->ddev.dev); |
107 | pm_runtime_put_autosuspend(dev: dmadev->ddev.dev); |
108 | return 0; |
109 | } |
110 | |
111 | /* |
112 | * hidma_dma_show: display HIDMA device info |
113 | * |
114 | * Display the info for the current HIDMA device. |
115 | */ |
116 | static int hidma_dma_show(struct seq_file *s, void *unused) |
117 | { |
118 | struct hidma_dev *dmadev = s->private; |
119 | resource_size_t sz; |
120 | |
121 | seq_printf(m: s, fmt: "nr_descriptors=%d\n" , dmadev->nr_descriptors); |
122 | seq_printf(m: s, fmt: "dev_trca=%p\n" , &dmadev->dev_trca); |
123 | seq_printf(m: s, fmt: "dev_trca_phys=%pa\n" , &dmadev->trca_resource->start); |
124 | sz = resource_size(res: dmadev->trca_resource); |
125 | seq_printf(m: s, fmt: "dev_trca_size=%pa\n" , &sz); |
126 | seq_printf(m: s, fmt: "dev_evca=%p\n" , &dmadev->dev_evca); |
127 | seq_printf(m: s, fmt: "dev_evca_phys=%pa\n" , &dmadev->evca_resource->start); |
128 | sz = resource_size(res: dmadev->evca_resource); |
129 | seq_printf(m: s, fmt: "dev_evca_size=%pa\n" , &sz); |
130 | return 0; |
131 | } |
132 | |
133 | DEFINE_SHOW_ATTRIBUTE(hidma_chan); |
134 | DEFINE_SHOW_ATTRIBUTE(hidma_dma); |
135 | |
136 | void hidma_debug_uninit(struct hidma_dev *dmadev) |
137 | { |
138 | debugfs_remove_recursive(dentry: dmadev->debugfs); |
139 | } |
140 | |
141 | void hidma_debug_init(struct hidma_dev *dmadev) |
142 | { |
143 | int chidx = 0; |
144 | struct list_head *position = NULL; |
145 | struct dentry *dir; |
146 | |
147 | dmadev->debugfs = debugfs_create_dir(name: dev_name(dev: dmadev->ddev.dev), NULL); |
148 | |
149 | /* walk through the virtual channel list */ |
150 | list_for_each(position, &dmadev->ddev.channels) { |
151 | struct hidma_chan *chan; |
152 | |
153 | chan = list_entry(position, struct hidma_chan, |
154 | chan.device_node); |
155 | sprintf(buf: chan->dbg_name, fmt: "chan%d" , chidx); |
156 | dir = debugfs_create_dir(name: chan->dbg_name, |
157 | parent: dmadev->debugfs); |
158 | debugfs_create_file(name: "stats" , S_IRUGO, parent: dir, data: chan, |
159 | fops: &hidma_chan_fops); |
160 | chidx++; |
161 | } |
162 | |
163 | debugfs_create_file(name: "stats" , S_IRUGO, parent: dmadev->debugfs, data: dmadev, |
164 | fops: &hidma_dma_fops); |
165 | } |
166 | |