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