59 size_t size; |
59 size_t size; |
60 }; |
60 }; |
61 |
61 |
62 static void ccat_wait_status_cleared(void __iomem * const ioaddr); |
62 static void ccat_wait_status_cleared(void __iomem * const ioaddr); |
63 static int ccat_read_flash(void __iomem * const ioaddr, char __user * buf, |
63 static int ccat_read_flash(void __iomem * const ioaddr, char __user * buf, |
64 uint32_t len, loff_t * off); |
64 u32 len, loff_t * off); |
65 static void ccat_write_flash(const struct update_buffer *const buf); |
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, |
66 static void ccat_update_cmd(void __iomem * const ioaddr, u8 cmd, u16 clocks); |
67 uint16_t clocks); |
|
68 static void ccat_update_destroy(struct kref *ref); |
67 static void ccat_update_destroy(struct kref *ref); |
69 |
68 |
70 /** |
69 /** |
71 * wait_until_busy_reset() - wait until the busy flag was reset |
70 * wait_until_busy_reset() - wait until the busy flag was reset |
72 * @ioaddr: address of the CCAT Update function in PCI config space |
71 * @ioaddr: address of the CCAT Update function in PCI config space |
82 static int ccat_update_open(struct inode *const i, struct file *const f) |
81 static int ccat_update_open(struct inode *const i, struct file *const f) |
83 { |
82 { |
84 struct ccat_update *update = |
83 struct ccat_update *update = |
85 container_of(i->i_cdev, struct ccat_update, cdev); |
84 container_of(i->i_cdev, struct ccat_update, cdev); |
86 struct update_buffer *buf; |
85 struct update_buffer *buf; |
|
86 |
87 kref_get(&update->refcount); |
87 kref_get(&update->refcount); |
88 if (atomic_read(&update->refcount.refcount) > 2) { |
88 if (atomic_read(&update->refcount.refcount) > 2) { |
89 kref_put(&update->refcount, ccat_update_destroy); |
89 kref_put(&update->refcount, ccat_update_destroy); |
90 return -EBUSY; |
90 return -EBUSY; |
91 } |
91 } |
103 |
103 |
104 static int ccat_update_release(struct inode *const i, struct file *const f) |
104 static int ccat_update_release(struct inode *const i, struct file *const f) |
105 { |
105 { |
106 const struct update_buffer *const buf = f->private_data; |
106 const struct update_buffer *const buf = f->private_data; |
107 struct ccat_update *const update = buf->update; |
107 struct ccat_update *const update = buf->update; |
|
108 |
108 if (buf->size > 0) { |
109 if (buf->size > 0) { |
109 ccat_update_cmd(update->ioaddr, CCAT_WRITE_ENABLE); |
110 ccat_update_cmd(update->ioaddr, CCAT_WRITE_ENABLE); |
110 ccat_update_cmd(update->ioaddr, CCAT_BULK_ERASE); |
111 ccat_update_cmd(update->ioaddr, CCAT_BULK_ERASE); |
111 ccat_wait_status_cleared(update->ioaddr); |
112 ccat_wait_status_cleared(update->ioaddr); |
112 ccat_write_flash(buf); |
113 ccat_write_flash(buf); |
131 */ |
132 */ |
132 static ssize_t ccat_update_read(struct file *const f, char __user * buf, |
133 static ssize_t ccat_update_read(struct file *const f, char __user * buf, |
133 size_t len, loff_t * off) |
134 size_t len, loff_t * off) |
134 { |
135 { |
135 struct update_buffer *update = f->private_data; |
136 struct update_buffer *update = f->private_data; |
|
137 |
136 if (!buf || !off) { |
138 if (!buf || !off) { |
137 return -EINVAL; |
139 return -EINVAL; |
138 } |
140 } |
139 if (*off >= CCAT_FLASH_SIZE) { |
141 if (*off >= CCAT_FLASH_SIZE) { |
140 return 0; |
142 return 0; |
160 |
162 |
161 static ssize_t ccat_update_write(struct file *const f, const char __user * buf, |
163 static ssize_t ccat_update_write(struct file *const f, const char __user * buf, |
162 size_t len, loff_t * off) |
164 size_t len, loff_t * off) |
163 { |
165 { |
164 struct update_buffer *const update = f->private_data; |
166 struct update_buffer *const update = f->private_data; |
|
167 |
165 if (*off + len > sizeof(update->data)) |
168 if (*off + len > sizeof(update->data)) |
166 return 0; |
169 return 0; |
167 |
170 |
168 if (copy_from_user(update->data + *off, buf, len)) { |
171 if (copy_from_user(update->data + *off, buf, len)) { |
169 return -EFAULT; |
172 return -EFAULT; |
188 * @cmd: the command identifier |
191 * @cmd: the command identifier |
189 * @clocks: the number of clocks associated with the specified command |
192 * @clocks: the number of clocks associated with the specified command |
190 * |
193 * |
191 * no write memory barrier is called and the busy flag is not evaluated |
194 * no write memory barrier is called and the busy flag is not evaluated |
192 */ |
195 */ |
193 static inline void __ccat_update_cmd(void __iomem * const ioaddr, uint8_t cmd, |
196 static inline void __ccat_update_cmd(void __iomem * const ioaddr, u8 cmd, |
194 uint16_t clocks) |
197 u16 clocks) |
195 { |
198 { |
196 iowrite8((0xff00 & clocks) >> 8, ioaddr); |
199 iowrite8((0xff00 & clocks) >> 8, ioaddr); |
197 iowrite8(0x00ff & clocks, ioaddr + 0x8); |
200 iowrite8(0x00ff & clocks, ioaddr + 0x8); |
198 iowrite8(cmd, ioaddr + 0x10); |
201 iowrite8(cmd, ioaddr + 0x10); |
199 } |
202 } |
205 * @clocks: the number of clocks associated with the specified command |
208 * @clocks: the number of clocks associated with the specified command |
206 * |
209 * |
207 * Triggers a full flash command cycle with write memory barrier and |
210 * Triggers a full flash command cycle with write memory barrier and |
208 * command activate. This call blocks until the busy flag is reset. |
211 * command activate. This call blocks until the busy flag is reset. |
209 */ |
212 */ |
210 static inline void ccat_update_cmd(void __iomem * const ioaddr, uint8_t cmd, |
213 static inline void ccat_update_cmd(void __iomem * const ioaddr, u8 cmd, |
211 uint16_t clocks) |
214 u16 clocks) |
212 { |
215 { |
213 __ccat_update_cmd(ioaddr, cmd, clocks); |
216 __ccat_update_cmd(ioaddr, cmd, clocks); |
214 wmb(); |
217 wmb(); |
215 iowrite8(0xff, ioaddr + 0x7f8); |
218 iowrite8(0xff, ioaddr + 0x7f8); |
216 wait_until_busy_reset(ioaddr); |
219 wait_until_busy_reset(ioaddr); |
225 * |
228 * |
226 * Triggers a full flash command cycle with write memory barrier and |
229 * Triggers a full flash command cycle with write memory barrier and |
227 * command activate. This call blocks until the busy flag is reset. |
230 * command activate. This call blocks until the busy flag is reset. |
228 */ |
231 */ |
229 static inline void ccat_update_cmd_addr(void __iomem * const ioaddr, |
232 static inline void ccat_update_cmd_addr(void __iomem * const ioaddr, |
230 uint8_t cmd, uint16_t clocks, |
233 u8 cmd, u16 clocks, u32 addr) |
231 uint32_t addr) |
234 { |
232 { |
235 const u8 addr_0 = SWAP_BITS(addr & 0xff); |
233 const uint8_t addr_0 = SWAP_BITS(addr & 0xff); |
236 const u8 addr_1 = SWAP_BITS((addr & 0xff00) >> 8); |
234 const uint8_t addr_1 = SWAP_BITS((addr & 0xff00) >> 8); |
237 const u8 addr_2 = SWAP_BITS((addr & 0xff0000) >> 16); |
235 const uint8_t addr_2 = SWAP_BITS((addr & 0xff0000) >> 16); |
238 |
236 __ccat_update_cmd(ioaddr, cmd, clocks); |
239 __ccat_update_cmd(ioaddr, cmd, clocks); |
237 iowrite8(addr_2, ioaddr + 0x18); |
240 iowrite8(addr_2, ioaddr + 0x18); |
238 iowrite8(addr_1, ioaddr + 0x20); |
241 iowrite8(addr_1, ioaddr + 0x20); |
239 iowrite8(addr_0, ioaddr + 0x28); |
242 iowrite8(addr_0, ioaddr + 0x28); |
240 wmb(); |
243 wmb(); |
246 * ccat_get_prom_id() - Read CCAT PROM ID |
249 * ccat_get_prom_id() - Read CCAT PROM ID |
247 * @ioaddr: address of the CCAT Update function in PCI config space |
250 * @ioaddr: address of the CCAT Update function in PCI config space |
248 * |
251 * |
249 * Return: the CCAT FPGA's PROM identifier |
252 * Return: the CCAT FPGA's PROM identifier |
250 */ |
253 */ |
251 uint8_t ccat_get_prom_id(void __iomem * const ioaddr) |
254 u8 ccat_get_prom_id(void __iomem * const ioaddr) |
252 { |
255 { |
253 ccat_update_cmd(ioaddr, CCAT_GET_PROM_ID); |
256 ccat_update_cmd(ioaddr, CCAT_GET_PROM_ID); |
254 return ioread8(ioaddr + 0x38); |
257 return ioread8(ioaddr + 0x38); |
255 } |
258 } |
256 |
259 |
258 * ccat_get_status() - Read CCAT Update status |
261 * ccat_get_status() - Read CCAT Update status |
259 * @ioaddr: address of the CCAT Update function in PCI config space |
262 * @ioaddr: address of the CCAT Update function in PCI config space |
260 * |
263 * |
261 * Return: the current status of the CCAT Update function |
264 * Return: the current status of the CCAT Update function |
262 */ |
265 */ |
263 static uint8_t ccat_get_status(void __iomem * const ioaddr) |
266 static u8 ccat_get_status(void __iomem * const ioaddr) |
264 { |
267 { |
265 ccat_update_cmd(ioaddr, CCAT_READ_STATUS); |
268 ccat_update_cmd(ioaddr, CCAT_READ_STATUS); |
266 return ioread8(ioaddr + 0x20); |
269 return ioread8(ioaddr + 0x20); |
267 } |
270 } |
268 |
271 |
270 * ccat_wait_status_cleared() - wait until CCAT status is cleared |
273 * ccat_wait_status_cleared() - wait until CCAT status is cleared |
271 * @ioaddr: address of the CCAT Update function in PCI config space |
274 * @ioaddr: address of the CCAT Update function in PCI config space |
272 * |
275 * |
273 * Blocks until bit 7 of the CCAT Update status is reset |
276 * Blocks until bit 7 of the CCAT Update status is reset |
274 */ |
277 */ |
275 |
|
276 static void ccat_wait_status_cleared(void __iomem * const ioaddr) |
278 static void ccat_wait_status_cleared(void __iomem * const ioaddr) |
277 { |
279 { |
278 uint8_t status; |
280 u8 status; |
|
281 |
279 do { |
282 do { |
280 status = ccat_get_status(ioaddr); |
283 status = ccat_get_status(ioaddr); |
281 } while (status & (1 << 7)); |
284 } while (status & (1 << 7)); |
282 } |
285 } |
283 |
286 |
294 * is very possible that the overall buffer ends with a lot of 0xff. |
297 * is very possible that the overall buffer ends with a lot of 0xff. |
295 * |
298 * |
296 * Return: the number of bytes copied |
299 * Return: the number of bytes copied |
297 */ |
300 */ |
298 static int ccat_read_flash_block(void __iomem * const ioaddr, |
301 static int ccat_read_flash_block(void __iomem * const ioaddr, |
299 const uint32_t addr, const uint16_t len, |
302 const u32 addr, const u16 len, |
300 char __user * const buf) |
303 char __user * const buf) |
301 { |
304 { |
302 uint16_t i; |
305 u16 i; |
303 const uint16_t clocks = 8 * len; |
306 const u16 clocks = 8 * len; |
|
307 |
304 ccat_update_cmd_addr(ioaddr, CCAT_READ_FLASH + clocks, addr); |
308 ccat_update_cmd_addr(ioaddr, CCAT_READ_FLASH + clocks, addr); |
305 for (i = 0; i < len; i++) { |
309 for (i = 0; i < len; i++) { |
306 put_user(ioread8(ioaddr + CCAT_DATA_IN_4 + 8 * i), buf + i); |
310 put_user(ioread8(ioaddr + CCAT_DATA_IN_4 + 8 * i), buf + i); |
307 } |
311 } |
308 return len; |
312 return len; |
319 * flash to the user space buffer. |
323 * flash to the user space buffer. |
320 * |
324 * |
321 * Return: the number of bytes copied |
325 * Return: the number of bytes copied |
322 */ |
326 */ |
323 static int ccat_read_flash(void __iomem * const ioaddr, char __user * buf, |
327 static int ccat_read_flash(void __iomem * const ioaddr, char __user * buf, |
324 uint32_t len, loff_t * off) |
328 u32 len, loff_t * off) |
325 { |
329 { |
326 const loff_t start = *off; |
330 const loff_t start = *off; |
|
331 |
327 while (len > CCAT_DATA_BLOCK_SIZE) { |
332 while (len > CCAT_DATA_BLOCK_SIZE) { |
328 *off += |
333 *off += |
329 ccat_read_flash_block(ioaddr, *off, CCAT_DATA_BLOCK_SIZE, |
334 ccat_read_flash_block(ioaddr, *off, CCAT_DATA_BLOCK_SIZE, |
330 buf); |
335 buf); |
331 buf += CCAT_DATA_BLOCK_SIZE; |
336 buf += CCAT_DATA_BLOCK_SIZE; |
345 * Copies one block of configuration data to the CCAT FPGA's flash |
350 * Copies one block of configuration data to the CCAT FPGA's flash |
346 * |
351 * |
347 * Return: the number of bytes copied |
352 * Return: the number of bytes copied |
348 */ |
353 */ |
349 static int ccat_write_flash_block(void __iomem * const ioaddr, |
354 static int ccat_write_flash_block(void __iomem * const ioaddr, |
350 const uint32_t addr, const uint16_t len, |
355 const u32 addr, const u16 len, |
351 const char *const buf) |
356 const char *const buf) |
352 { |
357 { |
353 const uint16_t clocks = 8 * len; |
358 const u16 clocks = 8 * len; |
354 uint16_t i; |
359 u16 i; |
|
360 |
355 ccat_update_cmd(ioaddr, CCAT_WRITE_ENABLE); |
361 ccat_update_cmd(ioaddr, CCAT_WRITE_ENABLE); |
356 for (i = 0; i < len; i++) { |
362 for (i = 0; i < len; i++) { |
357 iowrite8(buf[i], ioaddr + CCAT_DATA_OUT_4 + 8 * i); |
363 iowrite8(buf[i], ioaddr + CCAT_DATA_OUT_4 + 8 * i); |
358 } |
364 } |
359 ccat_update_cmd_addr(ioaddr, CCAT_WRITE_FLASH + clocks, addr); |
365 ccat_update_cmd_addr(ioaddr, CCAT_WRITE_FLASH + clocks, addr); |
366 * @update: a CCAT Update buffer containing the new FPGA configuration |
372 * @update: a CCAT Update buffer containing the new FPGA configuration |
367 */ |
373 */ |
368 static void ccat_write_flash(const struct update_buffer *const update) |
374 static void ccat_write_flash(const struct update_buffer *const update) |
369 { |
375 { |
370 const char *buf = update->data; |
376 const char *buf = update->data; |
371 uint32_t off = 0; |
377 u32 off = 0; |
372 size_t len = update->size; |
378 size_t len = update->size; |
|
379 |
373 while (len > CCAT_WRITE_BLOCK_SIZE) { |
380 while (len > CCAT_WRITE_BLOCK_SIZE) { |
374 ccat_write_flash_block(update->update->ioaddr, off, |
381 ccat_write_flash_block(update->update->ioaddr, off, |
375 (uint16_t) CCAT_WRITE_BLOCK_SIZE, buf); |
382 (u16) CCAT_WRITE_BLOCK_SIZE, buf); |
376 off += CCAT_WRITE_BLOCK_SIZE; |
383 off += CCAT_WRITE_BLOCK_SIZE; |
377 buf += CCAT_WRITE_BLOCK_SIZE; |
384 buf += CCAT_WRITE_BLOCK_SIZE; |
378 len -= CCAT_WRITE_BLOCK_SIZE; |
385 len -= CCAT_WRITE_BLOCK_SIZE; |
379 } |
386 } |
380 ccat_write_flash_block(update->update->ioaddr, off, (uint16_t) len, |
387 ccat_write_flash_block(update->update->ioaddr, off, (u16) len, buf); |
381 buf); |
|
382 } |
388 } |
383 |
389 |
384 /** |
390 /** |
385 * ccat_update_init() - Initialize the CCAT Update function |
391 * ccat_update_init() - Initialize the CCAT Update function |
386 */ |
392 */ |
387 struct ccat_update *ccat_update_init(const struct ccat_device *const ccatdev, |
393 struct ccat_update *ccat_update_init(const struct ccat_device *const ccatdev, |
388 void __iomem * const addr) |
394 void __iomem * const addr) |
389 { |
395 { |
390 struct ccat_update *const update = kzalloc(sizeof(*update), GFP_KERNEL); |
396 struct ccat_update *const update = kzalloc(sizeof(*update), GFP_KERNEL); |
|
397 |
391 if (!update) { |
398 if (!update) { |
392 return NULL; |
399 return NULL; |
393 } |
400 } |
394 kref_init(&update->refcount); |
401 kref_init(&update->refcount); |
395 update->ioaddr = ccatdev->bar[0].ioaddr + ioread32(addr + 0x8); |
402 update->ioaddr = ccatdev->bar[0].ioaddr + ioread32(addr + 0x8); |
441 */ |
448 */ |
442 static void ccat_update_destroy(struct kref *ref) |
449 static void ccat_update_destroy(struct kref *ref) |
443 { |
450 { |
444 struct ccat_update *update = |
451 struct ccat_update *update = |
445 container_of(ref, struct ccat_update, refcount); |
452 container_of(ref, struct ccat_update, refcount); |
|
453 |
446 cdev_del(&update->cdev); |
454 cdev_del(&update->cdev); |
447 device_destroy(update->class, update->dev); |
455 device_destroy(update->class, update->dev); |
448 class_destroy(update->class); |
456 class_destroy(update->class); |
449 unregister_chrdev_region(update->dev, 1); |
457 unregister_chrdev_region(update->dev, 1); |
450 kfree(update); |
458 kfree(update); |