xref: /openbmc/linux/drivers/char/ps3flash.c (revision 93dc544c)
1 /*
2  * PS3 FLASH ROM Storage Driver
3  *
4  * Copyright (C) 2007 Sony Computer Entertainment Inc.
5  * Copyright 2007 Sony Corp.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published
9  * by the Free Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <linux/fs.h>
22 #include <linux/miscdevice.h>
23 #include <linux/uaccess.h>
24 
25 #include <asm/lv1call.h>
26 #include <asm/ps3stor.h>
27 
28 
29 #define DEVICE_NAME		"ps3flash"
30 
31 #define FLASH_BLOCK_SIZE	(256*1024)
32 
33 
34 struct ps3flash_private {
35 	struct mutex mutex;	/* Bounce buffer mutex */
36 };
37 
38 static struct ps3_storage_device *ps3flash_dev;
39 
40 static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
41 					   u64 lpar, u64 start_sector,
42 					   u64 sectors, int write)
43 {
44 	u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
45 					     write);
46 	if (res) {
47 		dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
48 			__LINE__, write ? "write" : "read", res);
49 		return -EIO;
50 	}
51 	return sectors;
52 }
53 
54 static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
55 				     u64 start_sector, u64 sectors,
56 				     unsigned int sector_offset)
57 {
58 	u64 max_sectors, lpar;
59 
60 	max_sectors = dev->bounce_size / dev->blk_size;
61 	if (sectors > max_sectors) {
62 		dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %lu\n",
63 			__func__, __LINE__, max_sectors);
64 		sectors = max_sectors;
65 	}
66 
67 	lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
68 	return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
69 					   0);
70 }
71 
72 static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
73 				    u64 start_sector)
74 {
75        u64 sectors = dev->bounce_size / dev->blk_size;
76        return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
77 					  sectors, 1);
78 }
79 
80 static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
81 {
82 	struct ps3_storage_device *dev = ps3flash_dev;
83 	loff_t res;
84 
85 	mutex_lock(&file->f_mapping->host->i_mutex);
86 	switch (origin) {
87 	case 1:
88 		offset += file->f_pos;
89 		break;
90 	case 2:
91 		offset += dev->regions[dev->region_idx].size*dev->blk_size;
92 		break;
93 	}
94 	if (offset < 0) {
95 		res = -EINVAL;
96 		goto out;
97 	}
98 
99 	file->f_pos = offset;
100 	res = file->f_pos;
101 
102 out:
103 	mutex_unlock(&file->f_mapping->host->i_mutex);
104 	return res;
105 }
106 
107 static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
108 			     loff_t *pos)
109 {
110 	struct ps3_storage_device *dev = ps3flash_dev;
111 	struct ps3flash_private *priv = dev->sbd.core.driver_data;
112 	u64 size, start_sector, end_sector, offset;
113 	ssize_t sectors_read;
114 	size_t remaining, n;
115 
116 	dev_dbg(&dev->sbd.core,
117 		"%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
118 		__func__, __LINE__, count, *pos, buf);
119 
120 	size = dev->regions[dev->region_idx].size*dev->blk_size;
121 	if (*pos >= size || !count)
122 		return 0;
123 
124 	if (*pos + count > size) {
125 		dev_dbg(&dev->sbd.core,
126 			"%s:%u Truncating count from %zu to %llu\n", __func__,
127 			__LINE__, count, size - *pos);
128 		count = size - *pos;
129 	}
130 
131 	start_sector = *pos / dev->blk_size;
132 	offset = *pos % dev->blk_size;
133 	end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
134 
135 	remaining = count;
136 	do {
137 		mutex_lock(&priv->mutex);
138 
139 		sectors_read = ps3flash_read_sectors(dev, start_sector,
140 						     end_sector-start_sector,
141 						     0);
142 		if (sectors_read < 0) {
143 			mutex_unlock(&priv->mutex);
144 			goto fail;
145 		}
146 
147 		n = min(remaining, sectors_read*dev->blk_size-offset);
148 		dev_dbg(&dev->sbd.core,
149 			"%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
150 			__func__, __LINE__, n, dev->bounce_buf+offset, buf);
151 		if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
152 			mutex_unlock(&priv->mutex);
153 			sectors_read = -EFAULT;
154 			goto fail;
155 		}
156 
157 		mutex_unlock(&priv->mutex);
158 
159 		*pos += n;
160 		buf += n;
161 		remaining -= n;
162 		start_sector += sectors_read;
163 		offset = 0;
164 	} while (remaining > 0);
165 
166 	return count;
167 
168 fail:
169 	return sectors_read;
170 }
171 
172 static ssize_t ps3flash_write(struct file *file, const char __user *buf,
173 			      size_t count, loff_t *pos)
174 {
175 	struct ps3_storage_device *dev = ps3flash_dev;
176 	struct ps3flash_private *priv = dev->sbd.core.driver_data;
177 	u64 size, chunk_sectors, start_write_sector, end_write_sector,
178 	    end_read_sector, start_read_sector, head, tail, offset;
179 	ssize_t res;
180 	size_t remaining, n;
181 	unsigned int sec_off;
182 
183 	dev_dbg(&dev->sbd.core,
184 		"%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
185 		__func__, __LINE__, count, *pos, buf);
186 
187 	size = dev->regions[dev->region_idx].size*dev->blk_size;
188 	if (*pos >= size || !count)
189 		return 0;
190 
191 	if (*pos + count > size) {
192 		dev_dbg(&dev->sbd.core,
193 			"%s:%u Truncating count from %zu to %llu\n", __func__,
194 			__LINE__, count, size - *pos);
195 		count = size - *pos;
196 	}
197 
198 	chunk_sectors = dev->bounce_size / dev->blk_size;
199 
200 	start_write_sector = *pos / dev->bounce_size * chunk_sectors;
201 	offset = *pos % dev->bounce_size;
202 	end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
203 			   chunk_sectors;
204 
205 	end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
206 	start_read_sector = (*pos + count) / dev->blk_size;
207 
208 	/*
209 	 * As we have to write in 256 KiB chunks, while we can read in blk_size
210 	 * (usually 512 bytes) chunks, we perform the following steps:
211 	 *   1. Read from start_write_sector to end_read_sector ("head")
212 	 *   2. Read from start_read_sector to end_write_sector ("tail")
213 	 *   3. Copy data to buffer
214 	 *   4. Write from start_write_sector to end_write_sector
215 	 * All of this is complicated by using only one 256 KiB bounce buffer.
216 	 */
217 
218 	head = end_read_sector - start_write_sector;
219 	tail = end_write_sector - start_read_sector;
220 
221 	remaining = count;
222 	do {
223 		mutex_lock(&priv->mutex);
224 
225 		if (end_read_sector >= start_read_sector) {
226 			/* Merge head and tail */
227 			dev_dbg(&dev->sbd.core,
228 				"Merged head and tail: %lu sectors at %lu\n",
229 				chunk_sectors, start_write_sector);
230 			res = ps3flash_read_sectors(dev, start_write_sector,
231 						    chunk_sectors, 0);
232 			if (res < 0)
233 				goto fail;
234 		} else {
235 			if (head) {
236 				/* Read head */
237 				dev_dbg(&dev->sbd.core,
238 					"head: %lu sectors at %lu\n", head,
239 					start_write_sector);
240 				res = ps3flash_read_sectors(dev,
241 							    start_write_sector,
242 							    head, 0);
243 				if (res < 0)
244 					goto fail;
245 			}
246 			if (start_read_sector <
247 			    start_write_sector+chunk_sectors) {
248 				/* Read tail */
249 				dev_dbg(&dev->sbd.core,
250 					"tail: %lu sectors at %lu\n", tail,
251 					start_read_sector);
252 				sec_off = start_read_sector-start_write_sector;
253 				res = ps3flash_read_sectors(dev,
254 							    start_read_sector,
255 							    tail, sec_off);
256 				if (res < 0)
257 					goto fail;
258 			}
259 		}
260 
261 		n = min(remaining, dev->bounce_size-offset);
262 		dev_dbg(&dev->sbd.core,
263 			"%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
264 			__func__, __LINE__, n, buf, dev->bounce_buf+offset);
265 		if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
266 			res = -EFAULT;
267 			goto fail;
268 		}
269 
270 		res = ps3flash_write_chunk(dev, start_write_sector);
271 		if (res < 0)
272 			goto fail;
273 
274 		mutex_unlock(&priv->mutex);
275 
276 		*pos += n;
277 		buf += n;
278 		remaining -= n;
279 		start_write_sector += chunk_sectors;
280 		head = 0;
281 		offset = 0;
282 	} while (remaining > 0);
283 
284 	return count;
285 
286 fail:
287 	mutex_unlock(&priv->mutex);
288 	return res;
289 }
290 
291 
292 static irqreturn_t ps3flash_interrupt(int irq, void *data)
293 {
294 	struct ps3_storage_device *dev = data;
295 	int res;
296 	u64 tag, status;
297 
298 	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
299 
300 	if (tag != dev->tag)
301 		dev_err(&dev->sbd.core,
302 			"%s:%u: tag mismatch, got %lx, expected %lx\n",
303 			__func__, __LINE__, tag, dev->tag);
304 
305 	if (res) {
306 		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
307 			__func__, __LINE__, res, status);
308 	} else {
309 		dev->lv1_status = status;
310 		complete(&dev->done);
311 	}
312 	return IRQ_HANDLED;
313 }
314 
315 
316 static const struct file_operations ps3flash_fops = {
317 	.owner	= THIS_MODULE,
318 	.llseek	= ps3flash_llseek,
319 	.read	= ps3flash_read,
320 	.write	= ps3flash_write,
321 };
322 
323 static struct miscdevice ps3flash_misc = {
324 	.minor	= MISC_DYNAMIC_MINOR,
325 	.name	= DEVICE_NAME,
326 	.fops	= &ps3flash_fops,
327 };
328 
329 static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
330 {
331 	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
332 	struct ps3flash_private *priv;
333 	int error;
334 	unsigned long tmp;
335 
336 	tmp = dev->regions[dev->region_idx].start*dev->blk_size;
337 	if (tmp % FLASH_BLOCK_SIZE) {
338 		dev_err(&dev->sbd.core,
339 			"%s:%u region start %lu is not aligned\n", __func__,
340 			__LINE__, tmp);
341 		return -EINVAL;
342 	}
343 	tmp = dev->regions[dev->region_idx].size*dev->blk_size;
344 	if (tmp % FLASH_BLOCK_SIZE) {
345 		dev_err(&dev->sbd.core,
346 			"%s:%u region size %lu is not aligned\n", __func__,
347 			__LINE__, tmp);
348 		return -EINVAL;
349 	}
350 
351 	/* use static buffer, kmalloc cannot allocate 256 KiB */
352 	if (!ps3flash_bounce_buffer.address)
353 		return -ENODEV;
354 
355 	if (ps3flash_dev) {
356 		dev_err(&dev->sbd.core,
357 			"Only one FLASH device is supported\n");
358 		return -EBUSY;
359 	}
360 
361 	ps3flash_dev = dev;
362 
363 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
364 	if (!priv) {
365 		error = -ENOMEM;
366 		goto fail;
367 	}
368 
369 	dev->sbd.core.driver_data = priv;
370 	mutex_init(&priv->mutex);
371 
372 	dev->bounce_size = ps3flash_bounce_buffer.size;
373 	dev->bounce_buf = ps3flash_bounce_buffer.address;
374 
375 	error = ps3stor_setup(dev, ps3flash_interrupt);
376 	if (error)
377 		goto fail_free_priv;
378 
379 	ps3flash_misc.parent = &dev->sbd.core;
380 	error = misc_register(&ps3flash_misc);
381 	if (error) {
382 		dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n",
383 			__func__, __LINE__, error);
384 		goto fail_teardown;
385 	}
386 
387 	dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
388 		 __func__, __LINE__, ps3flash_misc.minor);
389 	return 0;
390 
391 fail_teardown:
392 	ps3stor_teardown(dev);
393 fail_free_priv:
394 	kfree(priv);
395 	dev->sbd.core.driver_data = NULL;
396 fail:
397 	ps3flash_dev = NULL;
398 	return error;
399 }
400 
401 static int ps3flash_remove(struct ps3_system_bus_device *_dev)
402 {
403 	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
404 
405 	misc_deregister(&ps3flash_misc);
406 	ps3stor_teardown(dev);
407 	kfree(dev->sbd.core.driver_data);
408 	dev->sbd.core.driver_data = NULL;
409 	ps3flash_dev = NULL;
410 	return 0;
411 }
412 
413 
414 static struct ps3_system_bus_driver ps3flash = {
415 	.match_id	= PS3_MATCH_ID_STOR_FLASH,
416 	.core.name	= DEVICE_NAME,
417 	.core.owner	= THIS_MODULE,
418 	.probe		= ps3flash_probe,
419 	.remove		= ps3flash_remove,
420 	.shutdown	= ps3flash_remove,
421 };
422 
423 
424 static int __init ps3flash_init(void)
425 {
426 	return ps3_system_bus_driver_register(&ps3flash);
427 }
428 
429 static void __exit ps3flash_exit(void)
430 {
431 	ps3_system_bus_driver_unregister(&ps3flash);
432 }
433 
434 module_init(ps3flash_init);
435 module_exit(ps3flash_exit);
436 
437 MODULE_LICENSE("GPL");
438 MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
439 MODULE_AUTHOR("Sony Corporation");
440 MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);
441