aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2015-10-16 03:21:30 -0400
committerJassi Brar <jaswinder.singh@linaro.org>2015-10-17 01:06:56 -0400
commit8ea4484d0c2bb4e2152261943fa1a3522654b1c7 (patch)
tree6e3c13403f8b1a1677ba8b5aa11611f59b86f482
parent9ef4546cbd7eed2412ec6f1161c2b92362379150 (diff)
mailbox: Add generic mechanism for testing Mailbox Controllers
This particular Client implementation uses shared memory in order to pass messages between Mailbox users; however, it can be easily hacked to support any type of Controller. Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
-rw-r--r--drivers/mailbox/Kconfig7
-rw-r--r--drivers/mailbox/Makefile2
-rw-r--r--drivers/mailbox/mailbox-test.c361
3 files changed, 370 insertions, 0 deletions
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 7b53386f9415..546d05f4358a 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -78,4 +78,11 @@ config STI_MBOX
78 Mailbox implementation for STMicroelectonics family chips with 78 Mailbox implementation for STMicroelectonics family chips with
79 hardware for interprocessor communication. 79 hardware for interprocessor communication.
80 80
81config MAILBOX_TEST
82 tristate "Mailbox Test Client"
83 depends on OF
84 help
85 Test client to help with testing new Controller driver
86 implementations.
87
81endif 88endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 7cb476643833..92435ef11f26 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -2,6 +2,8 @@
2 2
3obj-$(CONFIG_MAILBOX) += mailbox.o 3obj-$(CONFIG_MAILBOX) += mailbox.o
4 4
5obj-$(CONFIG_MAILBOX_TEST) += mailbox-test.o
6
5obj-$(CONFIG_ARM_MHU) += arm_mhu.o 7obj-$(CONFIG_ARM_MHU) += arm_mhu.o
6 8
7obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o 9obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c
new file mode 100644
index 000000000000..cac1ba2f3e22
--- /dev/null
+++ b/drivers/mailbox/mailbox-test.c
@@ -0,0 +1,361 @@
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/kernel.h>
15#include <linux/mailbox_client.h>
16#include <linux/module.h>
17#include <linux/of.h>
18#include <linux/platform_device.h>
19#include <linux/slab.h>
20#include <linux/uaccess.h>
21
22#define MBOX_MAX_SIG_LEN 8
23#define MBOX_MAX_MSG_LEN 128
24#define MBOX_BYTES_PER_LINE 16
25#define MBOX_HEXDUMP_LINE_LEN ((MBOX_BYTES_PER_LINE * 4) + 2)
26#define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \
27 (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
28
29static struct dentry *root_debugfs_dir;
30
31struct mbox_test_device {
32 struct device *dev;
33 void __iomem *mmio;
34 struct mbox_chan *tx_channel;
35 struct mbox_chan *rx_channel;
36 char *rx_buffer;
37 char *signal;
38 char *message;
39 spinlock_t lock;
40};
41
42static ssize_t mbox_test_signal_write(struct file *filp,
43 const char __user *userbuf,
44 size_t count, loff_t *ppos)
45{
46 struct mbox_test_device *tdev = filp->private_data;
47 int ret;
48
49 if (!tdev->tx_channel) {
50 dev_err(tdev->dev, "Channel cannot do Tx\n");
51 return -EINVAL;
52 }
53
54 if (count > MBOX_MAX_SIG_LEN) {
55 dev_err(tdev->dev,
56 "Signal length %d greater than max allowed %d\n",
57 count, MBOX_MAX_SIG_LEN);
58 return -EINVAL;
59 }
60
61 tdev->signal = kzalloc(MBOX_MAX_SIG_LEN, GFP_KERNEL);
62 if (!tdev->signal)
63 return -ENOMEM;
64
65 ret = copy_from_user(tdev->signal, userbuf, count);
66 if (ret) {
67 kfree(tdev->signal);
68 return -EFAULT;
69 }
70
71 return ret < 0 ? ret : count;
72}
73
74static const struct file_operations mbox_test_signal_ops = {
75 .write = mbox_test_signal_write,
76 .open = simple_open,
77 .llseek = generic_file_llseek,
78};
79
80static ssize_t mbox_test_message_write(struct file *filp,
81 const char __user *userbuf,
82 size_t count, loff_t *ppos)
83{
84 struct mbox_test_device *tdev = filp->private_data;
85 void *data;
86 int ret;
87
88 if (!tdev->tx_channel) {
89 dev_err(tdev->dev, "Channel cannot do Tx\n");
90 return -EINVAL;
91 }
92
93 if (count > MBOX_MAX_MSG_LEN) {
94 dev_err(tdev->dev,
95 "Message length %d greater than max allowed %d\n",
96 count, MBOX_MAX_MSG_LEN);
97 return -EINVAL;
98 }
99
100 tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
101 if (!tdev->message)
102 return -ENOMEM;
103
104 ret = copy_from_user(tdev->message, userbuf, count);
105 if (ret) {
106 ret = -EFAULT;
107 goto out;
108 }
109
110 /*
111 * A separate signal is only of use if there is
112 * MMIO to subsequently pass the message through
113 */
114 if (tdev->mmio && tdev->signal) {
115 print_hex_dump(KERN_INFO, "Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS,
116 MBOX_BYTES_PER_LINE, 1, tdev->signal, MBOX_MAX_SIG_LEN, true);
117
118 data = tdev->signal;
119 } else
120 data = tdev->message;
121
122 print_hex_dump(KERN_INFO, "Client: Sending: Message: ", DUMP_PREFIX_ADDRESS,
123 MBOX_BYTES_PER_LINE, 1, tdev->message, MBOX_MAX_MSG_LEN, true);
124
125 ret = mbox_send_message(tdev->tx_channel, data);
126 if (ret < 0)
127 dev_err(tdev->dev, "Failed to send message via mailbox\n");
128
129out:
130 kfree(tdev->signal);
131 kfree(tdev->message);
132
133 return ret < 0 ? ret : count;
134}
135
136static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
137 size_t count, loff_t *ppos)
138{
139 struct mbox_test_device *tdev = filp->private_data;
140 unsigned long flags;
141 char *touser, *ptr;
142 int l = 0;
143 int ret;
144
145 touser = kzalloc(MBOX_HEXDUMP_MAX_LEN, GFP_KERNEL);
146 if (!touser)
147 return -ENOMEM;
148
149 if (!tdev->rx_channel) {
150 ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
151 ret = simple_read_from_buffer(userbuf, count, ppos,
152 touser, ret);
153 goto out;
154 }
155
156 if (tdev->rx_buffer[0] == '\0') {
157 ret = snprintf(touser, 9, "<EMPTY>\n");
158 ret = simple_read_from_buffer(userbuf, count, ppos,
159 touser, ret);
160 goto out;
161 }
162
163 spin_lock_irqsave(&tdev->lock, flags);
164
165 ptr = tdev->rx_buffer;
166 while (l < MBOX_HEXDUMP_MAX_LEN) {
167 hex_dump_to_buffer(ptr,
168 MBOX_BYTES_PER_LINE,
169 MBOX_BYTES_PER_LINE, 1, touser + l,
170 MBOX_HEXDUMP_LINE_LEN, true);
171
172 ptr += MBOX_BYTES_PER_LINE;
173 l += MBOX_HEXDUMP_LINE_LEN;
174 *(touser + (l - 1)) = '\n';
175 }
176 *(touser + l) = '\0';
177
178 memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN);
179
180 spin_unlock_irqrestore(&tdev->lock, flags);
181
182 ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN);
183out:
184 kfree(touser);
185 return ret;
186}
187
188static const struct file_operations mbox_test_message_ops = {
189 .write = mbox_test_message_write,
190 .read = mbox_test_message_read,
191 .open = simple_open,
192 .llseek = generic_file_llseek,
193};
194
195static int mbox_test_add_debugfs(struct platform_device *pdev,
196 struct mbox_test_device *tdev)
197{
198 if (!debugfs_initialized())
199 return 0;
200
201 root_debugfs_dir = debugfs_create_dir("mailbox", NULL);
202 if (!root_debugfs_dir) {
203 dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n");
204 return -EINVAL;
205 }
206
207 debugfs_create_file("message", 0600, root_debugfs_dir,
208 tdev, &mbox_test_message_ops);
209
210 debugfs_create_file("signal", 0200, root_debugfs_dir,
211 tdev, &mbox_test_signal_ops);
212
213 return 0;
214}
215
216static void mbox_test_receive_message(struct mbox_client *client, void *message)
217{
218 struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
219 unsigned long flags;
220
221 spin_lock_irqsave(&tdev->lock, flags);
222 if (tdev->mmio) {
223 print_hex_dump(KERN_INFO, "Client: Received [MMIO]: ",
224 DUMP_PREFIX_ADDRESS, MBOX_BYTES_PER_LINE, 1,
225 tdev->mmio, MBOX_MAX_MSG_LEN, true);
226 memcpy(tdev->rx_buffer, tdev->mmio, MBOX_MAX_MSG_LEN);
227
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);
233 }
234 spin_unlock_irqrestore(&tdev->lock, flags);
235}
236
237static void mbox_test_prepare_message(struct mbox_client *client, void *message)
238{
239 struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
240
241 if (tdev->mmio) {
242 if (tdev->signal)
243 memcpy(tdev->mmio, tdev->message, MBOX_MAX_MSG_LEN);
244 else
245 memcpy(tdev->mmio, message, MBOX_MAX_MSG_LEN);
246 }
247}
248
249static void mbox_test_message_sent(struct mbox_client *client,
250 void *message, int r)
251{
252 if (r)
253 dev_warn(client->dev,
254 "Client: Message could not be sent: %d\n", r);
255 else
256 dev_info(client->dev,
257 "Client: Message sent\n");
258}
259
260static struct mbox_chan *
261mbox_test_request_channel(struct platform_device *pdev, const char *name)
262{
263 struct mbox_client *client;
264 struct mbox_chan *channel;
265
266 client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
267 if (!client)
268 return ERR_PTR(-ENOMEM);
269
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;
277
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);
281 return NULL;
282 }
283
284 return channel;
285}
286
287static int mbox_test_probe(struct platform_device *pdev)
288{
289 struct mbox_test_device *tdev;
290 struct resource *res;
291 int ret;
292
293 tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
294 if (!tdev)
295 return -ENOMEM;
296
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))
301 tdev->mmio = NULL;
302
303 tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
304 tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
305
306 if (!tdev->tx_channel && !tdev->tx_channel)
307 return -EPROBE_DEFER;
308
309 tdev->dev = &pdev->dev;
310 platform_set_drvdata(pdev, tdev);
311
312 spin_lock_init(&tdev->lock);
313
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)
318 return -ENOMEM;
319 }
320
321 ret = mbox_test_add_debugfs(pdev, tdev);
322 if (ret)
323 return ret;
324
325 dev_info(&pdev->dev, "Successfully registered\n");
326
327 return 0;
328}
329
330static int mbox_test_remove(struct platform_device *pdev)
331{
332 struct mbox_test_device *tdev = platform_get_drvdata(pdev);
333
334 debugfs_remove_recursive(root_debugfs_dir);
335
336 if (tdev->tx_channel)
337 mbox_free_channel(tdev->tx_channel);
338 if (tdev->rx_channel)
339 mbox_free_channel(tdev->rx_channel);
340
341 return 0;
342}
343
344static const struct of_device_id mbox_test_match[] = {
345 { .compatible = "mailbox_test" },
346 {},
347};
348
349static struct platform_driver mbox_test_driver = {
350 .driver = {
351 .name = "mailbox_sti_test",
352 .of_match_table = mbox_test_match,
353 },
354 .probe = mbox_test_probe,
355 .remove = mbox_test_remove,
356};
357module_platform_driver(mbox_test_driver);
358
359MODULE_DESCRIPTION("Generic Mailbox Testing Facility");
360MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org");
361MODULE_LICENSE("GPL v2");