4343#define DRIVER_NAME "axis_fifo"
4444
4545#define READ_BUF_SIZE 128U /* read buffer length in words */
46- #define WRITE_BUF_SIZE 128U /* write buffer length in words */
4746
4847#define AXIS_FIFO_DEBUG_REG_NAME_MAX_LEN 4
4948
@@ -231,6 +230,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
231230 }
232231
233232 bytes_available = ioread32 (fifo -> base_addr + XLLF_RLR_OFFSET );
233+ words_available = bytes_available / sizeof (u32 );
234234 if (!bytes_available ) {
235235 dev_err (fifo -> dt_device , "received a packet of length 0\n" );
236236 ret = - EIO ;
@@ -241,7 +241,7 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
241241 dev_err (fifo -> dt_device , "user read buffer too small (available bytes=%zu user buffer bytes=%zu)\n" ,
242242 bytes_available , len );
243243 ret = - EINVAL ;
244- goto end_unlock ;
244+ goto err_flush_rx ;
245245 }
246246
247247 if (bytes_available % sizeof (u32 )) {
@@ -250,11 +250,9 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
250250 */
251251 dev_err (fifo -> dt_device , "received a packet that isn't word-aligned\n" );
252252 ret = - EIO ;
253- goto end_unlock ;
253+ goto err_flush_rx ;
254254 }
255255
256- words_available = bytes_available / sizeof (u32 );
257-
258256 /* read data into an intermediate buffer, copying the contents
259257 * to userspace when the buffer is full
260258 */
@@ -266,18 +264,23 @@ static ssize_t axis_fifo_read(struct file *f, char __user *buf,
266264 tmp_buf [i ] = ioread32 (fifo -> base_addr +
267265 XLLF_RDFD_OFFSET );
268266 }
267+ words_available -= copy ;
269268
270269 if (copy_to_user (buf + copied * sizeof (u32 ), tmp_buf ,
271270 copy * sizeof (u32 ))) {
272271 ret = - EFAULT ;
273- goto end_unlock ;
272+ goto err_flush_rx ;
274273 }
275274
276275 copied += copy ;
277- words_available -= copy ;
278276 }
277+ mutex_unlock (& fifo -> read_lock );
278+
279+ return bytes_available ;
279280
280- ret = bytes_available ;
281+ err_flush_rx :
282+ while (words_available -- )
283+ ioread32 (fifo -> base_addr + XLLF_RDFD_OFFSET );
281284
282285end_unlock :
283286 mutex_unlock (& fifo -> read_lock );
@@ -305,11 +308,8 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
305308{
306309 struct axis_fifo * fifo = (struct axis_fifo * )f -> private_data ;
307310 unsigned int words_to_write ;
308- unsigned int copied ;
309- unsigned int copy ;
310- unsigned int i ;
311+ u32 * txbuf ;
311312 int ret ;
312- u32 tmp_buf [WRITE_BUF_SIZE ];
313313
314314 if (len % sizeof (u32 )) {
315315 dev_err (fifo -> dt_device ,
@@ -325,11 +325,17 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
325325 return - EINVAL ;
326326 }
327327
328- if (words_to_write > fifo -> tx_fifo_depth ) {
329- dev_err (fifo -> dt_device , "tried to write more words [%u] than slots in the fifo buffer [%u]\n" ,
330- words_to_write , fifo -> tx_fifo_depth );
328+ /*
329+ * In 'Store-and-Forward' mode, the maximum packet that can be
330+ * transmitted is limited by the size of the FIFO, which is
331+ * (C_TX_FIFO_DEPTH–4)*(data interface width/8) bytes.
332+ *
333+ * Do not attempt to send a packet larger than 'tx_fifo_depth - 4',
334+ * otherwise a 'Transmit Packet Overrun Error' interrupt will be
335+ * raised, which requires a reset of the TX circuit to recover.
336+ */
337+ if (words_to_write > (fifo -> tx_fifo_depth - 4 ))
331338 return - EINVAL ;
332- }
333339
334340 if (fifo -> write_flags & O_NONBLOCK ) {
335341 /*
@@ -368,32 +374,20 @@ static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
368374 }
369375 }
370376
371- /* write data from an intermediate buffer into the fifo IP, refilling
372- * the buffer with userspace data as needed
373- */
374- copied = 0 ;
375- while (words_to_write > 0 ) {
376- copy = min (words_to_write , WRITE_BUF_SIZE );
377-
378- if (copy_from_user (tmp_buf , buf + copied * sizeof (u32 ),
379- copy * sizeof (u32 ))) {
380- ret = - EFAULT ;
381- goto end_unlock ;
382- }
383-
384- for (i = 0 ; i < copy ; i ++ )
385- iowrite32 (tmp_buf [i ], fifo -> base_addr +
386- XLLF_TDFD_OFFSET );
387-
388- copied += copy ;
389- words_to_write -= copy ;
377+ txbuf = vmemdup_user (buf , len );
378+ if (IS_ERR (txbuf )) {
379+ ret = PTR_ERR (txbuf );
380+ goto end_unlock ;
390381 }
391382
392- ret = copied * sizeof (u32 );
383+ for (int i = 0 ; i < words_to_write ; ++ i )
384+ iowrite32 (txbuf [i ], fifo -> base_addr + XLLF_TDFD_OFFSET );
393385
394386 /* write packet size to fifo */
395- iowrite32 (ret , fifo -> base_addr + XLLF_TLR_OFFSET );
387+ iowrite32 (len , fifo -> base_addr + XLLF_TLR_OFFSET );
396388
389+ ret = len ;
390+ kvfree (txbuf );
397391end_unlock :
398392 mutex_unlock (& fifo -> write_lock );
399393
0 commit comments