linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* SCC UART hang
@ 2004-10-18  4:01 Jeff Angielski
  2004-10-18  9:30 ` Does kmalloc on MPC82xx work correctly with GFP_DMA? Conor McLoughlin
  0 siblings, 1 reply; 8+ messages in thread
From: Jeff Angielski @ 2004-10-18  4:01 UTC (permalink / raw)
  To: linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 798 bytes --]


I am seeing a problem on my EP8260 board whereby my SCC2 UART is
sometimes hanging under heavy load.  

I am using the latest DENX kernel.

My SCC2 UART is configured with no flow control.  I am trying to get it
to work with 115k and 230k baud rates.

When it hangs:  I no longer see any SCC UART interrupts, my test
application that is transmitting/receiving the data is idle, and
sometimes the application reports that it has received more data than
was actually transmitted...

I'll attach my little test program before anybody asks how I am doing
the testing.  It is pretty straightforward.  Most of the code is to help
collect the data and make the output user friendly.

Anybody run into anything similar or have any ideas on what may be
causing the problem?

Thanks,
Jeff Angielski






 

[-- Attachment #2: uarttest.c --]
[-- Type: text/x-c, Size: 6600 bytes --]

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <asm/types.h>
#include <sys/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> 
#include <linux/if_arcnet.h> 
#include <linux/version.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <signal.h>
#include <ctype.h>
#include <pthread.h>
#include <sys/time.h>
#include <stdlib.h>
#include <errno.h>

#ifdef _NOT_USED_
#endif

#define USE_HDLC_READ
#define USE_SCC_UART
#define USE_UART_READ

#define MAX_PKT_SIZE 		1500
#define DEFAULT_PKT_SIZE 	554
#define DEFAULT_ITERATIONS	1
#define DEFAULT_BAUD_RATE	B230400
#define DEFAULT_READ_TIMEOUT	3

static int uartfd;
static int uart_tx_bytes=0;
static int uart_rx_bytes=0;

static int iterations=DEFAULT_ITERATIONS;
static int pkt_size=DEFAULT_PKT_SIZE;
static int baud_rate=DEFAULT_BAUD_RATE;

static struct termios oldtty,newtty;
static pthread_t write_uart_thread_id;
static pthread_t read_uart_thread_id;

void hexdump(unsigned char *p, int count)
{
	int i, j;

	for(i = 0; i < count; i += 16) {
		printf("%04x : ", i);
		for (j = 0; j < 16 && i + j < count; j++)
			printf("%2.2x ", p[i + j]);
		for (; j < 16; j++) {
			printf("   ");
		}
		printf(": ");
		for (j = 0; j < 16 && i + j < count; j++) {
			char c = toascii(p[i + j]);
			printf("%c", isalnum(c) ? c : '.');
		}
		printf("\n");
	}
}

static char *get_bps(int baud)
{
	char *retval;
	switch(baud)
	{
		case B0:	retval = "0";		break;
		case B300:	retval = "300";		break;
		case B600:	retval = "600";		break;
		case B1200:	retval = "200";		break;
		case B2400:	retval = "2400";	break;
		case B4800:	retval = "4800";	break;
		case B9600:	retval = "9600";	break;
		case B19200:	retval = "19200";	break;
		case B38400:	retval = "38400";	break;
		case B57600:	retval = "57600";	break;
		case B115200:	retval = "15200";	break;
		case B230400:	retval = "230400";	break;
		default:	retval ="unknwon";	break;
				   
	}

	return retval;

}

static int get_baud(char *baud_rate_bps)
{
	int newbaud;
	int retval=-1;

	/* Check if 'baudr' is really a number */
	if ((newbaud = (atol(baud_rate_bps) / 100)) == 0 && 
			baud_rate_bps[0] != '0') {
		newbaud = -1;
	}

	switch(newbaud) {
		case 0:         retval = B0;       break;
		case 3:         retval = B300;     break;
		case 6:         retval = B600;     break;
		case 12:        retval = B1200;    break;
		case 24:        retval = B2400;    break;
		case 48:        retval = B4800;    break;
		case 96:        retval = B9600;    break;
		case 192:       retval = B19200;   break;
		case 384:       retval = B38400;   break;
		case 576:       retval = B57600;   break;
		case 1152:      retval = B115200;  break;
		case 2304:      retval = B230400;  break;
	}

	return retval;
}



ssize_t writen(int fd, const void *vptr, size_t n)
{
	size_t nleft;
	ssize_t nwritten;
	const char *ptr;

	ptr=vptr;
	nleft=n;
	while(nleft>0) {
		if( (nwritten=write(fd, ptr, nleft)) <=0 ) {
			if( errno==EINTR )
				nwritten=0;
			else
				return -1;
		}

		nleft-=nwritten;
		ptr+=nwritten;
	}

	return n;
}

void *write_uart_thread(void *arg)
{
	unsigned char buf[MAX_PKT_SIZE];
	int i;
	int n;
	time_t start,finish;
	double elapsed;

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

	time(&start);
	i=0;
	while(1)
	{
		n = writen(uartfd, buf, pkt_size);
		if (n < 0) {
			perror("write():");
		} else if(n == 0) {
			continue;
		} else {
			uart_tx_bytes+=n;
			if(++i>=iterations)
				break;
		}
	}
	time(&finish);

	elapsed=difftime(finish,start);
	if(elapsed>0) {
		printf("%.1fsec at %.1fbps\n", 
			elapsed, (iterations*pkt_size*8)/elapsed);
	} else {
		printf("%fsec\n", elapsed);
	}

	pthread_exit(NULL);

}

void *read_uart_thread(void *arg)
{
	unsigned char buf[MAX_PKT_SIZE];
	int n;
	fd_set rfds;
	struct timeval tv;

	while(1)
	{
		FD_ZERO(&rfds);
		FD_SET(uartfd, &rfds);

		tv.tv_sec=DEFAULT_READ_TIMEOUT;
		tv.tv_usec=0;

		n=select(uartfd+1,&rfds,NULL,NULL,&tv);
		if(n>0) {
			if(FD_ISSET(uartfd,&rfds)) {
				n = read(uartfd, buf, pkt_size);
				if(n>0) {
					/* hexdump(buf,n); */
					uart_rx_bytes+=n;
				}
			}
		} else if (n==0) {
			break;
		} else {
			if(errno!=EINTR) {
				printf("%s: select() error\n", __FUNCTION__);
			}
		}
	}		

	pthread_exit(NULL);
}

void display_settings(void)
{
	printf("Settings: %d x %dbytes (%dbytes) @ %sbps\n",
		iterations, pkt_size, (iterations*pkt_size),
		get_bps(baud_rate));
}


void termination_handler(int sig)
{
	printf("uart: tx=%d rx=%d : %s\n", 
		uart_tx_bytes, uart_rx_bytes,
		(uart_tx_bytes==uart_rx_bytes) ? "PASSED" : "FAILED");

	pthread_kill(write_uart_thread_id,SIGTERM);
	pthread_kill(read_uart_thread_id,SIGTERM);

	exit(0);
}

int main(int argc, char **argv)
{
	int c;
	int newbaud;


	while(1) 
	{
		c=getopt(argc,argv,"n:s:b:");
		switch(c) {
		case 'n':
			iterations=atoi(optarg);
			break;
		case 's':
			pkt_size=atoi(optarg);
			if(pkt_size>MAX_PKT_SIZE)
				pkt_size=MAX_PKT_SIZE;
			break;
		case 'b':
			newbaud=get_baud(optarg);
			if(newbaud!=-1) 
				baud_rate=newbaud;
			break;
		case -1:
			break;
		default:
			printf("usage: uarttest [-n <n>] [-s <size>] [-b <baud>]\n");
			exit(1);
		}
		
		if(c==-1)
			break;
	}

	/* register the signal handler */
	if(signal(SIGINT,termination_handler)==SIG_IGN)
		signal(SIGINT,SIG_IGN);

	display_settings();

	/* open the serial port */
	if( (uartfd=open("/dev/tts/2", O_RDWR | O_NOCTTY )) < 0 ) {
		perror("open(): serial port\n");
		exit(1);
	}

	/* save old settings */
	tcgetattr(uartfd, &oldtty);

	/* configure for raw mode */
	bzero(&newtty,sizeof(newtty));
	newtty.c_cflag = CLOCAL | CREAD | CS8;
	newtty.c_iflag = IGNPAR;
	newtty.c_oflag = 0;
	newtty.c_lflag = 0;

	/* optimize for our interface(?) */
	newtty.c_cc[VTIME] = 0;
	newtty.c_cc[VMIN] = 1; 

	cfsetospeed(&newtty, (speed_t)baud_rate);
	cfsetispeed(&newtty, (speed_t)baud_rate);

	tcflush(uartfd, TCIOFLUSH);

	tcsetattr(uartfd, TCSANOW, &newtty);

	if( pthread_create(&read_uart_thread_id, NULL, 
			    read_uart_thread, (void *)0 )!=0 ) {
		printf("Could not create thread\n");
		exit(1);
	}

	if( pthread_create(&write_uart_thread_id, NULL, 
			    write_uart_thread, (void *)0 )!=0 ) {
		printf("Could not create thread\n");
		exit(1);
	}

	pthread_join(read_uart_thread_id,NULL);
	pthread_join(write_uart_thread_id,NULL);

	tcsetattr(uartfd, TCSANOW, &oldtty);
	printf("uart: tx=%d rx=%d : %s\n", 
		uart_tx_bytes, uart_rx_bytes,
		(uart_tx_bytes==uart_rx_bytes) ? "PASSED" : "FAILED");
	exit(0);
}

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Does kmalloc on MPC82xx work correctly with GFP_DMA?
  2004-10-18  4:01 SCC UART hang Jeff Angielski
@ 2004-10-18  9:30 ` Conor McLoughlin
  2004-10-18 15:31   ` Dan Malek
  2004-10-19 14:27   ` Matt Porter
  0 siblings, 2 replies; 8+ messages in thread
From: Conor McLoughlin @ 2004-10-18  9:30 UTC (permalink / raw)
  To: linuxppc-embedded

I have been looking at the ethernet device driver (fcc_enet) for the
mpc82xx platform. This allocates buffer descriptors using kmalloc with
the GFP_DMA flag. As far as I can see on my platform, this allocates
from the regular kernel memory (0xCxxxxxxx). As the attributes of this
block of memory are controlled by the block address translation
registers, this cannot be DMA safe, can it?
Is there something I am missing here?

I am using the linuxppc-2.5 tree.

Conor

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Does kmalloc on MPC82xx work correctly with GFP_DMA?
  2004-10-18  9:30 ` Does kmalloc on MPC82xx work correctly with GFP_DMA? Conor McLoughlin
@ 2004-10-18 15:31   ` Dan Malek
  2004-10-19  8:36     ` Conor McLoughlin
  2004-10-19 14:31     ` Matt Porter
  2004-10-19 14:27   ` Matt Porter
  1 sibling, 2 replies; 8+ messages in thread
From: Dan Malek @ 2004-10-18 15:31 UTC (permalink / raw)
  To: Conor McLoughlin; +Cc: linuxppc-embedded


On Oct 18, 2004, at 5:30 AM, Conor McLoughlin wrote:

> I have been looking at the ethernet device driver (fcc_enet) for the
> mpc82xx platform. This allocates buffer descriptors using kmalloc with
> the GFP_DMA flag.

Yes.

>  As far as I can see on my platform, this allocates
> from the regular kernel memory (0xCxxxxxxx). As the attributes of this
> block of memory are controlled by the block address translation
> registers,

No, the kmalloc() space is not covered by BATs (but, that isn't
relevant for this discussion).

>  this cannot be DMA safe, can it?

Yes, it is DMA safe.  That's why this driver works :-)

	-- Dan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Does kmalloc on MPC82xx work correctly with GFP_DMA?
  2004-10-18 15:31   ` Dan Malek
@ 2004-10-19  8:36     ` Conor McLoughlin
  2004-10-19 14:15       ` Dan Malek
  2004-10-19 14:31     ` Matt Porter
  1 sibling, 1 reply; 8+ messages in thread
From: Conor McLoughlin @ 2004-10-19  8:36 UTC (permalink / raw)
  To: linuxppc-embedded

Thanks for your response Dan, but there is still something that I
am not seeing correctly here.

> No, the kmalloc() space is not covered by BATs (but, that isn't
> relevant for this discussion).

On my board, I can use  my BDI2000 to look at the BAT registers.
DBAT2U is 0xC00003FE and DBAT0L is 0x00000002.

To me this looks like all of my SDRAM starting at effective address
0xC0000000 is handled by DBAT2 with cache enabled.
If I look at where it is allocating the memory with kmalloc, it is
in this area. I do get a different area of memory assigned depending
on whether or not I use GPF_DMA, but it is still in this effective area
covered by DBAT2.  What am I missing here?

 > Yes, it is DMA safe.  That's why this driver works :-)

Just because it works doesn't mean that there might not be a bug
lurking there.
I agree that it is unlikely, but I don't understand how an area of
memory at effective address 0xCxxxxxxx is not covered by the BATs.

--Conor

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Does kmalloc on MPC82xx work correctly with GFP_DMA?
  2004-10-19  8:36     ` Conor McLoughlin
@ 2004-10-19 14:15       ` Dan Malek
  2004-10-19 15:26         ` Conor McLoughlin
  0 siblings, 1 reply; 8+ messages in thread
From: Dan Malek @ 2004-10-19 14:15 UTC (permalink / raw)
  To: Conor McLoughlin; +Cc: linuxppc-embedded


On Oct 19, 2004, at 4:36 AM, Conor McLoughlin wrote:

> If I look at where it is allocating the memory with kmalloc, it is
> in this area.

Oooops, sorry you are correct, I had vmalloc() on the brain
due to some debugging I was doing.

> Just because it works doesn't mean that there might not be a bug
> lurking there.

It works because the 82xx is cache coherent.  The MMU mapping
is irrelevant.  There is no bug here.  Just because people don't
understand how something works doesn't mean there is a bug
present.  On processors like the 8xx or 4xx that are not cache
coherent, this would be a bug unless cache management functions
are also called and the buffers are properly aligned to cache
boundaries.

Thanks.

	-- Dan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Does kmalloc on MPC82xx work correctly with GFP_DMA?
  2004-10-18  9:30 ` Does kmalloc on MPC82xx work correctly with GFP_DMA? Conor McLoughlin
  2004-10-18 15:31   ` Dan Malek
@ 2004-10-19 14:27   ` Matt Porter
  1 sibling, 0 replies; 8+ messages in thread
From: Matt Porter @ 2004-10-19 14:27 UTC (permalink / raw)
  To: Conor McLoughlin; +Cc: linuxppc-embedded

On Mon, Oct 18, 2004 at 10:30:15AM +0100, Conor McLoughlin wrote:
> I have been looking at the ethernet device driver (fcc_enet) for the
> mpc82xx platform. This allocates buffer descriptors using kmalloc with
> the GFP_DMA flag. As far as I can see on my platform, this allocates

GFP_DMA has no meaning on PPC. All memory is DMAable.  GFP_DMA is for
PeeCees with a limited ISA DMA space.  Drivers should be using GFP_KERNEL
so they don't confuse people.

> from the regular kernel memory (0xCxxxxxxx). As the attributes of this
> block of memory are controlled by the block address translation
> registers, this cannot be DMA safe, can it?

Sure it can. It works with hardware snooping.

> Is there something I am missing here?

Yes, it's a 603e core and hardware snooping support manages cache
coherency between system memory and devices.

-Matt

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Does kmalloc on MPC82xx work correctly with GFP_DMA?
  2004-10-18 15:31   ` Dan Malek
  2004-10-19  8:36     ` Conor McLoughlin
@ 2004-10-19 14:31     ` Matt Porter
  1 sibling, 0 replies; 8+ messages in thread
From: Matt Porter @ 2004-10-19 14:31 UTC (permalink / raw)
  To: Dan Malek; +Cc: linuxppc-embedded

On Mon, Oct 18, 2004 at 11:31:12AM -0400, Dan Malek wrote:
> No, the kmalloc() space is not covered by BATs (but, that isn't
> relevant for this discussion).

Dan, I think you forgot that green book PPCs get kernel lowmem
("kmalloc() space") covered by BATs if possible...unless you
pass in "nobats".

-Matt

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Does kmalloc on MPC82xx work correctly with GFP_DMA?
  2004-10-19 14:15       ` Dan Malek
@ 2004-10-19 15:26         ` Conor McLoughlin
  0 siblings, 0 replies; 8+ messages in thread
From: Conor McLoughlin @ 2004-10-19 15:26 UTC (permalink / raw)
  To: linuxppc-embedded

Thanks to everyone who replied. I appreciate your time to help
educate me.

> It works because the 82xx is cache coherent.  The MMU mapping
> is irrelevant.  
That is the missing piece of the puzzle. I had worked with the 860
before and this was an issue. It hadn't occurred to me that the 82xx
was different.

> There is no bug here.  Just because people don't
> understand how something works doesn't mean there is a bug
> present.  
The reason I asked the question in the first place was because I didn't
understand how it could work.  I now understand it and can rest easier.

Thanks,
Conor

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2004-10-19 15:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-10-18  4:01 SCC UART hang Jeff Angielski
2004-10-18  9:30 ` Does kmalloc on MPC82xx work correctly with GFP_DMA? Conor McLoughlin
2004-10-18 15:31   ` Dan Malek
2004-10-19  8:36     ` Conor McLoughlin
2004-10-19 14:15       ` Dan Malek
2004-10-19 15:26         ` Conor McLoughlin
2004-10-19 14:31     ` Matt Porter
2004-10-19 14:27   ` Matt Porter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).