Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 463 lines 11 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2015 ST Microelectronics 4 * 5 * Author: Lee Jones <lee.jones@linaro.org> 6 */ 7 8#include <linux/debugfs.h> 9#include <linux/err.h> 10#include <linux/fs.h> 11#include <linux/io.h> 12#include <linux/kernel.h> 13#include <linux/mailbox_client.h> 14#include <linux/module.h> 15#include <linux/mutex.h> 16#include <linux/of.h> 17#include <linux/platform_device.h> 18#include <linux/poll.h> 19#include <linux/slab.h> 20#include <linux/spinlock.h> 21#include <linux/uaccess.h> 22#include <linux/sched/signal.h> 23 24#define MBOX_MAX_SIG_LEN 8 25#define MBOX_MAX_MSG_LEN 128 26#define MBOX_BYTES_PER_LINE 16 27#define MBOX_HEXDUMP_LINE_LEN ((MBOX_BYTES_PER_LINE * 4) + 2) 28#define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ 29 (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) 30 31struct mbox_test_device { 32 struct device *dev; 33 void __iomem *tx_mmio; 34 void __iomem *rx_mmio; 35 struct mbox_chan *tx_channel; 36 struct mbox_chan *rx_channel; 37 char *rx_buffer; 38 char *signal; 39 char *message; 40 spinlock_t lock; 41 struct mutex mutex; 42 wait_queue_head_t waitq; 43 bool data_ready; 44 struct fasync_struct *async_queue; 45 struct dentry *root_debugfs_dir; 46}; 47 48static ssize_t mbox_test_signal_write(struct file *filp, 49 const char __user *userbuf, 50 size_t count, loff_t *ppos) 51{ 52 struct mbox_test_device *tdev = filp->private_data; 53 54 if (!tdev->tx_channel) { 55 dev_err(tdev->dev, "Channel cannot do Tx\n"); 56 return -EINVAL; 57 } 58 59 if (count > MBOX_MAX_SIG_LEN) { 60 dev_err(tdev->dev, 61 "Signal length %zd greater than max allowed %d\n", 62 count, MBOX_MAX_SIG_LEN); 63 return -EINVAL; 64 } 65 66 /* Only allocate memory if we need to */ 67 if (!tdev->signal) { 68 tdev->signal = kzalloc(MBOX_MAX_SIG_LEN, GFP_KERNEL); 69 if (!tdev->signal) 70 return -ENOMEM; 71 } 72 73 if (copy_from_user(tdev->signal, userbuf, count)) { 74 kfree(tdev->signal); 75 tdev->signal = NULL; 76 return -EFAULT; 77 } 78 79 return count; 80} 81 82static const struct file_operations mbox_test_signal_ops = { 83 .write = mbox_test_signal_write, 84 .open = simple_open, 85 .llseek = generic_file_llseek, 86}; 87 88static int mbox_test_message_fasync(int fd, struct file *filp, int on) 89{ 90 struct mbox_test_device *tdev = filp->private_data; 91 92 return fasync_helper(fd, filp, on, &tdev->async_queue); 93} 94 95static ssize_t mbox_test_message_write(struct file *filp, 96 const char __user *userbuf, 97 size_t count, loff_t *ppos) 98{ 99 struct mbox_test_device *tdev = filp->private_data; 100 char *message; 101 void *data; 102 int ret; 103 104 if (!tdev->tx_channel) { 105 dev_err(tdev->dev, "Channel cannot do Tx\n"); 106 return -EINVAL; 107 } 108 109 if (count > MBOX_MAX_MSG_LEN) { 110 dev_err(tdev->dev, 111 "Message length %zd greater than max allowed %d\n", 112 count, MBOX_MAX_MSG_LEN); 113 return -EINVAL; 114 } 115 116 message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL); 117 if (!message) 118 return -ENOMEM; 119 120 mutex_lock(&tdev->mutex); 121 122 tdev->message = message; 123 ret = copy_from_user(tdev->message, userbuf, count); 124 if (ret) { 125 ret = -EFAULT; 126 goto out; 127 } 128 129 /* 130 * A separate signal is only of use if there is 131 * MMIO to subsequently pass the message through 132 */ 133 if (tdev->tx_mmio && tdev->signal) { 134 print_hex_dump_bytes("Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS, 135 tdev->signal, MBOX_MAX_SIG_LEN); 136 137 data = tdev->signal; 138 } else 139 data = tdev->message; 140 141 print_hex_dump_bytes("Client: Sending: Message: ", DUMP_PREFIX_ADDRESS, 142 tdev->message, MBOX_MAX_MSG_LEN); 143 144 ret = mbox_send_message(tdev->tx_channel, data); 145 if (ret < 0) 146 dev_err(tdev->dev, "Failed to send message via mailbox\n"); 147 148out: 149 kfree(tdev->signal); 150 kfree(tdev->message); 151 tdev->signal = NULL; 152 153 mutex_unlock(&tdev->mutex); 154 155 return ret < 0 ? ret : count; 156} 157 158static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) 159{ 160 bool data_ready; 161 unsigned long flags; 162 163 spin_lock_irqsave(&tdev->lock, flags); 164 data_ready = tdev->data_ready; 165 spin_unlock_irqrestore(&tdev->lock, flags); 166 167 return data_ready; 168} 169 170static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, 171 size_t count, loff_t *ppos) 172{ 173 struct mbox_test_device *tdev = filp->private_data; 174 unsigned long flags; 175 char *touser, *ptr; 176 int l = 0; 177 int ret; 178 179 DECLARE_WAITQUEUE(wait, current); 180 181 touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL); 182 if (!touser) 183 return -ENOMEM; 184 185 if (!tdev->rx_channel) { 186 ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n"); 187 ret = simple_read_from_buffer(userbuf, count, ppos, 188 touser, ret); 189 goto kfree_err; 190 } 191 192 add_wait_queue(&tdev->waitq, &wait); 193 194 do { 195 __set_current_state(TASK_INTERRUPTIBLE); 196 197 if (mbox_test_message_data_ready(tdev)) 198 break; 199 200 if (filp->f_flags & O_NONBLOCK) { 201 ret = -EAGAIN; 202 goto waitq_err; 203 } 204 205 if (signal_pending(current)) { 206 ret = -ERESTARTSYS; 207 goto waitq_err; 208 } 209 schedule(); 210 211 } while (1); 212 213 spin_lock_irqsave(&tdev->lock, flags); 214 215 ptr = tdev->rx_buffer; 216 while (l < MBOX_HEXDUMP_MAX_LEN) { 217 hex_dump_to_buffer(ptr, 218 MBOX_BYTES_PER_LINE, 219 MBOX_BYTES_PER_LINE, 1, touser + l, 220 MBOX_HEXDUMP_LINE_LEN, true); 221 222 ptr += MBOX_BYTES_PER_LINE; 223 l += MBOX_HEXDUMP_LINE_LEN; 224 *(touser + (l - 1)) = '\n'; 225 } 226 *(touser + l) = '\0'; 227 228 memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); 229 tdev->data_ready = false; 230 231 spin_unlock_irqrestore(&tdev->lock, flags); 232 233 ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN); 234waitq_err: 235 __set_current_state(TASK_RUNNING); 236 remove_wait_queue(&tdev->waitq, &wait); 237kfree_err: 238 kfree(touser); 239 return ret; 240} 241 242static __poll_t 243mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait) 244{ 245 struct mbox_test_device *tdev = filp->private_data; 246 247 poll_wait(filp, &tdev->waitq, wait); 248 249 if (mbox_test_message_data_ready(tdev)) 250 return EPOLLIN | EPOLLRDNORM; 251 return 0; 252} 253 254static const struct file_operations mbox_test_message_ops = { 255 .write = mbox_test_message_write, 256 .read = mbox_test_message_read, 257 .fasync = mbox_test_message_fasync, 258 .poll = mbox_test_message_poll, 259 .open = simple_open, 260 .llseek = generic_file_llseek, 261}; 262 263static int mbox_test_add_debugfs(struct platform_device *pdev, 264 struct mbox_test_device *tdev) 265{ 266 if (!debugfs_initialized()) 267 return 0; 268 269 tdev->root_debugfs_dir = debugfs_create_dir(dev_name(&pdev->dev), NULL); 270 if (IS_ERR(tdev->root_debugfs_dir)) { 271 dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n"); 272 return -EINVAL; 273 } 274 275 debugfs_create_file("message", 0600, tdev->root_debugfs_dir, 276 tdev, &mbox_test_message_ops); 277 278 debugfs_create_file("signal", 0200, tdev->root_debugfs_dir, 279 tdev, &mbox_test_signal_ops); 280 281 return 0; 282} 283 284static void mbox_test_receive_message(struct mbox_client *client, void *message) 285{ 286 struct mbox_test_device *tdev = dev_get_drvdata(client->dev); 287 unsigned long flags; 288 289 spin_lock_irqsave(&tdev->lock, flags); 290 if (tdev->rx_mmio) { 291 memcpy_fromio(tdev->rx_buffer, tdev->rx_mmio, MBOX_MAX_MSG_LEN); 292 print_hex_dump_bytes("Client: Received [MMIO]: ", DUMP_PREFIX_ADDRESS, 293 tdev->rx_buffer, MBOX_MAX_MSG_LEN); 294 } else if (message) { 295 print_hex_dump_bytes("Client: Received [API]: ", DUMP_PREFIX_ADDRESS, 296 message, MBOX_MAX_MSG_LEN); 297 memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); 298 } 299 tdev->data_ready = true; 300 spin_unlock_irqrestore(&tdev->lock, flags); 301 302 wake_up_interruptible(&tdev->waitq); 303 304 kill_fasync(&tdev->async_queue, SIGIO, POLL_IN); 305} 306 307static void mbox_test_prepare_message(struct mbox_client *client, void *message) 308{ 309 struct mbox_test_device *tdev = dev_get_drvdata(client->dev); 310 311 if (tdev->tx_mmio) { 312 if (tdev->signal) 313 memcpy_toio(tdev->tx_mmio, tdev->message, MBOX_MAX_MSG_LEN); 314 else 315 memcpy_toio(tdev->tx_mmio, message, MBOX_MAX_MSG_LEN); 316 } 317} 318 319static void mbox_test_message_sent(struct mbox_client *client, 320 void *message, int r) 321{ 322 if (r) 323 dev_warn(client->dev, 324 "Client: Message could not be sent: %d\n", r); 325 else 326 dev_info(client->dev, 327 "Client: Message sent\n"); 328} 329 330static struct mbox_chan * 331mbox_test_request_channel(struct platform_device *pdev, const char *name) 332{ 333 struct mbox_client *client; 334 struct mbox_chan *channel; 335 336 client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); 337 if (!client) 338 return NULL; 339 340 client->dev = &pdev->dev; 341 client->rx_callback = mbox_test_receive_message; 342 client->tx_prepare = mbox_test_prepare_message; 343 client->tx_done = mbox_test_message_sent; 344 client->tx_block = true; 345 client->knows_txdone = false; 346 client->tx_tout = 500; 347 348 channel = mbox_request_channel_byname(client, name); 349 if (IS_ERR(channel)) { 350 dev_warn(&pdev->dev, "Failed to request %s channel\n", name); 351 return NULL; 352 } 353 354 return channel; 355} 356 357static void __iomem *mbox_test_ioremap(struct platform_device *pdev, unsigned int res_num) 358{ 359 struct resource *res; 360 void __iomem *mmio; 361 362 res = platform_get_resource(pdev, IORESOURCE_MEM, res_num); 363 if (!res) 364 return NULL; 365 366 mmio = devm_ioremap_resource(&pdev->dev, res); 367 if (PTR_ERR(mmio) == -EBUSY) { 368 dev_info(&pdev->dev, "trying workaround with plain ioremap\n"); 369 return devm_ioremap(&pdev->dev, res->start, resource_size(res)); 370 } 371 372 return IS_ERR(mmio) ? NULL : mmio; 373} 374 375static int mbox_test_probe(struct platform_device *pdev) 376{ 377 struct mbox_test_device *tdev; 378 int ret; 379 380 tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); 381 if (!tdev) 382 return -ENOMEM; 383 384 tdev->dev = &pdev->dev; 385 spin_lock_init(&tdev->lock); 386 mutex_init(&tdev->mutex); 387 init_waitqueue_head(&tdev->waitq); 388 platform_set_drvdata(pdev, tdev); 389 390 /* It's okay for MMIO to be NULL */ 391 tdev->tx_mmio = mbox_test_ioremap(pdev, 0); 392 393 /* If specified, second reg entry is Rx MMIO */ 394 tdev->rx_mmio = mbox_test_ioremap(pdev, 1); 395 if (!tdev->rx_mmio) 396 tdev->rx_mmio = tdev->tx_mmio; 397 398 tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); 399 tdev->rx_channel = mbox_test_request_channel(pdev, "rx"); 400 401 if (!tdev->tx_channel && !tdev->rx_channel) 402 return -EPROBE_DEFER; 403 404 /* If Rx is not specified but has Rx MMIO, then Rx = Tx */ 405 if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) 406 tdev->rx_channel = tdev->tx_channel; 407 408 if (tdev->rx_channel) { 409 tdev->rx_buffer = devm_kzalloc(&pdev->dev, 410 MBOX_MAX_MSG_LEN, GFP_KERNEL); 411 if (!tdev->rx_buffer) { 412 ret = -ENOMEM; 413 goto err_free_chans; 414 } 415 } 416 417 ret = mbox_test_add_debugfs(pdev, tdev); 418 if (ret) 419 goto err_free_chans; 420 421 dev_info(&pdev->dev, "Successfully registered\n"); 422 423 return 0; 424 425err_free_chans: 426 if (tdev->tx_channel) 427 mbox_free_channel(tdev->tx_channel); 428 if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) 429 mbox_free_channel(tdev->rx_channel); 430 return ret; 431} 432 433static void mbox_test_remove(struct platform_device *pdev) 434{ 435 struct mbox_test_device *tdev = platform_get_drvdata(pdev); 436 437 debugfs_remove_recursive(tdev->root_debugfs_dir); 438 439 if (tdev->tx_channel) 440 mbox_free_channel(tdev->tx_channel); 441 if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) 442 mbox_free_channel(tdev->rx_channel); 443} 444 445static const struct of_device_id mbox_test_match[] = { 446 { .compatible = "mailbox-test" }, 447 {}, 448}; 449MODULE_DEVICE_TABLE(of, mbox_test_match); 450 451static struct platform_driver mbox_test_driver = { 452 .driver = { 453 .name = "mailbox_test", 454 .of_match_table = mbox_test_match, 455 }, 456 .probe = mbox_test_probe, 457 .remove = mbox_test_remove, 458}; 459module_platform_driver(mbox_test_driver); 460 461MODULE_DESCRIPTION("Generic Mailbox Testing Facility"); 462MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org"); 463MODULE_LICENSE("GPL v2");