Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / accel / qaic / qaic_debugfs.c
blobba0cf2f94732cc6178abeaeab40adf6eb830ad19
1 // SPDX-License-Identifier: GPL-2.0-only
3 /* Copyright (c) 2020, The Linux Foundation. All rights reserved. */
4 /* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
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>
20 #include "qaic.h"
21 #include "qaic_debugfs.h"
23 #define BOOTLOG_POOL_SIZE 16
24 #define BOOTLOG_MSG_SIZE 512
25 #define QAIC_DBC_DIR_NAME 9
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;
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;
45 static int bootlog_show(struct seq_file *s, void *unused)
47 struct bootlog_page *page;
48 struct qaic_device *qdev;
49 void *page_end;
50 void *log;
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;
62 mutex_unlock(&qdev->bootlog_mutex);
64 return 0;
67 DEFINE_SHOW_ATTRIBUTE(bootlog);
69 static int fifo_size_show(struct seq_file *s, void *unused)
71 struct dma_bridge_chan *dbc = s->private;
73 seq_printf(s, "%u\n", dbc->nelem);
74 return 0;
77 DEFINE_SHOW_ATTRIBUTE(fifo_size);
79 static int queued_show(struct seq_file *s, void *unused)
81 struct dma_bridge_chan *dbc = s->private;
82 u32 tail = 0, head = 0;
84 qaic_data_get_fifo_info(dbc, &head, &tail);
86 if (head == U32_MAX || tail == U32_MAX)
87 seq_printf(s, "%u\n", 0);
88 else if (head > tail)
89 seq_printf(s, "%u\n", dbc->nelem - head + tail);
90 else
91 seq_printf(s, "%u\n", tail - head);
93 return 0;
96 DEFINE_SHOW_ATTRIBUTE(queued);
98 void qaic_debugfs_init(struct qaic_drm_device *qddev)
100 struct qaic_device *qdev = qddev->qdev;
101 struct dentry *debugfs_root;
102 struct dentry *debugfs_dir;
103 char name[QAIC_DBC_DIR_NAME];
104 u32 i;
106 debugfs_root = to_drm(qddev)->debugfs_root;
108 debugfs_create_file("bootlog", 0400, debugfs_root, qdev, &bootlog_fops);
110 * 256 dbcs per device is likely the max we will ever see and lets static checking see a
111 * reasonable range.
113 for (i = 0; i < qdev->num_dbc && i < 256; ++i) {
114 snprintf(name, QAIC_DBC_DIR_NAME, "dbc%03u", i);
115 debugfs_dir = debugfs_create_dir(name, debugfs_root);
116 debugfs_create_file("fifo_size", 0400, debugfs_dir, &qdev->dbc[i], &fifo_size_fops);
117 debugfs_create_file("queued", 0400, debugfs_dir, &qdev->dbc[i], &queued_fops);
121 static struct bootlog_page *alloc_bootlog_page(struct qaic_device *qdev)
123 struct bootlog_page *page;
125 page = (struct bootlog_page *)devm_get_free_pages(&qdev->pdev->dev, GFP_KERNEL, 0);
126 if (!page)
127 return page;
129 page->size = PAGE_SIZE;
130 page->offset = sizeof(*page);
131 list_add_tail(&page->node, &qdev->bootlog);
133 return page;
136 static int reset_bootlog(struct qaic_device *qdev)
138 struct bootlog_page *page;
139 struct bootlog_page *i;
141 mutex_lock(&qdev->bootlog_mutex);
142 list_for_each_entry_safe(page, i, &qdev->bootlog, node) {
143 list_del(&page->node);
144 devm_free_pages(&qdev->pdev->dev, (unsigned long)page);
147 page = alloc_bootlog_page(qdev);
148 mutex_unlock(&qdev->bootlog_mutex);
149 if (!page)
150 return -ENOMEM;
152 return 0;
155 static void *bootlog_get_space(struct qaic_device *qdev, unsigned int size)
157 struct bootlog_page *page;
159 page = list_last_entry(&qdev->bootlog, struct bootlog_page, node);
161 if (size_add(size, sizeof(*page)) > page->size)
162 return NULL;
164 if (page->offset + size > page->size) {
165 page = alloc_bootlog_page(qdev);
166 if (!page)
167 return NULL;
170 return (void *)page + page->offset;
173 static void bootlog_commit(struct qaic_device *qdev, unsigned int size)
175 struct bootlog_page *page;
177 page = list_last_entry(&qdev->bootlog, struct bootlog_page, node);
179 page->offset += size;
182 static void bootlog_log(struct work_struct *work)
184 struct bootlog_msg *msg = container_of(work, struct bootlog_msg, work);
185 unsigned int len = strlen(msg->str) + 1;
186 struct qaic_device *qdev = msg->qdev;
187 void *log;
189 mutex_lock(&qdev->bootlog_mutex);
190 log = bootlog_get_space(qdev, len);
191 if (log) {
192 memcpy(log, msg, len);
193 bootlog_commit(qdev, len);
195 mutex_unlock(&qdev->bootlog_mutex);
197 if (mhi_queue_buf(qdev->bootlog_ch, DMA_FROM_DEVICE, msg, BOOTLOG_MSG_SIZE, MHI_EOT))
198 devm_kfree(&qdev->pdev->dev, msg);
201 static int qaic_bootlog_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id)
203 struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev));
204 struct bootlog_msg *msg;
205 int i, ret;
207 qdev->bootlog_wq = alloc_ordered_workqueue("qaic_bootlog", 0);
208 if (!qdev->bootlog_wq) {
209 ret = -ENOMEM;
210 goto out;
213 ret = reset_bootlog(qdev);
214 if (ret)
215 goto destroy_workqueue;
217 ret = mhi_prepare_for_transfer(mhi_dev);
218 if (ret)
219 goto destroy_workqueue;
221 for (i = 0; i < BOOTLOG_POOL_SIZE; i++) {
222 msg = devm_kzalloc(&qdev->pdev->dev, sizeof(*msg), GFP_KERNEL);
223 if (!msg) {
224 ret = -ENOMEM;
225 goto mhi_unprepare;
228 msg->qdev = qdev;
229 INIT_WORK(&msg->work, bootlog_log);
231 ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, msg, BOOTLOG_MSG_SIZE, MHI_EOT);
232 if (ret)
233 goto mhi_unprepare;
236 dev_set_drvdata(&mhi_dev->dev, qdev);
237 qdev->bootlog_ch = mhi_dev;
238 return 0;
240 mhi_unprepare:
241 mhi_unprepare_from_transfer(mhi_dev);
242 destroy_workqueue:
243 flush_workqueue(qdev->bootlog_wq);
244 destroy_workqueue(qdev->bootlog_wq);
245 out:
246 return ret;
249 static void qaic_bootlog_mhi_remove(struct mhi_device *mhi_dev)
251 struct qaic_device *qdev;
253 qdev = dev_get_drvdata(&mhi_dev->dev);
255 mhi_unprepare_from_transfer(qdev->bootlog_ch);
256 flush_workqueue(qdev->bootlog_wq);
257 destroy_workqueue(qdev->bootlog_wq);
258 qdev->bootlog_ch = NULL;
261 static void qaic_bootlog_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
265 static void qaic_bootlog_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
267 struct qaic_device *qdev = dev_get_drvdata(&mhi_dev->dev);
268 struct bootlog_msg *msg = mhi_result->buf_addr;
270 if (mhi_result->transaction_status) {
271 devm_kfree(&qdev->pdev->dev, msg);
272 return;
275 /* Force a null at the end of the transferred string */
276 msg->str[mhi_result->bytes_xferd - 1] = 0;
278 queue_work(qdev->bootlog_wq, &msg->work);
281 static const struct mhi_device_id qaic_bootlog_mhi_match_table[] = {
282 { .chan = "QAIC_LOGGING", },
286 static struct mhi_driver qaic_bootlog_mhi_driver = {
287 .id_table = qaic_bootlog_mhi_match_table,
288 .remove = qaic_bootlog_mhi_remove,
289 .probe = qaic_bootlog_mhi_probe,
290 .ul_xfer_cb = qaic_bootlog_mhi_ul_xfer_cb,
291 .dl_xfer_cb = qaic_bootlog_mhi_dl_xfer_cb,
292 .driver = {
293 .name = "qaic_bootlog",
297 int qaic_bootlog_register(void)
299 return mhi_driver_register(&qaic_bootlog_mhi_driver);
302 void qaic_bootlog_unregister(void)
304 mhi_driver_unregister(&qaic_bootlog_mhi_driver);