devices/ccat/update.c
branchstable-1.5
changeset 2579 273d15e0f301
parent 2573 ad9a35065387
child 2636 0613017547fe
equal deleted inserted replaced
2564:976381a3bd9e 2579:273d15e0f301
    21 #include <linux/fs.h>
    21 #include <linux/fs.h>
    22 #include <linux/kernel.h>
    22 #include <linux/kernel.h>
    23 #include <linux/module.h>
    23 #include <linux/module.h>
    24 #include <linux/sched.h>
    24 #include <linux/sched.h>
    25 #include <linux/uaccess.h>
    25 #include <linux/uaccess.h>
    26 #include "compat.h"
       
    27 #include "module.h"
    26 #include "module.h"
    28 #include "print.h"
       
    29 #include "update.h"
    27 #include "update.h"
    30 
    28 
    31 #define CCAT_DATA_IN_4 0x038
    29 #define CCAT_DATA_IN_4 0x038
    32 #define CCAT_DATA_IN_N 0x7F0
    30 #define CCAT_DATA_IN_N 0x7F0
    33 #define CCAT_DATA_OUT_4 0x030
    31 #define CCAT_DATA_OUT_4 0x030
    57 	struct ccat_update *update;
    55 	struct ccat_update *update;
    58 	char data[CCAT_FLASH_SIZE];
    56 	char data[CCAT_FLASH_SIZE];
    59 	size_t size;
    57 	size_t size;
    60 };
    58 };
    61 
    59 
    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 /**
    60 /**
    71  * wait_until_busy_reset() - wait until the busy flag was reset
    61  * wait_until_busy_reset() - wait until the busy flag was reset
    72  * @ioaddr: address of the CCAT Update function in PCI config space
    62  * @ioaddr: address of the CCAT Update function in PCI config space
    73  */
    63  */
    74 static inline void wait_until_busy_reset(void __iomem * const ioaddr)
    64 static inline void wait_until_busy_reset(void __iomem * const ioaddr)
    77 	while (ioread8(ioaddr + 1)) {
    67 	while (ioread8(ioaddr + 1)) {
    78 		schedule();
    68 		schedule();
    79 	}
    69 	}
    80 }
    70 }
    81 
    71 
       
    72 /**
       
    73  * __ccat_update_cmd() - Helper to issue a FPGA flash command
       
    74  * @ioaddr: address of the CCAT Update function in PCI config space
       
    75  * @cmd: the command identifier
       
    76  * @clocks: the number of clocks associated with the specified command
       
    77  *
       
    78  * no write memory barrier is called and the busy flag is not evaluated
       
    79  */
       
    80 static inline void __ccat_update_cmd(void __iomem * const ioaddr, u8 cmd,
       
    81 				     u16 clocks)
       
    82 {
       
    83 	iowrite8((0xff00 & clocks) >> 8, ioaddr);
       
    84 	iowrite8(0x00ff & clocks, ioaddr + 0x8);
       
    85 	iowrite8(cmd, ioaddr + 0x10);
       
    86 }
       
    87 
       
    88 /**
       
    89  * ccat_update_cmd() - Helper to issue a FPGA flash command
       
    90  * @ioaddr: address of the CCAT Update function in PCI config space
       
    91  * @cmd: the command identifier
       
    92  * @clocks: the number of clocks associated with the specified command
       
    93  *
       
    94  * Triggers a full flash command cycle with write memory barrier and
       
    95  * command activate. This call blocks until the busy flag is reset.
       
    96  */
       
    97 static inline void ccat_update_cmd(void __iomem * const ioaddr, u8 cmd,
       
    98 				   u16 clocks)
       
    99 {
       
   100 	__ccat_update_cmd(ioaddr, cmd, clocks);
       
   101 	wmb();
       
   102 	iowrite8(0xff, ioaddr + 0x7f8);
       
   103 	wait_until_busy_reset(ioaddr);
       
   104 }
       
   105 
       
   106 /**
       
   107  * ccat_update_cmd_addr() - Helper to issue a FPGA flash command with address parameter
       
   108  * @ioaddr: address of the CCAT Update function in PCI config space
       
   109  * @cmd: the command identifier
       
   110  * @clocks: the number of clocks associated with the specified command
       
   111  * @addr: 24 bit address associated with the specified command
       
   112  *
       
   113  * Triggers a full flash command cycle with write memory barrier and
       
   114  * command activate. This call blocks until the busy flag is reset.
       
   115  */
       
   116 static inline void ccat_update_cmd_addr(void __iomem * const ioaddr,
       
   117 					u8 cmd, u16 clocks, u32 addr)
       
   118 {
       
   119 	const u8 addr_0 = SWAP_BITS(addr & 0xff);
       
   120 	const u8 addr_1 = SWAP_BITS((addr & 0xff00) >> 8);
       
   121 	const u8 addr_2 = SWAP_BITS((addr & 0xff0000) >> 16);
       
   122 
       
   123 	__ccat_update_cmd(ioaddr, cmd, clocks);
       
   124 	iowrite8(addr_2, ioaddr + 0x18);
       
   125 	iowrite8(addr_1, ioaddr + 0x20);
       
   126 	iowrite8(addr_0, ioaddr + 0x28);
       
   127 	wmb();
       
   128 	iowrite8(0xff, ioaddr + 0x7f8);
       
   129 	wait_until_busy_reset(ioaddr);
       
   130 }
       
   131 
       
   132 /**
       
   133  * ccat_get_status() - Read CCAT Update status
       
   134  * @ioaddr: address of the CCAT Update function in PCI config space
       
   135  *
       
   136  * Return: the current status of the CCAT Update function
       
   137  */
       
   138 static u8 ccat_get_status(void __iomem * const ioaddr)
       
   139 {
       
   140 	ccat_update_cmd(ioaddr, CCAT_READ_STATUS);
       
   141 	return ioread8(ioaddr + 0x20);
       
   142 }
       
   143 
       
   144 /**
       
   145  * ccat_read_flash_block() - Read a block of CCAT configuration data from flash
       
   146  * @ioaddr: address of the CCAT Update function in PCI config space
       
   147  * @addr: 24 bit address of the block to read
       
   148  * @len: number of bytes to read from this block, len <= CCAT_DATA_BLOCK_SIZE
       
   149  * @buf: output buffer in user space
       
   150  *
       
   151  * Copies one block of configuration data from the CCAT FPGA's flash to
       
   152  * the user space buffer.
       
   153  * Note that the size of the FPGA's firmware is not known exactly so it
       
   154  * is very possible that the overall buffer ends with a lot of 0xff.
       
   155  *
       
   156  * Return: the number of bytes copied
       
   157  */
       
   158 static int ccat_read_flash_block(void __iomem * const ioaddr,
       
   159 				 const u32 addr, const u16 len,
       
   160 				 char __user * const buf)
       
   161 {
       
   162 	u16 i;
       
   163 	const u16 clocks = 8 * len;
       
   164 
       
   165 	ccat_update_cmd_addr(ioaddr, CCAT_READ_FLASH + clocks, addr);
       
   166 	for (i = 0; i < len; i++) {
       
   167 		put_user(ioread8(ioaddr + CCAT_DATA_IN_4 + 8 * i), buf + i);
       
   168 	}
       
   169 	return len;
       
   170 }
       
   171 
       
   172 /**
       
   173  * ccat_read_flash() - Read a chunk of CCAT configuration data from flash
       
   174  * @ioaddr: address of the CCAT Update function in PCI config space
       
   175  * @buf: output buffer in user space
       
   176  * @len: number of bytes to read
       
   177  * @off: offset in the configuration data
       
   178  *
       
   179  * Copies multiple blocks of configuration data from the CCAT FPGA's
       
   180  * flash to the user space buffer.
       
   181  *
       
   182  * Return: the number of bytes copied
       
   183  */
       
   184 static int ccat_read_flash(void __iomem * const ioaddr, char __user * buf,
       
   185 			   u32 len, loff_t * off)
       
   186 {
       
   187 	const loff_t start = *off;
       
   188 
       
   189 	while (len > CCAT_DATA_BLOCK_SIZE) {
       
   190 		*off +=
       
   191 		    ccat_read_flash_block(ioaddr, *off, CCAT_DATA_BLOCK_SIZE,
       
   192 					  buf);
       
   193 		buf += CCAT_DATA_BLOCK_SIZE;
       
   194 		len -= CCAT_DATA_BLOCK_SIZE;
       
   195 	}
       
   196 	*off += ccat_read_flash_block(ioaddr, *off, len, buf);
       
   197 	return *off - start;
       
   198 }
       
   199 
       
   200 /**
       
   201  * ccat_wait_status_cleared() - wait until CCAT status is cleared
       
   202  * @ioaddr: address of the CCAT Update function in PCI config space
       
   203  *
       
   204  * Blocks until bit 7 of the CCAT Update status is reset
       
   205  */
       
   206 static void ccat_wait_status_cleared(void __iomem * const ioaddr)
       
   207 {
       
   208 	u8 status;
       
   209 
       
   210 	do {
       
   211 		status = ccat_get_status(ioaddr);
       
   212 	} while (status & (1 << 7));
       
   213 }
       
   214 
       
   215 /**
       
   216  * ccat_write_flash_block() - Write a block of CCAT configuration data to flash
       
   217  * @ioaddr: address of the CCAT Update function in PCI config space
       
   218  * @addr: 24 bit start address in the CCAT FPGA's flash
       
   219  * @len: number of bytes to write in this block, len <= CCAT_WRITE_BLOCK_SIZE
       
   220  * @buf: input buffer
       
   221  *
       
   222  * Copies one block of configuration data to the CCAT FPGA's flash
       
   223  *
       
   224  * Return: the number of bytes copied
       
   225  */
       
   226 static int ccat_write_flash_block(void __iomem * const ioaddr,
       
   227 				  const u32 addr, const u16 len,
       
   228 				  const char *const buf)
       
   229 {
       
   230 	const u16 clocks = 8 * len;
       
   231 	u16 i;
       
   232 
       
   233 	ccat_update_cmd(ioaddr, CCAT_WRITE_ENABLE);
       
   234 	for (i = 0; i < len; i++) {
       
   235 		iowrite8(buf[i], ioaddr + CCAT_DATA_OUT_4 + 8 * i);
       
   236 	}
       
   237 	ccat_update_cmd_addr(ioaddr, CCAT_WRITE_FLASH + clocks, addr);
       
   238 	ccat_wait_status_cleared(ioaddr);
       
   239 	return len;
       
   240 }
       
   241 
       
   242 /**
       
   243  * ccat_write_flash() - Write a new CCAT configuration to FPGA's flash
       
   244  * @update: a CCAT Update buffer containing the new FPGA configuration
       
   245  */
       
   246 static void ccat_write_flash(const struct update_buffer *const update)
       
   247 {
       
   248 	const char *buf = update->data;
       
   249 	u32 off = 0;
       
   250 	size_t len = update->size;
       
   251 
       
   252 	while (len > CCAT_WRITE_BLOCK_SIZE) {
       
   253 		ccat_write_flash_block(update->update->ioaddr, off,
       
   254 				       (u16) CCAT_WRITE_BLOCK_SIZE, buf);
       
   255 		off += CCAT_WRITE_BLOCK_SIZE;
       
   256 		buf += CCAT_WRITE_BLOCK_SIZE;
       
   257 		len -= CCAT_WRITE_BLOCK_SIZE;
       
   258 	}
       
   259 	ccat_write_flash_block(update->update->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 
    82 static int ccat_update_open(struct inode *const i, struct file *const f)
   281 static int ccat_update_open(struct inode *const i, struct file *const f)
    83 {
   282 {
    84 	struct ccat_update *update =
   283 	struct ccat_update *update =
    85 	    container_of(i->i_cdev, struct ccat_update, cdev);
   284 	    container_of(i->i_cdev, struct ccat_update, cdev);
    86 	struct update_buffer *buf;
   285 	struct update_buffer *buf;
       
   286 
    87 	kref_get(&update->refcount);
   287 	kref_get(&update->refcount);
    88 	if (atomic_read(&update->refcount.refcount) > 2) {
   288 	if (atomic_read(&update->refcount.refcount) > 2) {
    89 		kref_put(&update->refcount, ccat_update_destroy);
   289 		kref_put(&update->refcount, ccat_update_destroy);
    90 		return -EBUSY;
   290 		return -EBUSY;
    91 	}
   291 	}
   103 
   303 
   104 static int ccat_update_release(struct inode *const i, struct file *const f)
   304 static int ccat_update_release(struct inode *const i, struct file *const f)
   105 {
   305 {
   106 	const struct update_buffer *const buf = f->private_data;
   306 	const struct update_buffer *const buf = f->private_data;
   107 	struct ccat_update *const update = buf->update;
   307 	struct ccat_update *const update = buf->update;
       
   308 
   108 	if (buf->size > 0) {
   309 	if (buf->size > 0) {
   109 		ccat_update_cmd(update->ioaddr, CCAT_WRITE_ENABLE);
   310 		ccat_update_cmd(update->ioaddr, CCAT_WRITE_ENABLE);
   110 		ccat_update_cmd(update->ioaddr, CCAT_BULK_ERASE);
   311 		ccat_update_cmd(update->ioaddr, CCAT_BULK_ERASE);
   111 		ccat_wait_status_cleared(update->ioaddr);
   312 		ccat_wait_status_cleared(update->ioaddr);
   112 		ccat_write_flash(buf);
   313 		ccat_write_flash(buf);
   131  */
   332  */
   132 static ssize_t ccat_update_read(struct file *const f, char __user * buf,
   333 static ssize_t ccat_update_read(struct file *const f, char __user * buf,
   133 				size_t len, loff_t * off)
   334 				size_t len, loff_t * off)
   134 {
   335 {
   135 	struct update_buffer *update = f->private_data;
   336 	struct update_buffer *update = f->private_data;
       
   337 
   136 	if (!buf || !off) {
   338 	if (!buf || !off) {
   137 		return -EINVAL;
   339 		return -EINVAL;
   138 	}
   340 	}
   139 	if (*off >= CCAT_FLASH_SIZE) {
   341 	if (*off >= CCAT_FLASH_SIZE) {
   140 		return 0;
   342 		return 0;
   160 
   362 
   161 static ssize_t ccat_update_write(struct file *const f, const char __user * buf,
   363 static ssize_t ccat_update_write(struct file *const f, const char __user * buf,
   162 				 size_t len, loff_t * off)
   364 				 size_t len, loff_t * off)
   163 {
   365 {
   164 	struct update_buffer *const update = f->private_data;
   366 	struct update_buffer *const update = f->private_data;
       
   367 
   165 	if (*off + len > sizeof(update->data))
   368 	if (*off + len > sizeof(update->data))
   166 		return 0;
   369 		return 0;
   167 
   370 
   168 	if (copy_from_user(update->data + *off, buf, len)) {
   371 	if (copy_from_user(update->data + *off, buf, len)) {
   169 		return -EFAULT;
   372 		return -EFAULT;
   181 	.read = ccat_update_read,
   384 	.read = ccat_update_read,
   182 	.write = ccat_update_write,
   385 	.write = ccat_update_write,
   183 };
   386 };
   184 
   387 
   185 /**
   388 /**
   186  * __ccat_update_cmd() - Helper to issue a FPGA flash command
       
   187  * @ioaddr: address of the CCAT Update function in PCI config space
       
   188  * @cmd: the command identifier
       
   189  * @clocks: the number of clocks associated with the specified command
       
   190  *
       
   191  * no write memory barrier is called and the busy flag is not evaluated
       
   192  */
       
   193 static inline void __ccat_update_cmd(void __iomem * const ioaddr, uint8_t cmd,
       
   194 				     uint16_t clocks)
       
   195 {
       
   196 	iowrite8((0xff00 & clocks) >> 8, ioaddr);
       
   197 	iowrite8(0x00ff & clocks, ioaddr + 0x8);
       
   198 	iowrite8(cmd, ioaddr + 0x10);
       
   199 }
       
   200 
       
   201 /**
       
   202  * ccat_update_cmd() - Helper to issue a FPGA flash command
       
   203  * @ioaddr: address of the CCAT Update function in PCI config space
       
   204  * @cmd: the command identifier
       
   205  * @clocks: the number of clocks associated with the specified command
       
   206  *
       
   207  * Triggers a full flash command cycle with write memory barrier and
       
   208  * command activate. This call blocks until the busy flag is reset.
       
   209  */
       
   210 static inline void ccat_update_cmd(void __iomem * const ioaddr, uint8_t cmd,
       
   211 				   uint16_t clocks)
       
   212 {
       
   213 	__ccat_update_cmd(ioaddr, cmd, clocks);
       
   214 	wmb();
       
   215 	iowrite8(0xff, ioaddr + 0x7f8);
       
   216 	wait_until_busy_reset(ioaddr);
       
   217 }
       
   218 
       
   219 /**
       
   220  * ccat_update_cmd_addr() - Helper to issue a FPGA flash command with address parameter
       
   221  * @ioaddr: address of the CCAT Update function in PCI config space
       
   222  * @cmd: the command identifier
       
   223  * @clocks: the number of clocks associated with the specified command
       
   224  * @addr: 24 bit address associated with the specified command
       
   225  *
       
   226  * Triggers a full flash command cycle with write memory barrier and
       
   227  * command activate. This call blocks until the busy flag is reset.
       
   228  */
       
   229 static inline void ccat_update_cmd_addr(void __iomem * const ioaddr,
       
   230 					uint8_t cmd, uint16_t clocks,
       
   231 					uint32_t addr)
       
   232 {
       
   233 	const uint8_t addr_0 = SWAP_BITS(addr & 0xff);
       
   234 	const uint8_t addr_1 = SWAP_BITS((addr & 0xff00) >> 8);
       
   235 	const uint8_t addr_2 = SWAP_BITS((addr & 0xff0000) >> 16);
       
   236 	__ccat_update_cmd(ioaddr, cmd, clocks);
       
   237 	iowrite8(addr_2, ioaddr + 0x18);
       
   238 	iowrite8(addr_1, ioaddr + 0x20);
       
   239 	iowrite8(addr_0, ioaddr + 0x28);
       
   240 	wmb();
       
   241 	iowrite8(0xff, ioaddr + 0x7f8);
       
   242 	wait_until_busy_reset(ioaddr);
       
   243 }
       
   244 
       
   245 /**
       
   246  * ccat_get_prom_id() - Read CCAT PROM ID
   389  * ccat_get_prom_id() - Read CCAT PROM ID
   247  * @ioaddr: address of the CCAT Update function in PCI config space
   390  * @ioaddr: address of the CCAT Update function in PCI config space
   248  *
   391  *
   249  * Return: the CCAT FPGA's PROM identifier
   392  * Return: the CCAT FPGA's PROM identifier
   250  */
   393  */
   251 uint8_t ccat_get_prom_id(void __iomem * const ioaddr)
   394 u8 ccat_get_prom_id(void __iomem * const ioaddr)
   252 {
   395 {
   253 	ccat_update_cmd(ioaddr, CCAT_GET_PROM_ID);
   396 	ccat_update_cmd(ioaddr, CCAT_GET_PROM_ID);
   254 	return ioread8(ioaddr + 0x38);
   397 	return ioread8(ioaddr + 0x38);
   255 }
   398 }
   256 
   399 
   257 /**
   400 /**
   258  * ccat_get_status() - Read CCAT Update status
       
   259  * @ioaddr: address of the CCAT Update function in PCI config space
       
   260  *
       
   261  * Return: the current status of the CCAT Update function
       
   262  */
       
   263 static uint8_t ccat_get_status(void __iomem * const ioaddr)
       
   264 {
       
   265 	ccat_update_cmd(ioaddr, CCAT_READ_STATUS);
       
   266 	return ioread8(ioaddr + 0x20);
       
   267 }
       
   268 
       
   269 /**
       
   270  * ccat_wait_status_cleared() - wait until CCAT status is cleared
       
   271  * @ioaddr: address of the CCAT Update function in PCI config space
       
   272  *
       
   273  * Blocks until bit 7 of the CCAT Update status is reset
       
   274  */
       
   275 
       
   276 static void ccat_wait_status_cleared(void __iomem * const ioaddr)
       
   277 {
       
   278 	uint8_t status;
       
   279 	do {
       
   280 		status = ccat_get_status(ioaddr);
       
   281 	} while (status & (1 << 7));
       
   282 }
       
   283 
       
   284 /**
       
   285  * ccat_read_flash_block() - Read a block of CCAT configuration data from flash
       
   286  * @ioaddr: address of the CCAT Update function in PCI config space
       
   287  * @addr: 24 bit address of the block to read
       
   288  * @len: number of bytes to read from this block, len <= CCAT_DATA_BLOCK_SIZE
       
   289  * @buf: output buffer in user space
       
   290  *
       
   291  * Copies one block of configuration data from the CCAT FPGA's flash to
       
   292  * the user space buffer.
       
   293  * Note that the size of the FPGA's firmware is not known exactly so it
       
   294  * is very possible that the overall buffer ends with a lot of 0xff.
       
   295  *
       
   296  * Return: the number of bytes copied
       
   297  */
       
   298 static int ccat_read_flash_block(void __iomem * const ioaddr,
       
   299 				 const uint32_t addr, const uint16_t len,
       
   300 				 char __user * const buf)
       
   301 {
       
   302 	uint16_t i;
       
   303 	const uint16_t clocks = 8 * len;
       
   304 	ccat_update_cmd_addr(ioaddr, CCAT_READ_FLASH + clocks, addr);
       
   305 	for (i = 0; i < len; i++) {
       
   306 		put_user(ioread8(ioaddr + CCAT_DATA_IN_4 + 8 * i), buf + i);
       
   307 	}
       
   308 	return len;
       
   309 }
       
   310 
       
   311 /**
       
   312  * ccat_read_flash() - Read a chunk of CCAT configuration data from flash
       
   313  * @ioaddr: address of the CCAT Update function in PCI config space
       
   314  * @buf: output buffer in user space
       
   315  * @len: number of bytes to read
       
   316  * @off: offset in the configuration data
       
   317  *
       
   318  * Copies multiple blocks of configuration data from the CCAT FPGA's
       
   319  * flash to the user space buffer.
       
   320  *
       
   321  * Return: the number of bytes copied
       
   322  */
       
   323 static int ccat_read_flash(void __iomem * const ioaddr, char __user * buf,
       
   324 			   uint32_t len, loff_t * off)
       
   325 {
       
   326 	const loff_t start = *off;
       
   327 	while (len > CCAT_DATA_BLOCK_SIZE) {
       
   328 		*off +=
       
   329 		    ccat_read_flash_block(ioaddr, *off, CCAT_DATA_BLOCK_SIZE,
       
   330 					  buf);
       
   331 		buf += CCAT_DATA_BLOCK_SIZE;
       
   332 		len -= CCAT_DATA_BLOCK_SIZE;
       
   333 	}
       
   334 	*off += ccat_read_flash_block(ioaddr, *off, len, buf);
       
   335 	return *off - start;
       
   336 }
       
   337 
       
   338 /**
       
   339  * ccat_write_flash_block() - Write a block of CCAT configuration data to flash
       
   340  * @ioaddr: address of the CCAT Update function in PCI config space
       
   341  * @addr: 24 bit start address in the CCAT FPGA's flash
       
   342  * @len: number of bytes to write in this block, len <= CCAT_WRITE_BLOCK_SIZE
       
   343  * @buf: input buffer
       
   344  *
       
   345  * Copies one block of configuration data to the CCAT FPGA's flash
       
   346  *
       
   347  * Return: the number of bytes copied
       
   348  */
       
   349 static int ccat_write_flash_block(void __iomem * const ioaddr,
       
   350 				  const uint32_t addr, const uint16_t len,
       
   351 				  const char *const buf)
       
   352 {
       
   353 	const uint16_t clocks = 8 * len;
       
   354 	uint16_t i;
       
   355 	ccat_update_cmd(ioaddr, CCAT_WRITE_ENABLE);
       
   356 	for (i = 0; i < len; i++) {
       
   357 		iowrite8(buf[i], ioaddr + CCAT_DATA_OUT_4 + 8 * i);
       
   358 	}
       
   359 	ccat_update_cmd_addr(ioaddr, CCAT_WRITE_FLASH + clocks, addr);
       
   360 	ccat_wait_status_cleared(ioaddr);
       
   361 	return len;
       
   362 }
       
   363 
       
   364 /**
       
   365  * ccat_write_flash() - Write a new CCAT configuration to FPGA's flash
       
   366  * @update: a CCAT Update buffer containing the new FPGA configuration
       
   367  */
       
   368 static void ccat_write_flash(const struct update_buffer *const update)
       
   369 {
       
   370 	const char *buf = update->data;
       
   371 	uint32_t off = 0;
       
   372 	size_t len = update->size;
       
   373 	while (len > CCAT_WRITE_BLOCK_SIZE) {
       
   374 		ccat_write_flash_block(update->update->ioaddr, off,
       
   375 				       (uint16_t) CCAT_WRITE_BLOCK_SIZE, buf);
       
   376 		off += CCAT_WRITE_BLOCK_SIZE;
       
   377 		buf += CCAT_WRITE_BLOCK_SIZE;
       
   378 		len -= CCAT_WRITE_BLOCK_SIZE;
       
   379 	}
       
   380 	ccat_write_flash_block(update->update->ioaddr, off, (uint16_t) len,
       
   381 			       buf);
       
   382 }
       
   383 
       
   384 /**
       
   385  * ccat_update_init() - Initialize the CCAT Update function
   401  * ccat_update_init() - Initialize the CCAT Update function
   386  */
   402  */
   387 struct ccat_update *ccat_update_init(const struct ccat_device *const ccatdev,
   403 struct ccat_update *ccat_update_init(const struct ccat_device *const ccatdev,
   388 				     void __iomem * const addr)
   404 				     void __iomem * const addr)
   389 {
   405 {
   390 	struct ccat_update *const update = kzalloc(sizeof(*update), GFP_KERNEL);
   406 	struct ccat_update *const update = kzalloc(sizeof(*update), GFP_KERNEL);
       
   407 
   391 	if (!update) {
   408 	if (!update) {
   392 		return NULL;
   409 		return NULL;
   393 	}
   410 	}
   394 	kref_init(&update->refcount);
   411 	kref_init(&update->refcount);
   395 	update->ioaddr = ccatdev->bar[0].ioaddr + ioread32(addr + 0x8);
   412 	update->ioaddr = ccatdev->bar[0].ioaddr + ioread32(addr + 0x8);
   396 	memcpy_fromio(&update->info, addr, sizeof(update->info));
   413 	memcpy_fromio(&update->info, addr, sizeof(update->info));
   397 	print_update_info(&update->info, update->ioaddr);
   414 
   398 
   415 	if (0x00 != update->info.rev) {
   399 	if (0x00 != update->info.nRevision) {
       
   400 		pr_warn("CCAT Update rev. %d not supported\n",
   416 		pr_warn("CCAT Update rev. %d not supported\n",
   401 			update->info.nRevision);
   417 			update->info.rev);
   402 		goto cleanup;
   418 		goto cleanup;
   403 	}
   419 	}
   404 
   420 
   405 	if (alloc_chrdev_region(&update->dev, 0, 1, DRV_NAME)) {
   421 	if (alloc_chrdev_region(&update->dev, 0, 1, KBUILD_MODNAME)) {
   406 		pr_warn("alloc_chrdev_region() failed\n");
   422 		pr_warn("alloc_chrdev_region() failed\n");
   407 		goto cleanup;
   423 		goto cleanup;
   408 	}
   424 	}
   409 
   425 
   410 	update->class = class_create(THIS_MODULE, "ccat_update");
   426 	update->class = class_create(THIS_MODULE, "ccat_update");
   432 	kref_put(&update->refcount, ccat_update_destroy);
   448 	kref_put(&update->refcount, ccat_update_destroy);
   433 	return NULL;
   449 	return NULL;
   434 }
   450 }
   435 
   451 
   436 /**
   452 /**
   437  * ccat_update_destroy() - Cleanup the CCAT Update function
       
   438  * @ref: pointer to a struct kref embedded into a struct ccat_update, which we intend to destroy
       
   439  *
       
   440  * Retrieves the parent struct ccat_update and destroys it.
       
   441  */
       
   442 static void ccat_update_destroy(struct kref *ref)
       
   443 {
       
   444 	struct ccat_update *update =
       
   445 	    container_of(ref, struct ccat_update, refcount);
       
   446 	cdev_del(&update->cdev);
       
   447 	device_destroy(update->class, update->dev);
       
   448 	class_destroy(update->class);
       
   449 	unregister_chrdev_region(update->dev, 1);
       
   450 	kfree(update);
       
   451 	pr_debug("%s(): done\n", __FUNCTION__);
       
   452 }
       
   453 
       
   454 /**
       
   455  * ccat_update_remove() - Prepare the CCAT Update function for removal
   453  * ccat_update_remove() - Prepare the CCAT Update function for removal
   456  */
   454  */
   457 void ccat_update_remove(struct ccat_update *update)
   455 void ccat_update_remove(struct ccat_update *update)
   458 {
   456 {
   459 	kref_put(&update->refcount, ccat_update_destroy);
   457 	kref_put(&update->refcount, ccat_update_destroy);