devices/ccat/update.c
branchstable-1.5
changeset 2636 0613017547fe
parent 2573 ad9a35065387
child 2638 5995331a55fe
equal deleted inserted replaced
2599:4b0b906df1b4 2636:0613017547fe
    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
    44 /* from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits */
    43 /* from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits */
    45 #define SWAP_BITS(B) \
    44 #define SWAP_BITS(B) \
    46 	((((B) * 0x0802LU & 0x22110LU) | ((B) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16)
    45 	((((B) * 0x0802LU & 0x22110LU) | ((B) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16)
    47 
    46 
    48 /**
    47 /**
    49  * struct update_buffer - keep track of a CCAT FPGA update
       
    50  * @update: pointer to a valid ccat_update object
       
    51  * @data: buffer used for write operations
       
    52  * @size: number of bytes written to the data buffer, if 0 on ccat_update_release() no data will be written to FPGA
       
    53  */
       
    54 struct update_buffer {
       
    55 	struct ccat_update *update;
       
    56 	char data[CCAT_FLASH_SIZE];
       
    57 	size_t size;
       
    58 };
       
    59 
       
    60 /**
       
    61  * wait_until_busy_reset() - wait until the busy flag was reset
    48  * wait_until_busy_reset() - wait until the busy flag was reset
    62  * @ioaddr: address of the CCAT Update function in PCI config space
    49  * @ioaddr: address of the CCAT Update function in PCI config space
    63  */
    50  */
    64 static inline void wait_until_busy_reset(void __iomem * const ioaddr)
    51 static inline void wait_until_busy_reset(void __iomem * const ioaddr)
    65 {
    52 {
   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 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 }