This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/AM3359: am335x linux uart dma not working

Part Number: AM3359

Tool/software: Linux

Hi,

  I have a beagle boneblack devkit, which equipped with am3359. It running with uboot and kernel compiled from the newest sdk 'ti-processor-sdk-linux-am335x-evm-05.02.00.10'. So the kernel version number is '4.14.79'. 

  I connect UART4 of the devkit to my host PC (via USB2RS232 converter). By sending continuous bytes from PC to UART4 of devkit, I found that the RX DMA of uart4 does never work, that means every byte that it received is by polling(serial8250_rx_chars ) not dma.

The following are part of my dts configuration:

uart4_pins: pinmux_uart4_pins {
  pinctrl-single,pins = <
  0x70 (PIN_INPUT_PULLUP | MUX_MODE6) /* gpmc_wait0.uart4_rxd */
  0x74 (PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* gpmc_wpn.uart4_txd */
  >;
};

&uart4 {
  pinctrl-names = "default";
  pinctrl-0 = <&uart4_pins>;
  status = "okay";
};

uart4: serial@481a8000 {
  compatible = "ti,omap3-uart";
  ti,hwmods = "uart5";
  clock-frequency = <48000000>;
  reg = <0x481a8000 0x2000>;
  reg-shift = <2>;
  interrupts = <45>;
  status = "disabled";
  dmas = <&edma 34>, <&edma 35>;
  dma-names = "tx", "rx";
};

By searching the whole dts files(dts and dtsi), I confirmed the channel 34 and 35 are never refereneced by other functionalities.

I add some printk in 8250_omap.c, and have some discoveries:

Everytime when the rx char is comming, the following stacks are called sequentially:

   omap_8250_handle_rx_dma >>> handle_rx_dma >>> omap_8250_rx_dma_flush >>> serial8250_rx_chars >>> omap_8250_rx_dma

 It looks like, a dma slave is prepared and always waiting for the incoming bytes, but when the interrupt comes, the dma slave is flushed, none inserted into tty buffer when flush occors.

 Then, all chars left in FIFO are read out by 'serial8250_rx_chars'.

 Again, a new slave is prepared for the next dma, it still get flushed at the next interrupt, also none bytes are transferred by that dma.

Again and again, in the total test, none bytes from PC to devkit are transferred by DMA, they are all read out one by one in 'serial8250_rx_chars '.

The attached 'send.c' and 'recv.c' are my test program. The 'send.c' are running on PC (Ubuntu), while 'recv.c' are running on devkit(am335x).

Any help will be appreciated.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>

#include "list.h"

/* #define UUB_SIZE	0x8000 */
/* #define UUB_SIZE	0x400 */
/* #define UUB_COUNT	0x8000 */
/* #define UUB_COUNT	0x800 */

#define UUB_SIZE	512
#define UUB_COUNT	1024
#define BAUD B115200
#define UART "/dev/ttyS5"

static unsigned int m_def_baud = BAUD;
static char *m_def_uart = UART;

struct uart_user_buf_st {

	unsigned char buf[UUB_SIZE];
	unsigned int  len;
	struct list_head node;
};

static LIST_HEAD(uub_rcv);
static LIST_HEAD(uub_rec);

static pthread_mutex_t lock_rcv;
static pthread_mutex_t lock_rec;
static pthread_cond_t  cond_rcv=PTHREAD_COND_INITIALIZER;
static pthread_cond_t  cond_rec=PTHREAD_COND_INITIALIZER;

static pthread_t	pth_rcv;
static pthread_t	pth_rec;


#define ERR_RET(num)	do {			\
		err = num;			\
		goto error;			\
	} while(0)

static unsigned int rcvNum = 0;
static unsigned int recNum = 0;
static unsigned int recRunning = 1;

static int uart_init(void)
{
	int fd=-1, err=-1;
	struct termios ios;
	
	fd = open(m_def_uart, O_RDWR | O_NONBLOCK);
	if (fd < 0)
		return -1;

	if (tcgetattr(fd, &ios) < 0)
		ERR_RET(-1);

	cfsetispeed(&ios, m_def_baud);
	cfsetospeed(&ios, m_def_baud);

	ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
			 | INLCR | IGNCR | ICRNL | IXON);
	ios.c_oflag &= ~OPOST;
	ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
	ios.c_cflag &= ~(CSIZE | PARENB);
	ios.c_cflag |= CS8;

	if (tcsetattr(fd, TCSANOW, &ios) < 0)
		ERR_RET(-1);

	return fd;

  error:
	if (fd > 0)
		close(fd);
	return err;
}

static void uart_close(int fd)
{
	if (fd > 0)
		close(fd);
}

static int file_init(void)
{
	int	fd = -1;

	fd = open("/data/1.bin", O_CREAT | O_RDWR | O_TRUNC);
	if (fd < 0)
		return -1;
	return fd;
}

static void file_close(int fd)
{
	if (fd > 0)
		close(fd);
}

static int puub_free(struct list_head *lst_rcv, struct list_head *lst_rec);
static int puub_init(struct list_head *lst_rcv, struct list_head *lst_rec)
{

	int	i, err=-1;
	struct uart_user_buf_st  *puub;

	/* They should be empty before initialize */
	if (!list_empty(lst_rcv) || !list_empty(lst_rec))
		return -1;

	for (i = 0; i < UUB_COUNT; i++) {
		puub = calloc(1, sizeof(struct uart_user_buf_st));
		if (!puub) {
			fprintf(stderr, "Out of memory(-1)\n");
			ERR_RET(-1);
		}
		list_add_tail(&puub->node, lst_rcv);
	}

	return 0;

  error:
	puub_free(lst_rcv, lst_rec);
	return err;
}

static int puub_free(struct list_head *lst_rcv, struct list_head *lst_rec)
{
	struct uart_user_buf_st  *puub, *n;

	if (lst_rcv) {
		list_for_each_entry_safe(puub, n, lst_rcv, node)
			free(puub);
	}
		
	if (lst_rec) {
		list_for_each_entry_safe(puub, n, lst_rec, node)
			free(puub);
	}
	return 0;
}

static struct uart_user_buf_st *puub_pop_head(struct list_head *lst)
{
	struct uart_user_buf_st *puub;
	
	if (list_empty(lst))
		return NULL;

	/* remove head */
	puub = list_entry(lst->next, struct uart_user_buf_st, node);
	list_del(&puub->node);
	return puub;
}

static void puub_push_tail(struct list_head *lst, struct uart_user_buf_st *puub)
{
	/* add to tail */
	list_add_tail(&puub->node, lst);
}

static int read_assurance(int fd, unsigned char *buf, int size, int timeout, int *perr)
{
	fd_set		rfds, efds;
	struct timeval	to;

	int		ret, count;
	int err=0, actual_size=0;

	to.tv_sec = timeout;
	to.tv_usec = 0;

	while (size > 0) {

		FD_ZERO(&rfds);
		FD_ZERO(&efds);
		FD_SET(fd, &rfds);
		FD_SET(fd, &efds);

		ret = select(fd+1, &rfds, NULL, &efds, &to);
		if (ret > 0) {

			if (FD_ISSET(fd, &rfds)) {
				count = read(fd, buf+actual_size, size);
				if (count < 0) {
					fprintf(stderr, "UART Read return error\n");
					ERR_RET(-1);
				}
				actual_size += count;
				size -= count;

			} else if (FD_ISSET(fd, &efds)) {

				fprintf(stderr, "UART select indicate error\n");
				ERR_RET(-1);
			}
		} else if (ret == 0) {

			ERR_RET(0);

		} else {
			fprintf(stderr, "UART select return error\n");
			ERR_RET(-1);
		}
	}

  error:
	if (perr)
		*perr = err;
	return actual_size;
}

/* static int read_assurance_continuous(int fd, unsigned char *buf, int size, int timeout, int *perr) */
/* { */
/* 	int count; */
/* 	int err=0, actual_size=0; */

/* 	while (size > 0) { */

/* 		count = read(fd, buf+actual_size, size); */
/* 		if (count < 0) { */
/* 			fprintf(stderr, "UART Read return error\n"); */
/* 			ERR_RET(-1); */
/* 		} */
/* 		actual_size += count; */
/* 		size -= count; */
/* 	} */

/*   error: */
/* 	if (perr) */
/* 		*perr = err; */
/* 	return actual_size; */
/* } */

/* #define MAPSUPPORT */
#ifdef MAPSUPPORT
static unsigned char *mbase = NULL;

unsigned int serialin(unsigned char reg)
{
	unsigned int	val;
	val = *(volatile unsigned int *)((unsigned int)mbase + (reg<<2));
	return val;
}

static int read_from_map(int fd, unsigned char *buf, int size, int timeout, int *perr)
{
	int count;
	int err=0, actual_size=0;

	while (size > 0) {
		if (serialin(5) & 0x1) {
			*(buf+actual_size) = serialin(0);
			actual_size++;
			size--;
		}
	}
	return actual_size;
}
#endif
		
void *rcv_proc(void *arg)
{
	int	fd = *(int *)arg, ret;
	struct uart_user_buf_st *uub = NULL;
	int err;

#ifdef MAPSUPPORT


	do {

		int	mapfd = open("/dev/mem", O_RDWR | O_SYNC);
		if (mapfd == -1) {
			fprintf(stderr, "Open Map Error");
			pthread_exit(NULL);
		}
		
		mbase = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, mapfd, 0x481aa000);
		if (!mbase) {
			fprintf(stderr, "Map Error");
			close(mapfd);
			pthread_exit(NULL);
		}

		/* while (1) { */
		/* 	if (serialin(5) & 0x1) */
		/* 		fprintf(stderr, "read return %x\n", serialin(0)); */
		/* } */
			
	} while(0);
	
#endif
	
	while (1) {

		while (uub == NULL) {

			// 1. get buffer
			pthread_mutex_lock(&lock_rcv);
			if (list_empty(&uub_rcv))
				pthread_cond_wait(&cond_rcv, &lock_rcv);
			uub = puub_pop_head(&uub_rcv);
			pthread_mutex_unlock(&lock_rcv);
		}

		// 2. read data
		ret = read_assurance(fd, uub->buf, sizeof(uub->buf), 10, &err);
		/* ret = read_assurance_continuous(fd, uub->buf, sizeof(uub->buf), 10, &err); */
/* #ifdef MAPSUPPORT */
		/* ret = read_from_map(fd, uub->buf, sizeof(uub->buf), 10, &err); */
/* #endif */
		if (ret > 0) {

			if (ret != sizeof(uub->buf))
				fprintf(stderr, "unexpect bytes: %d\n", ret);

			uub->len = ret;
			rcvNum += ret;
			
			// 3. delivery it to rec thread
			pthread_mutex_lock(&lock_rec);
			puub_push_tail(&uub_rec, uub);
			pthread_cond_signal(&cond_rec);
			pthread_mutex_unlock(&lock_rec);
			uub = NULL;
		}
		
		if (ret == 0	 // timeout
		    || err != 0) // Error occured
			break;
	}

	recRunning = 0;
	pthread_cond_signal(&cond_rec);
	pthread_exit(NULL);
}

void *rec_proc(void *arg)
{
	/* int	fd = *(int *)arg; */
	int ret;
	struct uart_user_buf_st *uub = NULL;

	while (recRunning) {

		// 1. get buffer
		while (uub == NULL && recRunning) {

			pthread_mutex_lock(&lock_rec);
			if (list_empty(&uub_rec))
				pthread_cond_wait(&cond_rec, &lock_rec);
			uub = puub_pop_head(&uub_rec);
			pthread_mutex_unlock(&lock_rec);
		}

		if (!recRunning)
			break;
		
		// 2. write file
		/* ret = write(fd, uub->buf, uub->len); */
		/* if (ret < 0) */
		/* 	break; */
		ret = uub->len;
		
		recNum += ret;
		
		// 3. return buffer
		pthread_mutex_lock(&lock_rcv);
		puub_push_tail(&uub_rcv, uub);
		pthread_cond_signal(&cond_rcv);
		pthread_mutex_unlock(&lock_rcv);
		uub = NULL;
	}
	pthread_exit(NULL);
}

int main(int argc, char **argv)
{
	int uartfd=-1;
	int filefd=-1;
	int rpfd=-1;
	int err=0;


	/* rpfd = open("/dev/rp0", O_RDONLY); */
	/* if (rpfd < 0) */
	/* 	return -1; */
	
	if (argc > 1)
		m_def_uart = argv[1];
	
	if (argc > 2) {
		if (!strcmp(argv[2], "115200"))
			m_def_baud = B115200;
		else if (!strcmp(argv[2], "3686400"))
			m_def_baud = B75;
	}

	printf("Recv via '%s', baud '%d'...\n", m_def_uart, m_def_baud);
	
	uartfd = uart_init();
	if (uartfd < 0) {
		fprintf(stderr, "Initialize UART Error\n");
		/* close(rpfd); */
		return -1;
	}
	
	if (puub_init(&uub_rcv, &uub_rec) < 0) {
		ERR_RET(-1);
	}

	filefd = file_init();
	if (filefd < 0) {
		fprintf(stderr, "Initialize File Error\n");
		ERR_RET(-1);
	}

	
	pthread_mutex_init(&lock_rcv, NULL);
	pthread_mutex_init(&lock_rec, NULL);
	pthread_create(&pth_rcv, NULL, rcv_proc, (void *)&uartfd);
	/* pthread_create(&pth_rcv, NULL, rcv_proc, (void *)&rpfd); */
	pthread_create(&pth_rec, NULL, rec_proc, (void *)&filefd);

	/// ...

	pthread_join(pth_rcv, NULL);
	pthread_join(pth_rec, NULL);
	fprintf(stderr, "TOTAL: recvd %d, reced: %d\n", rcvNum, recNum);
	
  error:
	uart_close(rpfd);
	uart_close(uartfd);
	file_close(filefd);
	puub_free(&uub_rcv, &uub_rec);
	return err;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>

#define BUF_SIZE 400 
#define BUF_COUNT 4096
#define BAUD B115200
#define UART "/dev/ttyS5"

static unsigned int m_def_baud = BAUD;
static char *m_def_uart = UART;

#define ERR_RET(num)	do {			\
		err = num;			\
		goto error;			\
	} while(0)


static int	running = 1;

static int uart_init(void)
{
	int fd=-1, err=-1;
	struct termios ios;
	
	fd = open(m_def_uart, O_RDWR);
	if (fd < 0)
		return -1;

	if (tcgetattr(fd, &ios) < 0)
		ERR_RET(-1);


	ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
			 | INLCR | IGNCR | ICRNL | IXON);
	ios.c_oflag &= ~OPOST;
	ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
	ios.c_cflag &= ~(CSIZE | PARENB);
	ios.c_cflag |= CS8;

	cfsetispeed(&ios, m_def_baud);
	cfsetospeed(&ios, m_def_baud);

	if (tcsetattr(fd, TCSANOW, &ios) < 0)
		ERR_RET(-1);

	return fd;

  error:
	if (fd > 0)
		close(fd);
	return err;
}

static void uart_close(int fd)
{
	if (fd > 0)
		close(fd);
}

void sig_exit(int sig)
{
	running = 0;
}

int main(int argc, char **argv)
{
	unsigned char buf[BUF_SIZE];
	int uartfd=-1;
	int i, ret, total=0;

	time_t tb, te;
	unsigned int total_len = BUF_COUNT*BUF_SIZE;
	
	/* parse arguments */
	/* ./send uart_dev baud size_in_bytes*/
	if (argc > 1)
		m_def_uart = argv[1];
	
	if (argc > 2) {
		if (!strcmp(argv[2], "115200"))
			m_def_baud = B115200;
		else if (!strcmp(argv[2], "3686400"))
			m_def_baud = B75;
	}

	if (argc > 3) {
		total_len = atoi(argv[3]);
		if (total_len&(BUF_SIZE-1))
			total_len = (total_len&(~(BUF_SIZE-1))) + BUF_SIZE;
	}

	printf("Send via '%s', baud '%d', size: '%d(%xh)'...\n",	\
	       m_def_uart, m_def_baud, total_len, total_len);
	

	uartfd = uart_init();
	if (uartfd < 0) {
		fprintf(stderr, "Initialize UART Error\n");
		return -1;
	}

	for (i = 0; i < sizeof(buf); i++)
		buf[i] = i&0xff;

	tb = time(NULL);
	for (i = 0; i < total_len/BUF_SIZE; i++) {

		if (!running)
			break;
		
		ret = write(uartfd, buf, sizeof(buf));
		if (ret < 0) {
			fprintf(stderr, "Err >> Write error: %s\n", strerror(errno));
			break;
		} else {
			if (ret != sizeof(buf))
				fprintf(stderr, "Warn>> Writed %d bytes, it should be %u\n", ret, sizeof(buf));
			total += ret;
			/* fprintf(stderr, "Write>> %d\n", total); */
		}

		usleep(5000);
	}
	te = time(NULL);

	uart_close(uartfd);
	fprintf(stderr, "TOTAL Send %d(%xH) Bytes, %dKBps\n", total, total,	\
		(te-tb > 0) ? total/1024/(int)(te-tb) : 0);
	return 0;
}

Best Regards,

XJ

  • Hi,

    First of all, the Processor SDK Linux v5.1.0.11 introduced a driver bug which causes DMA failure when multiple UARTs are opened simultaneously, so the Processor SDK linux v5.2.0.10 is also affected by the bug.

    To check if the issue you faced is caused by this driver bug, can you please test with Processor SDK Linux v5.0.0.15 to see if the problem happens?
  • So, where to download the sdk 5.0.0.15? By the way,during the test, only the debug console(uart0) and uart4 are simultaneously in use, only uart4 is trying to use dma. I dont know if this is the bug case. Where to get the bug details?

  • Hi,

    Sorry, I was reading your message too fast and thought you were using 4 UART ports.
    No, your use case is not affected by the bug I mentioned. The console uart (uart0) doesn't use dma, so only uart4 is used in the test. The mentioned bug only affects if multiple uart ports use dma simultaneously.

    I will look into this test case, and get you back.
  • In a single word, on the uart receiving side(am335x linux uart driver), the dma callback __dma_rx_complete is never called. In every fifo interrupt handler, dma is flushed(no any bytes transferred), all bytes are transferred via the original func serial8250_rx_chars. The dma seems prepared but never work.
  • Hi,

    user4248043 said:
    uart4: serial@481a8000 {
    ...
      dmas = <&edma 34>, <&edma 35>;
      dma-names = "tx", "rx";
    };

    Are these dma channels added by you? I don't see them in the kernel source code in Processor SDK Linux v5.2.0.10.

  • I add them from the template of dts file of uboot. The kernel will parse the dts file and request the dma channels. How to confirm kernel will drive the designate dma channels?
  • Hi,

    Using channel 34 and 35 for UART3 is not correct. Please check TRM Table 11-23 for the EDMA events, 34 and 35 are not connected to UART3. You should refer to Table 11-24 and use EDMA Crossbar channel 7 and 8.

  • You are right. Uart4 dma events are fixed to 9&10 of Crossbar,I need to pick up two free dma channels and map them to the Crossbar event 9&10. This is to be done by correct dts setttings. I will post my verified dts settings and then close this issue. Thanks!
  • As my understanding, for table 11-23 "Direct Mapped event", dma channel is the event, no need to redirect or map (or mux). That's why in your sample dts files, channels 28&29 are assigned to uart1, and channels 30&31 are assigned to uart2. These assignment are fixed.

    ////////////////////////////////////////////
    uart1: serial@48022000 {
    compatible = "ti,am3352-uart", "ti,omap3-uart";
    ti,hwmods = "uart2";
    clock-frequency = <48000000>;
    reg = <0x48022000 0x2000>;
    interrupts = <73>;
    status = "disabled";
    dmas = <&edma 28 0>, <&edma 29 0>;
    dma-names = "tx", "rx";
    };

    uart2: serial@48024000 {
    compatible = "ti,am3352-uart", "ti,omap3-uart";
    ti,hwmods = "uart3";
    clock-frequency = <48000000>;
    reg = <0x48024000 0x2000>;
    interrupts = <74>;
    status = "disabled";
    dmas = <&edma 30 0>, <&edma 31 0>;
    dma-names = "tx", "rx";
    };
    ////////////////////////////////////////////

    For table 11-24 "Crossbar Mapped event", a new controller 'Crossbar' is integrated to extend more dma events for more peripherals.
    Uart4 has been maped to CrossBar with fixed event number 9&10, you should select two dma channels mapped for these two events.
    The below are part of my dts settings:

    ////////////////////////////////////////////
    /* This is the xbar controller */
    edma_xbar: dma-router@f90 {
    compatible = "ti,am335x-edma-crossbar";
    reg = <0xf90 0x40>;
    #dma-cells = <3>;
    dma-requests = <32>;
    dma-masters = <&edma>;
    };

    /* These are the uart4 settings */
    uart4: serial@481a8000 {
    compatible = "ti,am3352-uart", "ti,omap3-uart";
    ti,hwmods = "uart5";
    clock-frequency = <48000000>;
    reg = <0x481a8000 0x2000>;
    interrupts = <45>;
    status = "disabled";
    dmas = <&edma_xbar 34 0 9
    &edma_xbar 35 0 10>;
    dma-names = "tx", "rx";
    };
    ////////////////////////////////////////////

    The 'dmas' setting direct to 'edma_xbar' not 'edma', 34&35 are the dma channels (you can select other free channels), 9&10 are xbar events which are fixed accoring to table 11-24.

    More attention, how to identify dma is working or not.
    I enabled "DMA Engine debugging & DMA Engine verbose debugging" in kernel menuconfig.
    After the dma transferring complete, type instruction 'dmesg | grep dma' to check if there are something like this:

    ////////////////////////////////////////////
    [ 153.695592] edma 49000000.edma: vchan dc272908: txd db0ef240[1ade]: submitted
    [ 153.695610] edma 49000000.edma:
    [ 153.695619] edma 49000000.edma: first transfer starting on channel 38
    [ 153.695627] edma 49000000.edma: ER1 00000000
    [ 153.695635] edma 49000000.edma: EER1 00000040
    [ 153.695719] edma 49000000.edma: dma_irq_handler
    [ 153.695728] edma 49000000.edma: EER1 00000000
    [ 153.695736] edma 49000000.edma: txd db0ef240[1ade]: marked complete
    [ 153.695744] edma 49000000.edma: Transfer completed on channel 38
    ////////////////////////////////////////////

    I think this could be used to identify a successful dma transfer for channel 38 (with these key words: submit, irq_handler, complete).
    If you are trying uart with dma, found dmesg only contains 'submit' but 'complete', although you can still receive or transmit chars via the uart, you should be note that dma is not working, chars transmitted or received are handled with the original polling way.

    My verified case is with kernel 4.14.94, the newest kernel on github.
  • user4248043 said:
    I enabled "DMA Engine debugging & DMA Engine verbose debugging" in kernel menuconfig.

    This is not an optimal method to check dma, it enables a lot messages in the log. What I would do in a simple way is to add a debug message in kernel as the patch below.

    diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
    index 2bb0b092bff2..873121c728db 100644
    --- a/drivers/tty/serial/8250/8250_omap.c
    +++ b/drivers/tty/serial/8250/8250_omap.c
    @@ -794,6 +794,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
            if (count < dma->rx_size)
                    dmaengine_terminate_async(dma->rxchan);
     
    +       dev_info(p->port.dev, "dma rx %d bytes\n", count);
            ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
     
            p->port.icount.rx += ret
    

    then use a wire to look back UART4 RX and TX pins, run the following command on the serial console to transfer 50 bytes to UART4.

    root@am335x-evm:~# echo "12345678901234567890123456789012345678901234567890" > /dev/ttyS4

    then you should see the following kernel log showing dma receives 48 bytes.

    [  411.074237] omap8250 481a8000.serial: dma rx 48 bytes
    [  411.079405] omap8250 481a8000.serial: dma rx 0 bytes
    [  411.094727] omap8250 481a8000.serial: dma rx 0 bytes

    Please note that dma for UART only moves 48 bytes data at a time, any reminder of a transfer is not done by dma.

  • Yes, I tried to add printk in __dma_rx_do_complete, I got the same result you printed.
    During my throughput test, all printk and log will be disabled.

    The RX_TRIGGER is 48, can I change it to get a higher performance?
  • Hi,

    You could increase RX_TRIGGER to get less interrupts, but it doesn't ensure the performance will be higher. You would have to test it on your system.