2 * Copyright (C) 2015 ST Microelectronics
4 * Author: Lee Jones <lee.jones@linaro.org>
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.
12 #include <linux/debugfs.h>
13 #include <linux/err.h>
15 #include <linux/kernel.h>
16 #include <linux/mailbox_client.h>
17 #include <linux/module.h>
19 #include <linux/platform_device.h>
20 #include <linux/slab.h>
21 #include <linux/uaccess.h>
23 #define MBOX_MAX_SIG_LEN 8
24 #define MBOX_MAX_MSG_LEN 128
25 #define MBOX_BYTES_PER_LINE 16
26 #define MBOX_HEXDUMP_LINE_LEN ((MBOX_BYTES_PER_LINE * 4) + 2)
27 #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \
28 (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
30 static struct dentry
*root_debugfs_dir
;
32 struct mbox_test_device
{
35 struct mbox_chan
*tx_channel
;
36 struct mbox_chan
*rx_channel
;
43 static ssize_t
mbox_test_signal_write(struct file
*filp
,
44 const char __user
*userbuf
,
45 size_t count
, loff_t
*ppos
)
47 struct mbox_test_device
*tdev
= filp
->private_data
;
50 if (!tdev
->tx_channel
) {
51 dev_err(tdev
->dev
, "Channel cannot do Tx\n");
55 if (count
> MBOX_MAX_SIG_LEN
) {
57 "Signal length %zd greater than max allowed %d\n",
58 count
, MBOX_MAX_SIG_LEN
);
62 tdev
->signal
= kzalloc(MBOX_MAX_SIG_LEN
, GFP_KERNEL
);
66 ret
= copy_from_user(tdev
->signal
, userbuf
, count
);
72 return ret
< 0 ? ret
: count
;
75 static const struct file_operations mbox_test_signal_ops
= {
76 .write
= mbox_test_signal_write
,
78 .llseek
= generic_file_llseek
,
81 static ssize_t
mbox_test_message_write(struct file
*filp
,
82 const char __user
*userbuf
,
83 size_t count
, loff_t
*ppos
)
85 struct mbox_test_device
*tdev
= filp
->private_data
;
89 if (!tdev
->tx_channel
) {
90 dev_err(tdev
->dev
, "Channel cannot do Tx\n");
94 if (count
> MBOX_MAX_MSG_LEN
) {
96 "Message length %zd greater than max allowed %d\n",
97 count
, MBOX_MAX_MSG_LEN
);
101 tdev
->message
= kzalloc(MBOX_MAX_MSG_LEN
, GFP_KERNEL
);
105 ret
= copy_from_user(tdev
->message
, userbuf
, count
);
112 * A separate signal is only of use if there is
113 * MMIO to subsequently pass the message through
115 if (tdev
->mmio
&& tdev
->signal
) {
116 print_hex_dump(KERN_INFO
, "Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS
,
117 MBOX_BYTES_PER_LINE
, 1, tdev
->signal
, MBOX_MAX_SIG_LEN
, true);
121 data
= tdev
->message
;
123 print_hex_dump(KERN_INFO
, "Client: Sending: Message: ", DUMP_PREFIX_ADDRESS
,
124 MBOX_BYTES_PER_LINE
, 1, tdev
->message
, MBOX_MAX_MSG_LEN
, true);
126 ret
= mbox_send_message(tdev
->tx_channel
, data
);
128 dev_err(tdev
->dev
, "Failed to send message via mailbox\n");
132 kfree(tdev
->message
);
134 return ret
< 0 ? ret
: count
;
137 static ssize_t
mbox_test_message_read(struct file
*filp
, char __user
*userbuf
,
138 size_t count
, loff_t
*ppos
)
140 struct mbox_test_device
*tdev
= filp
->private_data
;
146 touser
= kzalloc(MBOX_HEXDUMP_MAX_LEN
+ 1, GFP_KERNEL
);
150 if (!tdev
->rx_channel
) {
151 ret
= snprintf(touser
, 20, "<NO RX CAPABILITY>\n");
152 ret
= simple_read_from_buffer(userbuf
, count
, ppos
,
157 if (tdev
->rx_buffer
[0] == '\0') {
158 ret
= snprintf(touser
, 9, "<EMPTY>\n");
159 ret
= simple_read_from_buffer(userbuf
, count
, ppos
,
164 spin_lock_irqsave(&tdev
->lock
, flags
);
166 ptr
= tdev
->rx_buffer
;
167 while (l
< MBOX_HEXDUMP_MAX_LEN
) {
168 hex_dump_to_buffer(ptr
,
170 MBOX_BYTES_PER_LINE
, 1, touser
+ l
,
171 MBOX_HEXDUMP_LINE_LEN
, true);
173 ptr
+= MBOX_BYTES_PER_LINE
;
174 l
+= MBOX_HEXDUMP_LINE_LEN
;
175 *(touser
+ (l
- 1)) = '\n';
177 *(touser
+ l
) = '\0';
179 memset(tdev
->rx_buffer
, 0, MBOX_MAX_MSG_LEN
);
181 spin_unlock_irqrestore(&tdev
->lock
, flags
);
183 ret
= simple_read_from_buffer(userbuf
, count
, ppos
, touser
, MBOX_HEXDUMP_MAX_LEN
);
189 static const struct file_operations mbox_test_message_ops
= {
190 .write
= mbox_test_message_write
,
191 .read
= mbox_test_message_read
,
193 .llseek
= generic_file_llseek
,
196 static int mbox_test_add_debugfs(struct platform_device
*pdev
,
197 struct mbox_test_device
*tdev
)
199 if (!debugfs_initialized())
202 root_debugfs_dir
= debugfs_create_dir("mailbox", NULL
);
203 if (!root_debugfs_dir
) {
204 dev_err(&pdev
->dev
, "Failed to create Mailbox debugfs\n");
208 debugfs_create_file("message", 0600, root_debugfs_dir
,
209 tdev
, &mbox_test_message_ops
);
211 debugfs_create_file("signal", 0200, root_debugfs_dir
,
212 tdev
, &mbox_test_signal_ops
);
217 static void mbox_test_receive_message(struct mbox_client
*client
, void *message
)
219 struct mbox_test_device
*tdev
= dev_get_drvdata(client
->dev
);
222 spin_lock_irqsave(&tdev
->lock
, flags
);
224 memcpy_fromio(tdev
->rx_buffer
, tdev
->mmio
, MBOX_MAX_MSG_LEN
);
225 print_hex_dump(KERN_INFO
, "Client: Received [MMIO]: ",
226 DUMP_PREFIX_ADDRESS
, MBOX_BYTES_PER_LINE
, 1,
227 tdev
->rx_buffer
, MBOX_MAX_MSG_LEN
, true);
228 } else if (message
) {
229 print_hex_dump(KERN_INFO
, "Client: Received [API]: ",
230 DUMP_PREFIX_ADDRESS
, MBOX_BYTES_PER_LINE
, 1,
231 message
, MBOX_MAX_MSG_LEN
, true);
232 memcpy(tdev
->rx_buffer
, message
, MBOX_MAX_MSG_LEN
);
234 spin_unlock_irqrestore(&tdev
->lock
, flags
);
237 static void mbox_test_prepare_message(struct mbox_client
*client
, void *message
)
239 struct mbox_test_device
*tdev
= dev_get_drvdata(client
->dev
);
243 memcpy_toio(tdev
->mmio
, tdev
->message
, MBOX_MAX_MSG_LEN
);
245 memcpy_toio(tdev
->mmio
, message
, MBOX_MAX_MSG_LEN
);
249 static void mbox_test_message_sent(struct mbox_client
*client
,
250 void *message
, int r
)
253 dev_warn(client
->dev
,
254 "Client: Message could not be sent: %d\n", r
);
256 dev_info(client
->dev
,
257 "Client: Message sent\n");
260 static struct mbox_chan
*
261 mbox_test_request_channel(struct platform_device
*pdev
, const char *name
)
263 struct mbox_client
*client
;
264 struct mbox_chan
*channel
;
266 client
= devm_kzalloc(&pdev
->dev
, sizeof(*client
), GFP_KERNEL
);
268 return ERR_PTR(-ENOMEM
);
270 client
->dev
= &pdev
->dev
;
271 client
->rx_callback
= mbox_test_receive_message
;
272 client
->tx_prepare
= mbox_test_prepare_message
;
273 client
->tx_done
= mbox_test_message_sent
;
274 client
->tx_block
= true;
275 client
->knows_txdone
= false;
276 client
->tx_tout
= 500;
278 channel
= mbox_request_channel_byname(client
, name
);
279 if (IS_ERR(channel
)) {
280 dev_warn(&pdev
->dev
, "Failed to request %s channel\n", name
);
287 static int mbox_test_probe(struct platform_device
*pdev
)
289 struct mbox_test_device
*tdev
;
290 struct resource
*res
;
293 tdev
= devm_kzalloc(&pdev
->dev
, sizeof(*tdev
), GFP_KERNEL
);
297 /* It's okay for MMIO to be NULL */
298 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
299 tdev
->mmio
= devm_ioremap_resource(&pdev
->dev
, res
);
300 if (IS_ERR(tdev
->mmio
))
303 tdev
->tx_channel
= mbox_test_request_channel(pdev
, "tx");
304 tdev
->rx_channel
= mbox_test_request_channel(pdev
, "rx");
306 if (!tdev
->tx_channel
&& !tdev
->rx_channel
)
307 return -EPROBE_DEFER
;
309 tdev
->dev
= &pdev
->dev
;
310 platform_set_drvdata(pdev
, tdev
);
312 spin_lock_init(&tdev
->lock
);
314 if (tdev
->rx_channel
) {
315 tdev
->rx_buffer
= devm_kzalloc(&pdev
->dev
,
316 MBOX_MAX_MSG_LEN
, GFP_KERNEL
);
317 if (!tdev
->rx_buffer
)
321 ret
= mbox_test_add_debugfs(pdev
, tdev
);
325 dev_info(&pdev
->dev
, "Successfully registered\n");
330 static int mbox_test_remove(struct platform_device
*pdev
)
332 struct mbox_test_device
*tdev
= platform_get_drvdata(pdev
);
334 debugfs_remove_recursive(root_debugfs_dir
);
336 if (tdev
->tx_channel
)
337 mbox_free_channel(tdev
->tx_channel
);
338 if (tdev
->rx_channel
)
339 mbox_free_channel(tdev
->rx_channel
);
344 static const struct of_device_id mbox_test_match
[] = {
345 { .compatible
= "mailbox_test" },
349 static struct platform_driver mbox_test_driver
= {
351 .name
= "mailbox_sti_test",
352 .of_match_table
= mbox_test_match
,
354 .probe
= mbox_test_probe
,
355 .remove
= mbox_test_remove
,
357 module_platform_driver(mbox_test_driver
);
359 MODULE_DESCRIPTION("Generic Mailbox Testing Facility");
360 MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org");
361 MODULE_LICENSE("GPL v2");