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