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 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 67 DEFINE_SHOW_ATTRIBUTE(bootlog); 68 69 static int fifo_size_show(struct seq_file *s, void *unused) 70 { 71 struct dma_bridge_chan *dbc = s->private; 72 73 seq_printf(s, "%u\n", dbc->nelem); 74 return 0; 75 } 76 77 DEFINE_SHOW_ATTRIBUTE(fifo_size); 78 79 static int queued_show(struct seq_file *s, void *unused) 80 { 81 struct dma_bridge_chan *dbc = s->private; 82 u32 tail = 0, head = 0; 83 84 qaic_data_get_fifo_info(dbc, &head, &tail); 85 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); 92 93 return 0; 94 } 95 96 DEFINE_SHOW_ATTRIBUTE(queued); 97 98 void qaic_debugfs_init(struct qaic_drm_device *qddev) 99 { 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; 105 106 debugfs_root = to_drm(qddev)->debugfs_root; 107 108 debugfs_create_file("bootlog", 0400, debugfs_root, qdev, &bootlog_fops); 109 /* 110 * 256 dbcs per device is likely the max we will ever see and lets static checking see a 111 * reasonable range. 112 */ 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); 118 } 119 } 120 121 static struct bootlog_page *alloc_bootlog_page(struct qaic_device *qdev) 122 { 123 struct bootlog_page *page; 124 125 page = (struct bootlog_page *)devm_get_free_pages(&qdev->pdev->dev, GFP_KERNEL, 0); 126 if (!page) 127 return page; 128 129 page->size = PAGE_SIZE; 130 page->offset = sizeof(*page); 131 list_add_tail(&page->node, &qdev->bootlog); 132 133 return page; 134 } 135 136 static int reset_bootlog(struct qaic_device *qdev) 137 { 138 struct bootlog_page *page; 139 struct bootlog_page *i; 140 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); 145 } 146 147 page = alloc_bootlog_page(qdev); 148 mutex_unlock(&qdev->bootlog_mutex); 149 if (!page) 150 return -ENOMEM; 151 152 return 0; 153 } 154 155 static void *bootlog_get_space(struct qaic_device *qdev, unsigned int size) 156 { 157 struct bootlog_page *page; 158 159 page = list_last_entry(&qdev->bootlog, struct bootlog_page, node); 160 161 if (size_add(size, sizeof(*page)) > page->size) 162 return NULL; 163 164 if (page->offset + size > page->size) { 165 page = alloc_bootlog_page(qdev); 166 if (!page) 167 return NULL; 168 } 169 170 return (void *)page + page->offset; 171 } 172 173 static void bootlog_commit(struct qaic_device *qdev, unsigned int size) 174 { 175 struct bootlog_page *page; 176 177 page = list_last_entry(&qdev->bootlog, struct bootlog_page, node); 178 179 page->offset += size; 180 } 181 182 static void bootlog_log(struct work_struct *work) 183 { 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; 188 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); 194 } 195 mutex_unlock(&qdev->bootlog_mutex); 196 197 if (mhi_queue_buf(qdev->bootlog_ch, DMA_FROM_DEVICE, msg, BOOTLOG_MSG_SIZE, MHI_EOT)) 198 devm_kfree(&qdev->pdev->dev, msg); 199 } 200 201 static int qaic_bootlog_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) 202 { 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; 206 207 qdev->bootlog_wq = alloc_ordered_workqueue("qaic_bootlog", 0); 208 if (!qdev->bootlog_wq) { 209 ret = -ENOMEM; 210 goto out; 211 } 212 213 ret = reset_bootlog(qdev); 214 if (ret) 215 goto destroy_workqueue; 216 217 ret = mhi_prepare_for_transfer(mhi_dev); 218 if (ret) 219 goto destroy_workqueue; 220 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; 226 } 227 228 msg->qdev = qdev; 229 INIT_WORK(&msg->work, bootlog_log); 230 231 ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, msg, BOOTLOG_MSG_SIZE, MHI_EOT); 232 if (ret) 233 goto mhi_unprepare; 234 } 235 236 dev_set_drvdata(&mhi_dev->dev, qdev); 237 qdev->bootlog_ch = mhi_dev; 238 return 0; 239 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; 247 } 248 249 static void qaic_bootlog_mhi_remove(struct mhi_device *mhi_dev) 250 { 251 struct qaic_device *qdev; 252 253 qdev = dev_get_drvdata(&mhi_dev->dev); 254 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; 259 } 260 261 static void qaic_bootlog_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) 262 { 263 } 264 265 static void qaic_bootlog_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) 266 { 267 struct qaic_device *qdev = dev_get_drvdata(&mhi_dev->dev); 268 struct bootlog_msg *msg = mhi_result->buf_addr; 269 270 if (mhi_result->transaction_status) { 271 devm_kfree(&qdev->pdev->dev, msg); 272 return; 273 } 274 275 /* Force a null at the end of the transferred string */ 276 msg->str[mhi_result->bytes_xferd - 1] = 0; 277 278 queue_work(qdev->bootlog_wq, &msg->work); 279 } 280 281 static const struct mhi_device_id qaic_bootlog_mhi_match_table[] = { 282 { .chan = "QAIC_LOGGING", }, 283 {}, 284 }; 285 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", 294 }, 295 }; 296 297 int qaic_bootlog_register(void) 298 { 299 return mhi_driver_register(&qaic_bootlog_mhi_driver); 300 } 301 302 void qaic_bootlog_unregister(void) 303 { 304 mhi_driver_unregister(&qaic_bootlog_mhi_driver); 305 } 306