xref: /linux/drivers/accel/qaic/qaic_debugfs.c (revision db5d28c0bfe566908719bec8e25443aabecbb802)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 /* Copyright (c) 2020, The Linux Foundation. All rights reserved. */
4 /* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
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 	/* Root struct of device, used to access device resources */
31 	struct qaic_device *qdev;
32 	/* Work struct to schedule work coming on QAIC_LOGGING channel */
33 	struct work_struct work;
34 };
35 
36 struct bootlog_page {
37 	/* Node in list of bootlog pages maintained by root device struct */
38 	struct list_head node;
39 	/* Total size of the buffer that holds the bootlogs. It is PAGE_SIZE */
40 	unsigned int size;
41 	/* Offset for the next bootlog */
42 	unsigned int offset;
43 };
44 
bootlog_show(struct seq_file * s,void * unused)45 static int bootlog_show(struct seq_file *s, void *unused)
46 {
47 	struct bootlog_page *page;
48 	struct qaic_device *qdev;
49 	void *page_end;
50 	void *log;
51 
52 	qdev = s->private;
53 	mutex_lock(&qdev->bootlog_mutex);
54 	list_for_each_entry(page, &qdev->bootlog, node) {
55 		log = page + 1;
56 		page_end = (void *)page + page->offset;
57 		while (log < page_end) {
58 			seq_printf(s, "%s", (char *)log);
59 			log += strlen(log) + 1;
60 		}
61 	}
62 	mutex_unlock(&qdev->bootlog_mutex);
63 
64 	return 0;
65 }
66 
bootlog_fops_open(struct inode * inode,struct file * file)67 static int bootlog_fops_open(struct inode *inode, struct file *file)
68 {
69 	return single_open(file, bootlog_show, inode->i_private);
70 }
71 
72 static const struct file_operations bootlog_fops = {
73 	.owner = THIS_MODULE,
74 	.open = bootlog_fops_open,
75 	.read = seq_read,
76 	.llseek = seq_lseek,
77 	.release = single_release,
78 };
79 
read_dbc_fifo_size(struct seq_file * s,void * unused)80 static int read_dbc_fifo_size(struct seq_file *s, void *unused)
81 {
82 	struct dma_bridge_chan *dbc = s->private;
83 
84 	seq_printf(s, "%u\n", dbc->nelem);
85 	return 0;
86 }
87 
fifo_size_open(struct inode * inode,struct file * file)88 static int fifo_size_open(struct inode *inode, struct file *file)
89 {
90 	return single_open(file, read_dbc_fifo_size, inode->i_private);
91 }
92 
93 static const struct file_operations fifo_size_fops = {
94 	.owner = THIS_MODULE,
95 	.open = fifo_size_open,
96 	.read = seq_read,
97 	.llseek = seq_lseek,
98 	.release = single_release,
99 };
100 
read_dbc_queued(struct seq_file * s,void * unused)101 static int read_dbc_queued(struct seq_file *s, void *unused)
102 {
103 	struct dma_bridge_chan *dbc = s->private;
104 	u32 tail = 0, head = 0;
105 
106 	qaic_data_get_fifo_info(dbc, &head, &tail);
107 
108 	if (head == U32_MAX || tail == U32_MAX)
109 		seq_printf(s, "%u\n", 0);
110 	else if (head > tail)
111 		seq_printf(s, "%u\n", dbc->nelem - head + tail);
112 	else
113 		seq_printf(s, "%u\n", tail - head);
114 
115 	return 0;
116 }
117 
queued_open(struct inode * inode,struct file * file)118 static int queued_open(struct inode *inode, struct file *file)
119 {
120 	return single_open(file, read_dbc_queued, inode->i_private);
121 }
122 
123 static const struct file_operations queued_fops = {
124 	.owner = THIS_MODULE,
125 	.open = queued_open,
126 	.read = seq_read,
127 	.llseek = seq_lseek,
128 	.release = single_release,
129 };
130 
qaic_debugfs_init(struct qaic_drm_device * qddev)131 void qaic_debugfs_init(struct qaic_drm_device *qddev)
132 {
133 	struct qaic_device *qdev = qddev->qdev;
134 	struct dentry *debugfs_root;
135 	struct dentry *debugfs_dir;
136 	char name[QAIC_DBC_DIR_NAME];
137 	u32 i;
138 
139 	debugfs_root = to_drm(qddev)->debugfs_root;
140 
141 	debugfs_create_file("bootlog", 0400, debugfs_root, qdev, &bootlog_fops);
142 	/*
143 	 * 256 dbcs per device is likely the max we will ever see and lets static checking see a
144 	 * reasonable range.
145 	 */
146 	for (i = 0; i < qdev->num_dbc && i < 256; ++i) {
147 		snprintf(name, QAIC_DBC_DIR_NAME, "dbc%03u", i);
148 		debugfs_dir = debugfs_create_dir(name, debugfs_root);
149 		debugfs_create_file("fifo_size", 0400, debugfs_dir, &qdev->dbc[i], &fifo_size_fops);
150 		debugfs_create_file("queued", 0400, debugfs_dir, &qdev->dbc[i], &queued_fops);
151 	}
152 }
153 
alloc_bootlog_page(struct qaic_device * qdev)154 static struct bootlog_page *alloc_bootlog_page(struct qaic_device *qdev)
155 {
156 	struct bootlog_page *page;
157 
158 	page = (struct bootlog_page *)devm_get_free_pages(&qdev->pdev->dev, GFP_KERNEL, 0);
159 	if (!page)
160 		return page;
161 
162 	page->size = PAGE_SIZE;
163 	page->offset = sizeof(*page);
164 	list_add_tail(&page->node, &qdev->bootlog);
165 
166 	return page;
167 }
168 
reset_bootlog(struct qaic_device * qdev)169 static int reset_bootlog(struct qaic_device *qdev)
170 {
171 	struct bootlog_page *page;
172 	struct bootlog_page *i;
173 
174 	mutex_lock(&qdev->bootlog_mutex);
175 	list_for_each_entry_safe(page, i, &qdev->bootlog, node) {
176 		list_del(&page->node);
177 		devm_free_pages(&qdev->pdev->dev, (unsigned long)page);
178 	}
179 
180 	page = alloc_bootlog_page(qdev);
181 	mutex_unlock(&qdev->bootlog_mutex);
182 	if (!page)
183 		return -ENOMEM;
184 
185 	return 0;
186 }
187 
bootlog_get_space(struct qaic_device * qdev,unsigned int size)188 static void *bootlog_get_space(struct qaic_device *qdev, unsigned int size)
189 {
190 	struct bootlog_page *page;
191 
192 	page = list_last_entry(&qdev->bootlog, struct bootlog_page, node);
193 
194 	if (size_add(size, sizeof(*page)) > page->size)
195 		return NULL;
196 
197 	if (page->offset + size > page->size) {
198 		page = alloc_bootlog_page(qdev);
199 		if (!page)
200 			return NULL;
201 	}
202 
203 	return (void *)page + page->offset;
204 }
205 
bootlog_commit(struct qaic_device * qdev,unsigned int size)206 static void bootlog_commit(struct qaic_device *qdev, unsigned int size)
207 {
208 	struct bootlog_page *page;
209 
210 	page = list_last_entry(&qdev->bootlog, struct bootlog_page, node);
211 
212 	page->offset += size;
213 }
214 
bootlog_log(struct work_struct * work)215 static void bootlog_log(struct work_struct *work)
216 {
217 	struct bootlog_msg *msg = container_of(work, struct bootlog_msg, work);
218 	unsigned int len = strlen(msg->str) + 1;
219 	struct qaic_device *qdev = msg->qdev;
220 	void *log;
221 
222 	mutex_lock(&qdev->bootlog_mutex);
223 	log = bootlog_get_space(qdev, len);
224 	if (log) {
225 		memcpy(log, msg, len);
226 		bootlog_commit(qdev, len);
227 	}
228 	mutex_unlock(&qdev->bootlog_mutex);
229 
230 	if (mhi_queue_buf(qdev->bootlog_ch, DMA_FROM_DEVICE, msg, BOOTLOG_MSG_SIZE, MHI_EOT))
231 		devm_kfree(&qdev->pdev->dev, msg);
232 }
233 
qaic_bootlog_mhi_probe(struct mhi_device * mhi_dev,const struct mhi_device_id * id)234 static int qaic_bootlog_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id)
235 {
236 	struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev));
237 	struct bootlog_msg *msg;
238 	int i, ret;
239 
240 	qdev->bootlog_wq = alloc_ordered_workqueue("qaic_bootlog", 0);
241 	if (!qdev->bootlog_wq) {
242 		ret = -ENOMEM;
243 		goto out;
244 	}
245 
246 	ret = reset_bootlog(qdev);
247 	if (ret)
248 		goto destroy_workqueue;
249 
250 	ret = mhi_prepare_for_transfer(mhi_dev);
251 	if (ret)
252 		goto destroy_workqueue;
253 
254 	for (i = 0; i < BOOTLOG_POOL_SIZE; i++) {
255 		msg = devm_kzalloc(&qdev->pdev->dev, sizeof(*msg), GFP_KERNEL);
256 		if (!msg) {
257 			ret = -ENOMEM;
258 			goto mhi_unprepare;
259 		}
260 
261 		msg->qdev = qdev;
262 		INIT_WORK(&msg->work, bootlog_log);
263 
264 		ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, msg, BOOTLOG_MSG_SIZE, MHI_EOT);
265 		if (ret)
266 			goto mhi_unprepare;
267 	}
268 
269 	dev_set_drvdata(&mhi_dev->dev, qdev);
270 	qdev->bootlog_ch = mhi_dev;
271 	return 0;
272 
273 mhi_unprepare:
274 	mhi_unprepare_from_transfer(mhi_dev);
275 destroy_workqueue:
276 	flush_workqueue(qdev->bootlog_wq);
277 	destroy_workqueue(qdev->bootlog_wq);
278 out:
279 	return ret;
280 }
281 
qaic_bootlog_mhi_remove(struct mhi_device * mhi_dev)282 static void qaic_bootlog_mhi_remove(struct mhi_device *mhi_dev)
283 {
284 	struct qaic_device *qdev;
285 
286 	qdev = dev_get_drvdata(&mhi_dev->dev);
287 
288 	mhi_unprepare_from_transfer(qdev->bootlog_ch);
289 	flush_workqueue(qdev->bootlog_wq);
290 	destroy_workqueue(qdev->bootlog_wq);
291 	qdev->bootlog_ch = NULL;
292 }
293 
qaic_bootlog_mhi_ul_xfer_cb(struct mhi_device * mhi_dev,struct mhi_result * mhi_result)294 static void qaic_bootlog_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
295 {
296 }
297 
qaic_bootlog_mhi_dl_xfer_cb(struct mhi_device * mhi_dev,struct mhi_result * mhi_result)298 static void qaic_bootlog_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
299 {
300 	struct qaic_device *qdev = dev_get_drvdata(&mhi_dev->dev);
301 	struct bootlog_msg *msg = mhi_result->buf_addr;
302 
303 	if (mhi_result->transaction_status) {
304 		devm_kfree(&qdev->pdev->dev, msg);
305 		return;
306 	}
307 
308 	/* Force a null at the end of the transferred string */
309 	msg->str[mhi_result->bytes_xferd - 1] = 0;
310 
311 	queue_work(qdev->bootlog_wq, &msg->work);
312 }
313 
314 static const struct mhi_device_id qaic_bootlog_mhi_match_table[] = {
315 	{ .chan = "QAIC_LOGGING", },
316 	{},
317 };
318 
319 static struct mhi_driver qaic_bootlog_mhi_driver = {
320 	.id_table = qaic_bootlog_mhi_match_table,
321 	.remove = qaic_bootlog_mhi_remove,
322 	.probe = qaic_bootlog_mhi_probe,
323 	.ul_xfer_cb = qaic_bootlog_mhi_ul_xfer_cb,
324 	.dl_xfer_cb = qaic_bootlog_mhi_dl_xfer_cb,
325 	.driver = {
326 		.name = "qaic_bootlog",
327 	},
328 };
329 
qaic_bootlog_register(void)330 int qaic_bootlog_register(void)
331 {
332 	return mhi_driver_register(&qaic_bootlog_mhi_driver);
333 }
334 
qaic_bootlog_unregister(void)335 void qaic_bootlog_unregister(void)
336 {
337 	mhi_driver_unregister(&qaic_bootlog_mhi_driver);
338 }
339