xref: /linux/drivers/accel/qaic/qaic_debugfs.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 /* Copyright (c) 2020, The Linux Foundation. All rights reserved. */
4 /* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
5 
6 #include <linux/debugfs.h>
7 #include <linux/device.h>
8 #include <linux/fs.h>
9 #include <linux/list.h>
10 #include <linux/mhi.h>
11 #include <linux/mutex.h>
12 #include <linux/overflow.h>
13 #include <linux/pci.h>
14 #include <linux/seq_file.h>
15 #include <linux/sprintf.h>
16 #include <linux/string.h>
17 #include <linux/types.h>
18 #include <linux/workqueue.h>
19 
20 #include "qaic.h"
21 #include "qaic_debugfs.h"
22 
23 #define BOOTLOG_POOL_SIZE		16
24 #define BOOTLOG_MSG_SIZE		512
25 #define QAIC_DBC_DIR_NAME		9
26 
27 struct bootlog_msg {
28 	/* Buffer for bootlog messages */
29 	char str[BOOTLOG_MSG_SIZE];
30 	/* Length of bootlog message */
31 	size_t len;
32 	/* Root struct of device, used to access device resources */
33 	struct qaic_device *qdev;
34 	/* Work struct to schedule work coming on QAIC_LOGGING channel */
35 	struct work_struct work;
36 };
37 
38 struct bootlog_page {
39 	/* Node in list of bootlog pages maintained by root device struct */
40 	struct list_head node;
41 	/* Total size of the buffer that holds the bootlogs. It is PAGE_SIZE */
42 	unsigned int size;
43 	/* Offset for the next bootlog */
44 	unsigned int offset;
45 };
46 
47 static int bootlog_show(struct seq_file *s, void *unused)
48 {
49 	struct bootlog_page *page;
50 	struct qaic_device *qdev;
51 	size_t len;
52 	void *log;
53 
54 	qdev = s->private;
55 	mutex_lock(&qdev->bootlog_mutex);
56 	list_for_each_entry(page, &qdev->bootlog, node) {
57 		log = page + 1;
58 		len = page->offset - sizeof(*page);
59 		seq_write(s, log, len);
60 	}
61 	mutex_unlock(&qdev->bootlog_mutex);
62 
63 	return 0;
64 }
65 
66 DEFINE_SHOW_ATTRIBUTE(bootlog);
67 
68 static int fifo_size_show(struct seq_file *s, void *unused)
69 {
70 	struct dma_bridge_chan *dbc = s->private;
71 
72 	seq_printf(s, "%u\n", dbc->nelem);
73 	return 0;
74 }
75 
76 DEFINE_SHOW_ATTRIBUTE(fifo_size);
77 
78 static int queued_show(struct seq_file *s, void *unused)
79 {
80 	struct dma_bridge_chan *dbc = s->private;
81 	u32 tail = 0, head = 0;
82 
83 	qaic_data_get_fifo_info(dbc, &head, &tail);
84 
85 	if (head == U32_MAX || tail == U32_MAX)
86 		seq_printf(s, "%u\n", 0);
87 	else if (head > tail)
88 		seq_printf(s, "%u\n", dbc->nelem - head + tail);
89 	else
90 		seq_printf(s, "%u\n", tail - head);
91 
92 	return 0;
93 }
94 
95 DEFINE_SHOW_ATTRIBUTE(queued);
96 
97 void qaic_debugfs_init(struct qaic_drm_device *qddev)
98 {
99 	struct qaic_device *qdev = qddev->qdev;
100 	struct dentry *debugfs_root;
101 	struct dentry *debugfs_dir;
102 	char name[QAIC_DBC_DIR_NAME];
103 	u32 i;
104 
105 	debugfs_root = to_drm(qddev)->debugfs_root;
106 
107 	debugfs_create_file("bootlog", 0400, debugfs_root, qdev, &bootlog_fops);
108 	/*
109 	 * 256 dbcs per device is likely the max we will ever see and lets static checking see a
110 	 * reasonable range.
111 	 */
112 	for (i = 0; i < qdev->num_dbc && i < 256; ++i) {
113 		snprintf(name, QAIC_DBC_DIR_NAME, "dbc%03u", i);
114 		debugfs_dir = debugfs_create_dir(name, debugfs_root);
115 		debugfs_create_file("fifo_size", 0400, debugfs_dir, &qdev->dbc[i], &fifo_size_fops);
116 		debugfs_create_file("queued", 0400, debugfs_dir, &qdev->dbc[i], &queued_fops);
117 	}
118 }
119 
120 static struct bootlog_page *alloc_bootlog_page(struct qaic_device *qdev)
121 {
122 	struct bootlog_page *page;
123 
124 	page = (struct bootlog_page *)devm_get_free_pages(&qdev->pdev->dev, GFP_KERNEL, 0);
125 	if (!page)
126 		return page;
127 
128 	page->size = PAGE_SIZE;
129 	page->offset = sizeof(*page);
130 	list_add_tail(&page->node, &qdev->bootlog);
131 
132 	return page;
133 }
134 
135 static int reset_bootlog(struct qaic_device *qdev)
136 {
137 	struct bootlog_page *page;
138 	struct bootlog_page *i;
139 
140 	mutex_lock(&qdev->bootlog_mutex);
141 	list_for_each_entry_safe(page, i, &qdev->bootlog, node) {
142 		list_del(&page->node);
143 		devm_free_pages(&qdev->pdev->dev, (unsigned long)page);
144 	}
145 
146 	page = alloc_bootlog_page(qdev);
147 	mutex_unlock(&qdev->bootlog_mutex);
148 	if (!page)
149 		return -ENOMEM;
150 
151 	return 0;
152 }
153 
154 static void *bootlog_get_space(struct qaic_device *qdev, unsigned int size)
155 {
156 	struct bootlog_page *page;
157 
158 	page = list_last_entry(&qdev->bootlog, struct bootlog_page, node);
159 
160 	if (size_add(size, sizeof(*page)) > page->size)
161 		return NULL;
162 
163 	if (page->offset + size > page->size) {
164 		page = alloc_bootlog_page(qdev);
165 		if (!page)
166 			return NULL;
167 	}
168 
169 	return (void *)page + page->offset;
170 }
171 
172 static void bootlog_commit(struct qaic_device *qdev, unsigned int size)
173 {
174 	struct bootlog_page *page;
175 
176 	page = list_last_entry(&qdev->bootlog, struct bootlog_page, node);
177 
178 	page->offset += size;
179 }
180 
181 static void bootlog_log(struct work_struct *work)
182 {
183 	struct bootlog_msg *msg = container_of(work, struct bootlog_msg, work);
184 	struct qaic_device *qdev = msg->qdev;
185 	void *log;
186 
187 	mutex_lock(&qdev->bootlog_mutex);
188 	log = bootlog_get_space(qdev, msg->len);
189 	if (log) {
190 		memcpy(log, msg, msg->len);
191 		bootlog_commit(qdev, msg->len);
192 	}
193 	mutex_unlock(&qdev->bootlog_mutex);
194 
195 	if (mhi_queue_buf(qdev->bootlog_ch, DMA_FROM_DEVICE, msg, BOOTLOG_MSG_SIZE, MHI_EOT))
196 		devm_kfree(&qdev->pdev->dev, msg);
197 }
198 
199 static int qaic_bootlog_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id)
200 {
201 	struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev));
202 	struct bootlog_msg *msg;
203 	int i, ret;
204 
205 	qdev->bootlog_wq = alloc_ordered_workqueue("qaic_bootlog", 0);
206 	if (!qdev->bootlog_wq) {
207 		ret = -ENOMEM;
208 		goto out;
209 	}
210 
211 	ret = reset_bootlog(qdev);
212 	if (ret)
213 		goto destroy_workqueue;
214 
215 	ret = mhi_prepare_for_transfer(mhi_dev);
216 	if (ret)
217 		goto destroy_workqueue;
218 
219 	dev_set_drvdata(&mhi_dev->dev, qdev);
220 	qdev->bootlog_ch = mhi_dev;
221 
222 	for (i = 0; i < BOOTLOG_POOL_SIZE; i++) {
223 		msg = devm_kzalloc(&qdev->pdev->dev, sizeof(*msg), GFP_KERNEL);
224 		if (!msg) {
225 			ret = -ENOMEM;
226 			goto mhi_unprepare;
227 		}
228 
229 		msg->qdev = qdev;
230 		INIT_WORK(&msg->work, bootlog_log);
231 
232 		ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, msg, BOOTLOG_MSG_SIZE, MHI_EOT);
233 		if (ret)
234 			goto mhi_unprepare;
235 	}
236 
237 	return 0;
238 
239 mhi_unprepare:
240 	mhi_unprepare_from_transfer(mhi_dev);
241 destroy_workqueue:
242 	destroy_workqueue(qdev->bootlog_wq);
243 out:
244 	return ret;
245 }
246 
247 static void qaic_bootlog_mhi_remove(struct mhi_device *mhi_dev)
248 {
249 	struct qaic_device *qdev;
250 
251 	qdev = dev_get_drvdata(&mhi_dev->dev);
252 
253 	mhi_unprepare_from_transfer(qdev->bootlog_ch);
254 	destroy_workqueue(qdev->bootlog_wq);
255 	qdev->bootlog_ch = NULL;
256 }
257 
258 static void qaic_bootlog_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
259 {
260 }
261 
262 static void qaic_bootlog_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
263 {
264 	struct qaic_device *qdev = dev_get_drvdata(&mhi_dev->dev);
265 	struct bootlog_msg *msg = mhi_result->buf_addr;
266 	int status = mhi_result->transaction_status;
267 
268 	if (status && status != -EOVERFLOW) {
269 		devm_kfree(&qdev->pdev->dev, msg);
270 		return;
271 	}
272 
273 	msg->len = mhi_result->bytes_xferd;
274 
275 	/* Exclude trailing null to normalize AIC100/AIC200 line endings */
276 	if (msg->len && msg->str[msg->len - 1] == '\0')
277 		msg->len--;
278 
279 	queue_work(qdev->bootlog_wq, &msg->work);
280 }
281 
282 static const struct mhi_device_id qaic_bootlog_mhi_match_table[] = {
283 	{ .chan = "QAIC_LOGGING", },
284 	{},
285 };
286 
287 static struct mhi_driver qaic_bootlog_mhi_driver = {
288 	.id_table = qaic_bootlog_mhi_match_table,
289 	.remove = qaic_bootlog_mhi_remove,
290 	.probe = qaic_bootlog_mhi_probe,
291 	.ul_xfer_cb = qaic_bootlog_mhi_ul_xfer_cb,
292 	.dl_xfer_cb = qaic_bootlog_mhi_dl_xfer_cb,
293 	.driver = {
294 		.name = "qaic_bootlog",
295 	},
296 };
297 
298 int qaic_bootlog_register(void)
299 {
300 	return mhi_driver_register(&qaic_bootlog_mhi_driver);
301 }
302 
303 void qaic_bootlog_unregister(void)
304 {
305 	mhi_driver_unregister(&qaic_bootlog_mhi_driver);
306 }
307