16 You should have received a copy of the GNU General Public License along |
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., |
17 with this program; if not, write to the Free Software Foundation, Inc., |
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 */ |
19 */ |
20 |
20 |
21 #include <linux/fs.h> |
|
22 #include <linux/kernel.h> |
21 #include <linux/kernel.h> |
23 #include <linux/module.h> |
22 #include <linux/module.h> |
24 #include <linux/sched.h> |
23 #include <linux/sched.h> |
25 #include <linux/uaccess.h> |
24 #include <linux/uaccess.h> |
26 #include "module.h" |
25 #include "module.h" |
27 #include "update.h" |
26 |
28 |
27 #define CCAT_DEVICES_MAX 5 |
29 #define CCAT_DATA_IN_4 0x038 |
28 #define CCAT_DATA_IN_4 0x038 |
30 #define CCAT_DATA_IN_N 0x7F0 |
29 #define CCAT_DATA_IN_N 0x7F0 |
31 #define CCAT_DATA_OUT_4 0x030 |
30 #define CCAT_DATA_OUT_4 0x030 |
32 #define CCAT_DATA_BLOCK_SIZE (size_t)((CCAT_DATA_IN_N - CCAT_DATA_IN_4)/8) |
31 #define CCAT_DATA_BLOCK_SIZE (size_t)((CCAT_DATA_IN_N - CCAT_DATA_IN_4)/8) |
33 #define CCAT_WRITE_BLOCK_SIZE 128 |
32 #define CCAT_WRITE_BLOCK_SIZE 128 |
241 |
228 |
242 /** |
229 /** |
243 * ccat_write_flash() - Write a new CCAT configuration to FPGA's flash |
230 * ccat_write_flash() - Write a new CCAT configuration to FPGA's flash |
244 * @update: a CCAT Update buffer containing the new FPGA configuration |
231 * @update: a CCAT Update buffer containing the new FPGA configuration |
245 */ |
232 */ |
246 static void ccat_write_flash(const struct update_buffer *const update) |
233 static void ccat_write_flash(const struct cdev_buffer *const buffer) |
247 { |
234 { |
248 const char *buf = update->data; |
235 const char *buf = buffer->data; |
249 u32 off = 0; |
236 u32 off = 0; |
250 size_t len = update->size; |
237 size_t len = buffer->size; |
251 |
238 |
252 while (len > CCAT_WRITE_BLOCK_SIZE) { |
239 while (len > CCAT_WRITE_BLOCK_SIZE) { |
253 ccat_write_flash_block(update->update->ioaddr, off, |
240 ccat_write_flash_block(buffer->ccdev->ioaddr, off, |
254 (u16) CCAT_WRITE_BLOCK_SIZE, buf); |
241 (u16) CCAT_WRITE_BLOCK_SIZE, buf); |
255 off += CCAT_WRITE_BLOCK_SIZE; |
242 off += CCAT_WRITE_BLOCK_SIZE; |
256 buf += CCAT_WRITE_BLOCK_SIZE; |
243 buf += CCAT_WRITE_BLOCK_SIZE; |
257 len -= CCAT_WRITE_BLOCK_SIZE; |
244 len -= CCAT_WRITE_BLOCK_SIZE; |
258 } |
245 } |
259 ccat_write_flash_block(update->update->ioaddr, off, (u16) len, buf); |
246 ccat_write_flash_block(buffer->ccdev->ioaddr, off, (u16) len, buf); |
260 } |
|
261 |
|
262 /** |
|
263 * ccat_update_destroy() - Cleanup the CCAT Update function |
|
264 * @ref: pointer to a struct kref embedded into a struct ccat_update, which we intend to destroy |
|
265 * |
|
266 * Retrieves the parent struct ccat_update and destroys it. |
|
267 */ |
|
268 static void ccat_update_destroy(struct kref *ref) |
|
269 { |
|
270 struct ccat_update *update = |
|
271 container_of(ref, struct ccat_update, refcount); |
|
272 |
|
273 cdev_del(&update->cdev); |
|
274 device_destroy(update->class, update->dev); |
|
275 class_destroy(update->class); |
|
276 unregister_chrdev_region(update->dev, 1); |
|
277 kfree(update); |
|
278 pr_debug("%s(): done\n", __FUNCTION__); |
|
279 } |
|
280 |
|
281 static int ccat_update_open(struct inode *const i, struct file *const f) |
|
282 { |
|
283 struct ccat_update *update = |
|
284 container_of(i->i_cdev, struct ccat_update, cdev); |
|
285 struct update_buffer *buf; |
|
286 |
|
287 kref_get(&update->refcount); |
|
288 if (atomic_read(&update->refcount.refcount) > 2) { |
|
289 kref_put(&update->refcount, ccat_update_destroy); |
|
290 return -EBUSY; |
|
291 } |
|
292 |
|
293 buf = kzalloc(sizeof(*buf), GFP_KERNEL); |
|
294 if (!buf) { |
|
295 kref_put(&update->refcount, ccat_update_destroy); |
|
296 return -ENOMEM; |
|
297 } |
|
298 |
|
299 buf->update = update; |
|
300 f->private_data = buf; |
|
301 return 0; |
|
302 } |
247 } |
303 |
248 |
304 static int ccat_update_release(struct inode *const i, struct file *const f) |
249 static int ccat_update_release(struct inode *const i, struct file *const f) |
305 { |
250 { |
306 const struct update_buffer *const buf = f->private_data; |
251 const struct cdev_buffer *const buf = f->private_data; |
307 struct ccat_update *const update = buf->update; |
252 void __iomem *ioaddr = buf->ccdev->ioaddr; |
308 |
253 |
309 if (buf->size > 0) { |
254 if (buf->size > 0) { |
310 ccat_update_cmd(update->ioaddr, CCAT_WRITE_ENABLE); |
255 ccat_update_cmd(ioaddr, CCAT_WRITE_ENABLE); |
311 ccat_update_cmd(update->ioaddr, CCAT_BULK_ERASE); |
256 ccat_update_cmd(ioaddr, CCAT_BULK_ERASE); |
312 ccat_wait_status_cleared(update->ioaddr); |
257 ccat_wait_status_cleared(ioaddr); |
313 ccat_write_flash(buf); |
258 ccat_write_flash(buf); |
314 } |
259 } |
315 kfree(f->private_data); |
260 return ccat_cdev_release(i, f); |
316 kref_put(&update->refcount, ccat_update_destroy); |
|
317 return 0; |
|
318 } |
261 } |
319 |
262 |
320 /** |
263 /** |
321 * ccat_update_read() - Read CCAT configuration data from flash |
264 * ccat_update_read() - Read CCAT configuration data from flash |
322 * @f: file handle previously initialized with ccat_update_open() |
265 * @f: file handle previously initialized with ccat_update_open() |
331 * Return: the number of bytes written, or 0 if EOF reached |
274 * Return: the number of bytes written, or 0 if EOF reached |
332 */ |
275 */ |
333 static ssize_t ccat_update_read(struct file *const f, char __user * buf, |
276 static ssize_t ccat_update_read(struct file *const f, char __user * buf, |
334 size_t len, loff_t * off) |
277 size_t len, loff_t * off) |
335 { |
278 { |
336 struct update_buffer *update = f->private_data; |
279 struct cdev_buffer *buffer = f->private_data; |
337 |
280 const size_t iosize = buffer->ccdev->iosize; |
338 if (!buf || !off) { |
281 |
339 return -EINVAL; |
282 if (*off >= iosize) { |
340 } |
|
341 if (*off >= CCAT_FLASH_SIZE) { |
|
342 return 0; |
283 return 0; |
343 } |
284 } |
344 if (*off + len >= CCAT_FLASH_SIZE) { |
285 |
345 len = CCAT_FLASH_SIZE - *off; |
286 len = min(len, (size_t) (iosize - *off)); |
346 } |
287 |
347 return ccat_read_flash(update->update->ioaddr, buf, len, off); |
288 return ccat_read_flash(buffer->ccdev->ioaddr, buf, len, off); |
348 } |
289 } |
349 |
290 |
350 /** |
291 /** |
351 * ccat_update_write() - Write data to the CCAT FPGA's configuration flash |
292 * ccat_update_write() - Write data to the CCAT FPGA's configuration flash |
352 * @f: file handle previously initialized with ccat_update_open() |
293 * @f: file handle previously initialized with ccat_update_open() |
353 * @buf: buffer in user space providing the new configuration data (from *.rbf) |
294 * @buf: buffer in user space providing the new configuration data (from *.rbf) |
354 * @len: length of the user space buffer |
295 * @len: length of the user space buffer |
355 * @off: current offset in the configuration data |
296 * @off: current offset in the configuration data |
356 * |
297 * |
357 * Copies data from user space (possibly a *.rbf) to the CCAT FPGA's |
298 * Copies data from user space (possibly a *.rbf) to the CCAT FPGA's |
358 * configuration flash to user space. |
299 * configuration flash. |
359 * |
300 * |
360 * Return: the number of bytes written, or 0 if flash end is reached |
301 * Return: the number of bytes written, or 0 if flash end is reached |
361 */ |
302 */ |
362 |
|
363 static ssize_t ccat_update_write(struct file *const f, const char __user * buf, |
303 static ssize_t ccat_update_write(struct file *const f, const char __user * buf, |
364 size_t len, loff_t * off) |
304 size_t len, loff_t * off) |
365 { |
305 { |
366 struct update_buffer *const update = f->private_data; |
306 struct cdev_buffer *const buffer = f->private_data; |
367 |
307 |
368 if (*off + len > sizeof(update->data)) |
308 if (*off + len > buffer->ccdev->iosize) { |
369 return 0; |
309 return 0; |
370 |
310 } |
371 if (copy_from_user(update->data + *off, buf, len)) { |
311 |
|
312 if (copy_from_user(buffer->data + *off, buf, len)) { |
372 return -EFAULT; |
313 return -EFAULT; |
373 } |
314 } |
374 |
315 |
375 *off += len; |
316 *off += len; |
376 update->size = *off; |
317 buffer->size = *off; |
377 return len; |
318 return len; |
378 } |
319 } |
379 |
320 |
380 static struct file_operations update_ops = { |
321 static struct ccat_cdev dev_table[CCAT_DEVICES_MAX]; |
381 .owner = THIS_MODULE, |
322 static struct ccat_class cdev_class = { |
382 .open = ccat_update_open, |
323 .count = CCAT_DEVICES_MAX, |
383 .release = ccat_update_release, |
324 .devices = dev_table, |
384 .read = ccat_update_read, |
325 .name = "ccat_update", |
385 .write = ccat_update_write, |
326 .fops = { |
|
327 .owner = THIS_MODULE, |
|
328 .open = ccat_cdev_open, |
|
329 .release = ccat_update_release, |
|
330 .read = ccat_update_read, |
|
331 .write = ccat_update_write, |
|
332 }, |
386 }; |
333 }; |
387 |
334 |
388 /** |
335 static int ccat_update_probe(struct ccat_function *func) |
389 * ccat_get_prom_id() - Read CCAT PROM ID |
336 { |
390 * @ioaddr: address of the CCAT Update function in PCI config space |
337 static const u16 SUPPORTED_REVISION = 0x00; |
391 * |
338 |
392 * Return: the CCAT FPGA's PROM identifier |
339 if (SUPPORTED_REVISION != func->info.rev) { |
393 */ |
340 pr_warn("CCAT Update rev. %d not supported\n", func->info.rev); |
394 u8 ccat_get_prom_id(void __iomem * const ioaddr) |
341 return -ENODEV; |
395 { |
342 } |
396 ccat_update_cmd(ioaddr, CCAT_GET_PROM_ID); |
343 return ccat_cdev_probe(func, &cdev_class, CCAT_FLASH_SIZE); |
397 return ioread8(ioaddr + 0x38); |
344 } |
398 } |
345 |
399 |
346 const struct ccat_driver update_driver = { |
400 /** |
347 .type = CCATINFO_EPCS_PROM, |
401 * ccat_update_init() - Initialize the CCAT Update function |
348 .probe = ccat_update_probe, |
402 */ |
349 .remove = ccat_cdev_remove, |
403 struct ccat_update *ccat_update_init(const struct ccat_device *const ccatdev, |
350 .cdev_class = &cdev_class, |
404 void __iomem * const addr) |
351 }; |
405 { |
|
406 struct ccat_update *const update = kzalloc(sizeof(*update), GFP_KERNEL); |
|
407 |
|
408 if (!update) { |
|
409 return NULL; |
|
410 } |
|
411 kref_init(&update->refcount); |
|
412 update->ioaddr = ccatdev->bar[0].ioaddr + ioread32(addr + 0x8); |
|
413 memcpy_fromio(&update->info, addr, sizeof(update->info)); |
|
414 |
|
415 if (0x00 != update->info.rev) { |
|
416 pr_warn("CCAT Update rev. %d not supported\n", |
|
417 update->info.rev); |
|
418 goto cleanup; |
|
419 } |
|
420 |
|
421 if (alloc_chrdev_region(&update->dev, 0, 1, KBUILD_MODNAME)) { |
|
422 pr_warn("alloc_chrdev_region() failed\n"); |
|
423 goto cleanup; |
|
424 } |
|
425 |
|
426 update->class = class_create(THIS_MODULE, "ccat_update"); |
|
427 if (NULL == update->class) { |
|
428 pr_warn("Create device class failed\n"); |
|
429 goto cleanup; |
|
430 } |
|
431 |
|
432 if (NULL == |
|
433 device_create(update->class, NULL, update->dev, NULL, |
|
434 "ccat_update")) { |
|
435 pr_warn("device_create() failed\n"); |
|
436 goto cleanup; |
|
437 } |
|
438 |
|
439 cdev_init(&update->cdev, &update_ops); |
|
440 update->cdev.owner = THIS_MODULE; |
|
441 update->cdev.ops = &update_ops; |
|
442 if (cdev_add(&update->cdev, update->dev, 1)) { |
|
443 pr_warn("add update device failed\n"); |
|
444 goto cleanup; |
|
445 } |
|
446 return update; |
|
447 cleanup: |
|
448 kref_put(&update->refcount, ccat_update_destroy); |
|
449 return NULL; |
|
450 } |
|
451 |
|
452 /** |
|
453 * ccat_update_remove() - Prepare the CCAT Update function for removal |
|
454 */ |
|
455 void ccat_update_remove(struct ccat_update *update) |
|
456 { |
|
457 kref_put(&update->refcount, ccat_update_destroy); |
|
458 pr_debug("%s(): done\n", __FUNCTION__); |
|
459 } |
|