devices/ccat/update-3.4-ethercat.c
branchstable-1.5
changeset 2550 7e25950ea941
parent 2549 933a1b36b05f
child 2552 6e419c23b1b3
equal deleted inserted replaced
2549:933a1b36b05f 2550:7e25950ea941
     1 ../../../ccat/update.c
     1 /**
       
     2     Network Driver for Beckhoff CCAT communication controller
       
     3     Copyright (C) 2014  Beckhoff Automation GmbH
       
     4     Author: Patrick Bruenn <p.bruenn@beckhoff.com>
       
     5 
       
     6     This program is free software; you can redistribute it and/or modify
       
     7     it under the terms of the GNU General Public License as published by
       
     8     the Free Software Foundation; either version 2 of the License, or
       
     9     (at your option) any later version.
       
    10 
       
    11     This program is distributed in the hope that it will be useful,
       
    12     but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    14     GNU 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/kernel.h>
       
    23 #include <linux/module.h>
       
    24 #include <linux/sched.h>
       
    25 #include <linux/uaccess.h>
       
    26 
       
    27 #include "module.h"
       
    28 #include "print.h"
       
    29 #include "update.h"
       
    30 
       
    31 #define CCAT_DATA_IN_4 0x038
       
    32 #define CCAT_DATA_IN_N 0x7F0
       
    33 #define CCAT_DATA_OUT_4 0x030
       
    34 #define CCAT_DATA_BLOCK_SIZE (size_t)((CCAT_DATA_IN_N - CCAT_DATA_IN_4)/8)
       
    35 #define CCAT_WRITE_BLOCK_SIZE 128
       
    36 #define CCAT_FLASH_SIZE (size_t)0xE0000
       
    37 
       
    38 /**     FUNCTION_NAME            CMD,  CLOCKS          */
       
    39 #define CCAT_BULK_ERASE          0xE3, 8
       
    40 #define CCAT_GET_PROM_ID         0xD5, 40
       
    41 #define CCAT_READ_FLASH          0xC0, 32
       
    42 #define CCAT_READ_STATUS         0xA0, 16
       
    43 #define CCAT_WRITE_ENABLE        0x60, 8
       
    44 #define CCAT_WRITE_FLASH         0x40, 32
       
    45 
       
    46 /* from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits */
       
    47 #define SWAP_BITS(B) \
       
    48 	((((B) * 0x0802LU & 0x22110LU) | ((B) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16)
       
    49 
       
    50 /**
       
    51  * struct update_buffer - keep track of a CCAT FPGA update
       
    52  * @update: pointer to a valid ccat_update object
       
    53  * @data: buffer used for write operations
       
    54  * @size: number of bytes written to the data buffer, if 0 on ccat_update_release() no data will be written to FPGA
       
    55  */
       
    56 struct update_buffer {
       
    57 	struct ccat_update *update;
       
    58 	char data[CCAT_FLASH_SIZE];
       
    59 	size_t size;
       
    60 };
       
    61 
       
    62 static void ccat_wait_status_cleared(void __iomem * const ioaddr);
       
    63 static int ccat_read_flash(void __iomem * const ioaddr, char __user * buf,
       
    64 			   uint32_t len, loff_t * off);
       
    65 static void ccat_write_flash(const struct update_buffer *const buf);
       
    66 static void ccat_update_cmd(void __iomem * const ioaddr, uint8_t cmd,
       
    67 			    uint16_t clocks);
       
    68 static void ccat_update_destroy(struct kref *ref);
       
    69 
       
    70 /**
       
    71  * wait_until_busy_reset() - wait until the busy flag was reset
       
    72  * @ioaddr: address of the CCAT Update function in PCI config space
       
    73  */
       
    74 static inline void wait_until_busy_reset(void __iomem * const ioaddr)
       
    75 {
       
    76 	wmb();
       
    77 	while (ioread8(ioaddr + 1)) {
       
    78 		schedule();
       
    79 	}
       
    80 }
       
    81 
       
    82 static int ccat_update_open(struct inode *const i, struct file *const f)
       
    83 {
       
    84 	struct ccat_update *update =
       
    85 	    container_of(i->i_cdev, struct ccat_update, cdev);
       
    86 	struct update_buffer *buf;
       
    87 	kref_get(&update->refcount);
       
    88 	if (atomic_read(&update->refcount.refcount) > 2) {
       
    89 		kref_put(&update->refcount, ccat_update_destroy);
       
    90 		return -EBUSY;
       
    91 	}
       
    92 
       
    93 	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
       
    94 	if (!buf) {
       
    95 		kref_put(&update->refcount, ccat_update_destroy);
       
    96 		return -ENOMEM;
       
    97 	}
       
    98 
       
    99 	buf->update = update;
       
   100 	f->private_data = buf;
       
   101 	return 0;
       
   102 }
       
   103 
       
   104 static int ccat_update_release(struct inode *const i, struct file *const f)
       
   105 {
       
   106 	const struct update_buffer *const buf = f->private_data;
       
   107 	struct ccat_update *const update = buf->update;
       
   108 	if (buf->size > 0) {
       
   109 		ccat_update_cmd(update->ioaddr, CCAT_WRITE_ENABLE);
       
   110 		ccat_update_cmd(update->ioaddr, CCAT_BULK_ERASE);
       
   111 		ccat_wait_status_cleared(update->ioaddr);
       
   112 		ccat_write_flash(buf);
       
   113 	}
       
   114 	kfree(f->private_data);
       
   115 	kref_put(&update->refcount, ccat_update_destroy);
       
   116 	return 0;
       
   117 }
       
   118 
       
   119 /**
       
   120  * ccat_update_read() - Read CCAT configuration data from flash
       
   121  * @f: file handle previously initialized with ccat_update_open()
       
   122  * @buf: buffer in user space provided for our data
       
   123  * @len: length of the user space buffer
       
   124  * @off: current offset of our file operation
       
   125  *
       
   126  * Copies data from the CCAT FPGA's configuration flash to user space.
       
   127  * Note that the size of the FPGA's firmware is not known exactly so it
       
   128  * is very possible that the overall buffer ends with a lot of 0xff.
       
   129  *
       
   130  * Return: the number of bytes written, or 0 if EOF reached
       
   131  */
       
   132 static ssize_t ccat_update_read(struct file *const f, char __user * buf,
       
   133 				size_t len, loff_t * off)
       
   134 {
       
   135 	struct update_buffer *update = f->private_data;
       
   136 	if (!buf || !off) {
       
   137 		return -EINVAL;
       
   138 	}
       
   139 	if (*off >= CCAT_FLASH_SIZE) {
       
   140 		return 0;
       
   141 	}
       
   142 	if (*off + len >= CCAT_FLASH_SIZE) {
       
   143 		len = CCAT_FLASH_SIZE - *off;
       
   144 	}
       
   145 	return ccat_read_flash(update->update->ioaddr, buf, len, off);
       
   146 }
       
   147 
       
   148 /**
       
   149  * ccat_update_write() - Write data to the CCAT FPGA's configuration flash
       
   150  * @f: file handle previously initialized with ccat_update_open()
       
   151  * @buf: buffer in user space providing the new configuration data (from *.rbf)
       
   152  * @len: length of the user space buffer
       
   153  * @off: current offset in the configuration data
       
   154  *
       
   155  * Copies data from user space (possibly a *.rbf) to the CCAT FPGA's
       
   156  * configuration flash to user space.
       
   157  *
       
   158  * Return: the number of bytes written, or 0 if flash end is reached
       
   159  */
       
   160 
       
   161 static ssize_t ccat_update_write(struct file *const f, const char __user * buf,
       
   162 				 size_t len, loff_t * off)
       
   163 {
       
   164 	struct update_buffer *const update = f->private_data;
       
   165 	if (*off + len > sizeof(update->data))
       
   166 		return 0;
       
   167 
       
   168 	copy_from_user(update->data + *off, buf, len);
       
   169 	*off += len;
       
   170 	update->size = *off;
       
   171 	return len;
       
   172 }
       
   173 
       
   174 static struct file_operations update_ops = {
       
   175 	.owner = THIS_MODULE,
       
   176 	.open = ccat_update_open,
       
   177 	.release = ccat_update_release,
       
   178 	.read = ccat_update_read,
       
   179 	.write = ccat_update_write,
       
   180 };
       
   181 
       
   182 /**
       
   183  * __ccat_update_cmd() - Helper to issue a FPGA flash command
       
   184  * @ioaddr: address of the CCAT Update function in PCI config space
       
   185  * @cmd: the command identifier
       
   186  * @clocks: the number of clocks associated with the specified command
       
   187  *
       
   188  * no write memory barrier is called and the busy flag is not evaluated
       
   189  */
       
   190 static inline void __ccat_update_cmd(void __iomem * const ioaddr, uint8_t cmd,
       
   191 				     uint16_t clocks)
       
   192 {
       
   193 	iowrite8((0xff00 & clocks) >> 8, ioaddr);
       
   194 	iowrite8(0x00ff & clocks, ioaddr + 0x8);
       
   195 	iowrite8(cmd, ioaddr + 0x10);
       
   196 }
       
   197 
       
   198 /**
       
   199  * ccat_update_cmd() - Helper to issue a FPGA flash command
       
   200  * @ioaddr: address of the CCAT Update function in PCI config space
       
   201  * @cmd: the command identifier
       
   202  * @clocks: the number of clocks associated with the specified command
       
   203  *
       
   204  * Triggers a full flash command cycle with write memory barrier and
       
   205  * command activate. This call blocks until the busy flag is reset.
       
   206  */
       
   207 static inline void ccat_update_cmd(void __iomem * const ioaddr, uint8_t cmd,
       
   208 				   uint16_t clocks)
       
   209 {
       
   210 	__ccat_update_cmd(ioaddr, cmd, clocks);
       
   211 	wmb();
       
   212 	iowrite8(0xff, ioaddr + 0x7f8);
       
   213 	wait_until_busy_reset(ioaddr);
       
   214 }
       
   215 
       
   216 /**
       
   217  * ccat_update_cmd_addr() - Helper to issue a FPGA flash command with address parameter
       
   218  * @ioaddr: address of the CCAT Update function in PCI config space
       
   219  * @cmd: the command identifier
       
   220  * @clocks: the number of clocks associated with the specified command
       
   221  * @addr: 24 bit address associated with the specified command
       
   222  *
       
   223  * Triggers a full flash command cycle with write memory barrier and
       
   224  * command activate. This call blocks until the busy flag is reset.
       
   225  */
       
   226 static inline void ccat_update_cmd_addr(void __iomem * const ioaddr,
       
   227 					uint8_t cmd, uint16_t clocks,
       
   228 					uint32_t addr)
       
   229 {
       
   230 	const uint8_t addr_0 = SWAP_BITS(addr & 0xff);
       
   231 	const uint8_t addr_1 = SWAP_BITS((addr & 0xff00) >> 8);
       
   232 	const uint8_t addr_2 = SWAP_BITS((addr & 0xff0000) >> 16);
       
   233 	__ccat_update_cmd(ioaddr, cmd, clocks);
       
   234 	iowrite8(addr_2, ioaddr + 0x18);
       
   235 	iowrite8(addr_1, ioaddr + 0x20);
       
   236 	iowrite8(addr_0, ioaddr + 0x28);
       
   237 	wmb();
       
   238 	iowrite8(0xff, ioaddr + 0x7f8);
       
   239 	wait_until_busy_reset(ioaddr);
       
   240 }
       
   241 
       
   242 /**
       
   243  * ccat_get_prom_id() - Read CCAT PROM ID
       
   244  * @ioaddr: address of the CCAT Update function in PCI config space
       
   245  *
       
   246  * Return: the CCAT FPGA's PROM identifier
       
   247  */
       
   248 uint8_t ccat_get_prom_id(void __iomem * const ioaddr)
       
   249 {
       
   250 	ccat_update_cmd(ioaddr, CCAT_GET_PROM_ID);
       
   251 	return ioread8(ioaddr + 0x38);
       
   252 }
       
   253 
       
   254 /**
       
   255  * ccat_get_status() - Read CCAT Update status
       
   256  * @ioaddr: address of the CCAT Update function in PCI config space
       
   257  *
       
   258  * Return: the current status of the CCAT Update function
       
   259  */
       
   260 static uint8_t ccat_get_status(void __iomem * const ioaddr)
       
   261 {
       
   262 	ccat_update_cmd(ioaddr, CCAT_READ_STATUS);
       
   263 	return ioread8(ioaddr + 0x20);
       
   264 }
       
   265 
       
   266 /**
       
   267  * ccat_wait_status_cleared() - wait until CCAT status is cleared
       
   268  * @ioaddr: address of the CCAT Update function in PCI config space
       
   269  *
       
   270  * Blocks until bit 7 of the CCAT Update status is reset
       
   271  */
       
   272 
       
   273 static void ccat_wait_status_cleared(void __iomem * const ioaddr)
       
   274 {
       
   275 	uint8_t status;
       
   276 	do {
       
   277 		status = ccat_get_status(ioaddr);
       
   278 	} while (status & (1 << 7));
       
   279 }
       
   280 
       
   281 /**
       
   282  * ccat_read_flash_block() - Read a block of CCAT configuration data from flash
       
   283  * @ioaddr: address of the CCAT Update function in PCI config space
       
   284  * @addr: 24 bit address of the block to read
       
   285  * @len: number of bytes to read from this block, len <= CCAT_DATA_BLOCK_SIZE
       
   286  * @buf: output buffer in user space
       
   287  *
       
   288  * Copies one block of configuration data from the CCAT FPGA's flash to
       
   289  * the user space buffer.
       
   290  * Note that the size of the FPGA's firmware is not known exactly so it
       
   291  * is very possible that the overall buffer ends with a lot of 0xff.
       
   292  *
       
   293  * Return: the number of bytes copied
       
   294  */
       
   295 static int ccat_read_flash_block(void __iomem * const ioaddr,
       
   296 				 const uint32_t addr, const uint16_t len,
       
   297 				 char __user * const buf)
       
   298 {
       
   299 	uint16_t i;
       
   300 	const uint16_t clocks = 8 * len;
       
   301 	ccat_update_cmd_addr(ioaddr, CCAT_READ_FLASH + clocks, addr);
       
   302 	for (i = 0; i < len; i++) {
       
   303 		put_user(ioread8(ioaddr + CCAT_DATA_IN_4 + 8 * i), buf + i);
       
   304 	}
       
   305 	return len;
       
   306 }
       
   307 
       
   308 /**
       
   309  * ccat_read_flash() - Read a chunk of CCAT configuration data from flash
       
   310  * @ioaddr: address of the CCAT Update function in PCI config space
       
   311  * @buf: output buffer in user space
       
   312  * @len: number of bytes to read
       
   313  * @off: offset in the configuration data
       
   314  *
       
   315  * Copies multiple blocks of configuration data from the CCAT FPGA's
       
   316  * flash to the user space buffer.
       
   317  *
       
   318  * Return: the number of bytes copied
       
   319  */
       
   320 static int ccat_read_flash(void __iomem * const ioaddr, char __user * buf,
       
   321 			   uint32_t len, loff_t * off)
       
   322 {
       
   323 	const loff_t start = *off;
       
   324 	while (len > CCAT_DATA_BLOCK_SIZE) {
       
   325 		*off +=
       
   326 		    ccat_read_flash_block(ioaddr, *off, CCAT_DATA_BLOCK_SIZE,
       
   327 					  buf);
       
   328 		buf += CCAT_DATA_BLOCK_SIZE;
       
   329 		len -= CCAT_DATA_BLOCK_SIZE;
       
   330 	}
       
   331 	*off += ccat_read_flash_block(ioaddr, *off, len, buf);
       
   332 	return *off - start;
       
   333 }
       
   334 
       
   335 /**
       
   336  * ccat_write_flash_block() - Write a block of CCAT configuration data to flash
       
   337  * @ioaddr: address of the CCAT Update function in PCI config space
       
   338  * @addr: 24 bit start address in the CCAT FPGA's flash
       
   339  * @len: number of bytes to write in this block, len <= CCAT_WRITE_BLOCK_SIZE
       
   340  * @buf: input buffer
       
   341  *
       
   342  * Copies one block of configuration data to the CCAT FPGA's flash
       
   343  *
       
   344  * Return: the number of bytes copied
       
   345  */
       
   346 static int ccat_write_flash_block(void __iomem * const ioaddr,
       
   347 				  const uint32_t addr, const uint16_t len,
       
   348 				  const char *const buf)
       
   349 {
       
   350 	const uint16_t clocks = 8 * len;
       
   351 	uint16_t i;
       
   352 	ccat_update_cmd(ioaddr, CCAT_WRITE_ENABLE);
       
   353 	for (i = 0; i < len; i++) {
       
   354 		iowrite8(buf[i], ioaddr + CCAT_DATA_OUT_4 + 8 * i);
       
   355 	}
       
   356 	ccat_update_cmd_addr(ioaddr, CCAT_WRITE_FLASH + clocks, addr);
       
   357 	ccat_wait_status_cleared(ioaddr);
       
   358 	return len;
       
   359 }
       
   360 
       
   361 /**
       
   362  * ccat_write_flash() - Write a new CCAT configuration to FPGA's flash
       
   363  * @update: a CCAT Update buffer containing the new FPGA configuration
       
   364  */
       
   365 static void ccat_write_flash(const struct update_buffer *const update)
       
   366 {
       
   367 	const char *buf = update->data;
       
   368 	uint32_t off = 0;
       
   369 	size_t len = update->size;
       
   370 	while (len > CCAT_WRITE_BLOCK_SIZE) {
       
   371 		ccat_write_flash_block(update->update->ioaddr, off,
       
   372 				       (uint16_t) CCAT_WRITE_BLOCK_SIZE, buf);
       
   373 		off += CCAT_WRITE_BLOCK_SIZE;
       
   374 		buf += CCAT_WRITE_BLOCK_SIZE;
       
   375 		len -= CCAT_WRITE_BLOCK_SIZE;
       
   376 	}
       
   377 	ccat_write_flash_block(update->update->ioaddr, off, (uint16_t) len,
       
   378 			       buf);
       
   379 }
       
   380 
       
   381 /**
       
   382  * ccat_update_init() - Initialize the CCAT Update function
       
   383  */
       
   384 struct ccat_update *ccat_update_init(const struct ccat_device *const ccatdev,
       
   385 				     void __iomem * const addr)
       
   386 {
       
   387 	struct ccat_update *const update = kzalloc(sizeof(*update), GFP_KERNEL);
       
   388 	if (!update) {
       
   389 		return NULL;
       
   390 	}
       
   391 	kref_init(&update->refcount);
       
   392 	update->ioaddr = ccatdev->bar[0].ioaddr + ioread32(addr + 0x8);
       
   393 	memcpy_fromio(&update->info, addr, sizeof(update->info));
       
   394 	print_update_info(&update->info, update->ioaddr);
       
   395 
       
   396 	if (0x00 != update->info.nRevision) {
       
   397 		pr_warn("CCAT Update rev. %d not supported\n",
       
   398 			update->info.nRevision);
       
   399 		goto cleanup;
       
   400 	}
       
   401 
       
   402 	if (alloc_chrdev_region(&update->dev, 0, 1, DRV_NAME)) {
       
   403 		pr_warn("alloc_chrdev_region() failed\n");
       
   404 		goto cleanup;
       
   405 	}
       
   406 
       
   407 	update->class = class_create(THIS_MODULE, "ccat_update");
       
   408 	if (NULL == update->class) {
       
   409 		pr_warn("Create device class failed\n");
       
   410 		goto cleanup;
       
   411 	}
       
   412 
       
   413 	if (NULL ==
       
   414 	    device_create(update->class, NULL, update->dev, NULL,
       
   415 			  "ccat_update")) {
       
   416 		pr_warn("device_create() failed\n");
       
   417 		goto cleanup;
       
   418 	}
       
   419 
       
   420 	cdev_init(&update->cdev, &update_ops);
       
   421 	update->cdev.owner = THIS_MODULE;
       
   422 	update->cdev.ops = &update_ops;
       
   423 	if (cdev_add(&update->cdev, update->dev, 1)) {
       
   424 		pr_warn("add update device failed\n");
       
   425 		goto cleanup;
       
   426 	}
       
   427 	return update;
       
   428 cleanup:
       
   429 	kref_put(&update->refcount, ccat_update_destroy);
       
   430 	return NULL;
       
   431 }
       
   432 
       
   433 /**
       
   434  * ccat_update_destroy() - Cleanup the CCAT Update function
       
   435  * @ref: pointer to a struct kref embedded into a struct ccat_update, which we intend to destroy
       
   436  *
       
   437  * Retrieves the parent struct ccat_update and destroys it.
       
   438  */
       
   439 static void ccat_update_destroy(struct kref *ref)
       
   440 {
       
   441 	struct ccat_update *update =
       
   442 	    container_of(ref, struct ccat_update, refcount);
       
   443 	cdev_del(&update->cdev);
       
   444 	device_destroy(update->class, update->dev);
       
   445 	class_destroy(update->class);
       
   446 	unregister_chrdev_region(update->dev, 1);
       
   447 	kfree(update);
       
   448 	pr_debug("%s(): done\n", __FUNCTION__);
       
   449 }
       
   450 
       
   451 /**
       
   452  * ccat_update_remove() - Prepare the CCAT Update function for removal
       
   453  */
       
   454 void ccat_update_remove(struct ccat_update *update)
       
   455 {
       
   456 	kref_put(&update->refcount, ccat_update_destroy);
       
   457 	pr_debug("%s(): done\n", __FUNCTION__);
       
   458 }