blob: a18acd6706e18d74d93ad0c884262e82673c7ca5 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/interrupt.h>
15#include <linux/reboot.h>
16#include <linux/workqueue.h>
17#include <linux/io.h>
18#include <linux/jiffies.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070019#include <linux/sched.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020#include <linux/stringify.h>
21#include <linux/delay.h>
22#include <linux/module.h>
23#include <linux/miscdevice.h>
24#include <linux/fs.h>
25#include <linux/mm.h>
26#include <linux/slab.h>
27#include <linux/poll.h>
28#include <linux/uaccess.h>
29
30#include <asm-generic/poll.h>
31
32#include "ramdump.h"
33
34#define RAMDUMP_WAIT_MSECS 120000
35
36struct ramdump_device {
37 char name[256];
38
39 unsigned int data_ready;
40 unsigned int consumer_present;
41 int ramdump_status;
42
43 struct completion ramdump_complete;
44 struct miscdevice device;
45
46 wait_queue_head_t dump_wait_q;
47 int nsegments;
48 struct ramdump_segment *segments;
49};
50
51static int ramdump_open(struct inode *inode, struct file *filep)
52{
53 struct ramdump_device *rd_dev = container_of(filep->private_data,
54 struct ramdump_device, device);
55 rd_dev->consumer_present = 1;
56 rd_dev->ramdump_status = 0;
57 return 0;
58}
59
60static int ramdump_release(struct inode *inode, struct file *filep)
61{
62 struct ramdump_device *rd_dev = container_of(filep->private_data,
63 struct ramdump_device, device);
64 rd_dev->consumer_present = 0;
65 rd_dev->data_ready = 0;
66 complete(&rd_dev->ramdump_complete);
67 return 0;
68}
69
70static unsigned long offset_translate(loff_t user_offset,
71 struct ramdump_device *rd_dev, unsigned long *data_left)
72{
73 int i = 0;
74
75 for (i = 0; i < rd_dev->nsegments; i++)
76 if (user_offset >= rd_dev->segments[i].size)
77 user_offset -= rd_dev->segments[i].size;
78 else
79 break;
80
81 if (i == rd_dev->nsegments) {
82 pr_debug("Ramdump(%s): offset_translate returning zero\n",
83 rd_dev->name);
84 *data_left = 0;
85 return 0;
86 }
87
88 *data_left = rd_dev->segments[i].size - user_offset;
89
90 pr_debug("Ramdump(%s): Returning address: %llx, data_left = %ld\n",
91 rd_dev->name, rd_dev->segments[i].address + user_offset,
92 *data_left);
93
94 return rd_dev->segments[i].address + user_offset;
95}
96
97#define MAX_IOREMAP_SIZE SZ_1M
98
99static int ramdump_read(struct file *filep, char __user *buf, size_t count,
100 loff_t *pos)
101{
102 struct ramdump_device *rd_dev = container_of(filep->private_data,
103 struct ramdump_device, device);
104 void *device_mem = NULL;
105 unsigned long data_left = 0;
106 unsigned long addr = 0;
107 size_t copy_size = 0;
108 int ret = 0;
109
110 if (rd_dev->data_ready == 0) {
111 pr_err("Ramdump(%s): Read when there's no dump available!",
112 rd_dev->name);
113 return -EPIPE;
114 }
115
116 addr = offset_translate(*pos, rd_dev, &data_left);
117
118 /* EOF check */
119 if (data_left == 0) {
120 pr_debug("Ramdump(%s): Ramdump complete. %lld bytes read.",
121 rd_dev->name, *pos);
122 rd_dev->ramdump_status = 0;
123 ret = 0;
124 goto ramdump_done;
125 }
126
127 copy_size = min(count, (size_t)MAX_IOREMAP_SIZE);
128 copy_size = min((unsigned long)copy_size, data_left);
129 device_mem = ioremap_nocache(addr, copy_size);
130
131 if (device_mem == NULL) {
132 pr_err("Ramdump(%s): Unable to ioremap: addr %lx, size %x\n",
133 rd_dev->name, addr, copy_size);
134 rd_dev->ramdump_status = -1;
135 ret = -ENOMEM;
136 goto ramdump_done;
137 }
138
139 if (copy_to_user(buf, device_mem, copy_size)) {
140 pr_err("Ramdump(%s): Couldn't copy all data to user.",
141 rd_dev->name);
142 iounmap(device_mem);
143 rd_dev->ramdump_status = -1;
144 ret = -EFAULT;
145 goto ramdump_done;
146 }
147
148 iounmap(device_mem);
149 *pos += copy_size;
150
151 pr_debug("Ramdump(%s): Read %d bytes from address %lx.",
152 rd_dev->name, copy_size, addr);
153
154 return copy_size;
155
156ramdump_done:
157 rd_dev->data_ready = 0;
158 *pos = 0;
159 complete(&rd_dev->ramdump_complete);
160 return ret;
161}
162
163static unsigned int ramdump_poll(struct file *filep,
164 struct poll_table_struct *wait)
165{
166 struct ramdump_device *rd_dev = container_of(filep->private_data,
167 struct ramdump_device, device);
168 unsigned int mask = 0;
169
170 if (rd_dev->data_ready)
171 mask |= (POLLIN | POLLRDNORM);
172
173 poll_wait(filep, &rd_dev->dump_wait_q, wait);
174 return mask;
175}
176
177const struct file_operations ramdump_file_ops = {
178 .open = ramdump_open,
179 .release = ramdump_release,
180 .read = ramdump_read,
181 .poll = ramdump_poll
182};
183
184void *create_ramdump_device(const char *dev_name)
185{
186 int ret;
187 struct ramdump_device *rd_dev;
188
189 if (!dev_name) {
190 pr_err("%s: Invalid device name.\n", __func__);
191 return NULL;
192 }
193
194 rd_dev = kzalloc(sizeof(struct ramdump_device), GFP_KERNEL);
195
196 if (!rd_dev) {
197 pr_err("%s: Couldn't alloc space for ramdump device!",
198 __func__);
199 return NULL;
200 }
201
Matt Wagantallf9563142011-11-10 19:04:51 -0800202 snprintf(rd_dev->name, ARRAY_SIZE(rd_dev->name), "ramdump_%s",
203 dev_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204
205 init_completion(&rd_dev->ramdump_complete);
206
207 rd_dev->device.minor = MISC_DYNAMIC_MINOR;
208 rd_dev->device.name = rd_dev->name;
209 rd_dev->device.fops = &ramdump_file_ops;
210
211 init_waitqueue_head(&rd_dev->dump_wait_q);
212
213 ret = misc_register(&rd_dev->device);
214
215 if (ret) {
216 pr_err("%s: misc_register failed for %s (%d)", __func__,
217 dev_name, ret);
218 kfree(rd_dev);
219 return NULL;
220 }
221
222 return (void *)rd_dev;
223}
224
225int do_ramdump(void *handle, struct ramdump_segment *segments,
226 int nsegments)
227{
228 int ret, i;
229 struct ramdump_device *rd_dev = (struct ramdump_device *)handle;
230
231 if (!rd_dev->consumer_present) {
232 pr_err("Ramdump(%s): No consumers. Aborting..\n", rd_dev->name);
233 return -EPIPE;
234 }
235
236 for (i = 0; i < nsegments; i++)
237 segments[i].size = PAGE_ALIGN(segments[i].size);
238
239 rd_dev->segments = segments;
240 rd_dev->nsegments = nsegments;
241
242 rd_dev->data_ready = 1;
243 rd_dev->ramdump_status = -1;
244
245 INIT_COMPLETION(rd_dev->ramdump_complete);
246
247 /* Tell userspace that the data is ready */
248 wake_up(&rd_dev->dump_wait_q);
249
250 /* Wait (with a timeout) to let the ramdump complete */
251 ret = wait_for_completion_timeout(&rd_dev->ramdump_complete,
252 msecs_to_jiffies(RAMDUMP_WAIT_MSECS));
253
254 if (!ret) {
255 pr_err("Ramdump(%s): Timed out waiting for userspace.\n",
256 rd_dev->name);
257 ret = -EPIPE;
258 } else
259 ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE;
260
261 rd_dev->data_ready = 0;
262 return ret;
263}