Linux MIPS Architecture development
 help / color / mirror / Atom feed
* [RFC PATCH] Alchemy: Au1210/Au1250 CPU support
From: Manuel Lauss @ 2007-12-06  8:07 UTC (permalink / raw)
  To: linux-mips

This patch adds IDs fornew Au1200 variants: Au1210 and Au1250.
They are essentially identical to the Au1200 except for the Au1210
which has a different SoC-ID in the PRId register [bits 31:24].
The Au1250 is a "Au1200 V0.2".

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>

--- linux-2.6.24-rc4/include/asm-mips/cpu.h	2007-12-04 08:33:33.143002000 +0100
+++ linux-2.6.24-rc4-work/include/asm-mips/cpu.h	2007-12-06 16:28:48.000000000 +0100
@@ -195,8 +195,8 @@ enum cpu_type_enum {
 	 * MIPS32 class processors
 	 */
 	CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_74K, CPU_AU1000,
-	CPU_AU1100, CPU_AU1200, CPU_AU1500, CPU_AU1550, CPU_PR4450,
-	CPU_BCM3302, CPU_BCM4710,
+	CPU_AU1100, CPU_AU1200, CPU_AU1210, CPU_AU1250, CPU_AU1500, CPU_AU1550,
+	CPU_PR4450, CPU_BCM3302, CPU_BCM4710,
 
 	/*
 	 * MIPS64 class processors
--- linux-2.6.24-rc4/arch/mips/kernel/cpu-probe.c	2007-12-04 08:33:00.793002000 +0100
+++ linux-2.6.24-rc4-work/arch/mips/kernel/cpu-probe.c	2007-12-06 16:27:06.000000000 +0100
@@ -188,6 +188,8 @@ static inline void check_wait(void)
 	case CPU_AU1500:
 	case CPU_AU1550:
 	case CPU_AU1200:
+	case CPU_AU1210:
+	case CPU_AU1250:
 		if (allow_au1k_wait)
 			cpu_wait = au1k_wait;
 		break;
@@ -733,6 +735,11 @@ static inline void cpu_probe_alchemy(str
 			break;
 		case 4:
 			c->cputype = CPU_AU1200;
+			if (2 == (c->processor_id & 0xff))
+				c->cputype = CPU_AU1250;
+			break;
+		case 5:
+			c->cputype = CPU_AU1210;
 			break;
 		default:
 			panic("Unknown Au Core!");
@@ -858,6 +865,8 @@ static __init const char *cpu_to_name(st
 	case CPU_AU1100:	name = "Au1100"; break;
 	case CPU_AU1550:	name = "Au1550"; break;
 	case CPU_AU1200:	name = "Au1200"; break;
+	case CPU_AU1210:	name = "Au1210"; break;
+	case CPU_AU1250:	name = "Au1250"; break;
 	case CPU_4KEC:		name = "MIPS 4KEc"; break;
 	case CPU_4KSC:		name = "MIPS 4KSc"; break;
 	case CPU_VR41XX:	name = "NEC Vr41xx"; break;
--- linux-2.6.24-rc4/arch/mips/mm/c-r4k.c	2007-12-04 08:33:00.963002000 +0100
+++ linux-2.6.24-rc4-work/arch/mips/mm/c-r4k.c	2007-12-06 16:44:07.000000000 +0100
@@ -989,6 +989,8 @@ static void __init probe_pcache(void)
 	case CPU_AU1100:
 	case CPU_AU1550:
 	case CPU_AU1200:
+	case CPU_AU1210:
+	case CPU_AU1250:
 		c->icache.flags |= MIPS_CACHE_IC_F_DC;
 		break;
 	}
--- linux-2.6.24-rc4/arch/mips/mm/tlbex.c	2007-12-04 08:33:00.983002000 +0100
+++ linux-2.6.24-rc4-work/arch/mips/mm/tlbex.c	2007-12-06 16:44:30.000000000 +0100
@@ -894,6 +894,8 @@ static __init void build_tlb_write_entry
 	case CPU_AU1500:
 	case CPU_AU1550:
 	case CPU_AU1200:
+	case CPU_AU1210:
+	case CPU_AU1250:
 	case CPU_PR4450:
 		i_nop(p);
 		tlbw(p);

^ permalink raw reply

* [PATCH] Alchemy: Fix Au1x SD controller IRQ
From: Manuel Lauss @ 2007-12-06  7:11 UTC (permalink / raw)
  To: linux-mips

With the introduction of MIPS_CPU_IRQ_BASE, the hardcoded IRQ number
of the au1100/au1200 SD controller(s) is no longer valid.

Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>

--- linux-2.6.24-rc4/include/asm-mips/mach-au1x00/au1100_mmc.h	2007-12-04 08:31:24.613002000 +0100
+++ linux-2.6.24-rc4-work/include/asm-mips/mach-au1x00/au1100_mmc.h	2007-12-06 15:33:35.000000000 +0100
@@ -41,8 +41,11 @@
 
 #define NUM_AU1100_MMC_CONTROLLERS	2
 
-
-#define AU1100_SD_IRQ	2
+#if defined(CONFIG_SOC_AU1100)
+#define AU1100_SD_IRQ	AU1100_SD_INT
+#elif defined(CONFIG_SOC_AU1200)
+#define AU1100_SD_IRQ	AU1200_SD_INT
+#endif
 
 
 #define SD0_BASE	0xB0600000

^ permalink raw reply

* Re: [UPDATED PATCH] IP28 support
From: David Daney @ 2007-12-05 20:37 UTC (permalink / raw)
  To: peter fuerst; +Cc: Thomas Bogendoerfer, Kumba, Ralf Baechle, linux-mips
In-Reply-To: <Pine.LNX.4.21.0712051841520.1354@Opal.Peter>

peter fuerst wrote:
> 
> On Wed, 5 Dec 2007, Thomas Bogendoerfer wrote:
> 
>> Date: Wed, 5 Dec 2007 10:39:38 +0100
>> From: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
>> To: Kumba <kumba@gentoo.org>
>> Cc: Ralf Baechle <ralf@linux-mips.org>, linux-mips@linux-mips.org
>> Subject: Re: [UPDATED PATCH] IP28 support
>>
>> On Wed, Dec 05, 2007 at 01:16:13AM -0500, Kumba wrote:
>>> I've been out of it lately -- did the gcc side of things ever make it in,
>>> or do we need to go push on that some more?
>> We need push on that. ...
> 
> There was no answer to .../2006-05/msg01446.html. Perhaps i should just
> put together an updated patch,

That would be helpful.  It would have to be against GCC's svn trunk. 
Currently 4.3 is in regression fix only mode.  The earliest the patch 
could appear in an official GCC release would probably be version 4.4


> that incorporates the changes proposed in
> msg01446.html, and submit it (with the longer "Cc:" line and a hint to
> the increasing demand for it ;-) to revive at least the discussion at
> gcc-patches.

Just sent it to gcc-patches@   I think it will be noticed.


> What could be changed beyond the proposed changes without either omitting
> necessary cache-barriers or crippling the R10k, i can't see yet.
> 
>> We need push on that. Looking at
>>
>> http://gcc.gnu.org/ml/gcc-patches/2006-04/msg00291.html
>>
>> there seems to be a missing understanding, why the cache
>> barriers are needed. I guess the patch could be improved
>> by pointing directly to the errata section of the R10k
>> user manual. Or even better copy the text out of the user
>> manual. That should make clear why this patch is needed.
> 
> Better copy, i guess. (Assuming copying whole paragraphs is still proper
> citation ;-) Along with the initial patch (.../2006-03.msg00090.html) as
> well as in the last letter so far (.../2006-05/msg01446.html) i pointed
> to the corresponding chapter in the R10k User's Manual and to the entry
> in the NetBSD eMail archive. In the last letter i tried to augment these
> by a summarizing explanation, but it seems i'm not very good at that...
> 
>> Peter did you do the copyright assigment ? That's probably
>> the second part, which needs to be done.
> 
> Yes, the assignment process became complete on May 22 2006
> (though apparently i missed to notify Richard Sandiford about it)
> 

Good.  Richard is generally quite responsive to patches.  Perhaps CC him 
on your patch.

David Daney

^ permalink raw reply

* Re: [UPDATED PATCH] IP28 support
From: peter fuerst @ 2007-12-05 19:49 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: Kumba, Ralf Baechle, linux-mips
In-Reply-To: <20071205093938.GA6848@alpha.franken.de>



On Wed, 5 Dec 2007, Thomas Bogendoerfer wrote:

> Date: Wed, 5 Dec 2007 10:39:38 +0100
> From: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> To: Kumba <kumba@gentoo.org>
> Cc: Ralf Baechle <ralf@linux-mips.org>, linux-mips@linux-mips.org
> Subject: Re: [UPDATED PATCH] IP28 support
>
> On Wed, Dec 05, 2007 at 01:16:13AM -0500, Kumba wrote:
> > I've been out of it lately -- did the gcc side of things ever make it in,
> > or do we need to go push on that some more?
>
> We need push on that. ...

There was no answer to .../2006-05/msg01446.html. Perhaps i should just
put together an updated patch, that incorporates the changes proposed in
msg01446.html, and submit it (with the longer "Cc:" line and a hint to
the increasing demand for it ;-) to revive at least the discussion at
gcc-patches.
What could be changed beyond the proposed changes without either omitting
necessary cache-barriers or crippling the R10k, i can't see yet.

> We need push on that. Looking at
>
> http://gcc.gnu.org/ml/gcc-patches/2006-04/msg00291.html
>
> there seems to be a missing understanding, why the cache
> barriers are needed. I guess the patch could be improved
> by pointing directly to the errata section of the R10k
> user manual. Or even better copy the text out of the user
> manual. That should make clear why this patch is needed.

Better copy, i guess. (Assuming copying whole paragraphs is still proper
citation ;-) Along with the initial patch (.../2006-03.msg00090.html) as
well as in the last letter so far (.../2006-05/msg01446.html) i pointed
to the corresponding chapter in the R10k User's Manual and to the entry
in the NetBSD eMail archive. In the last letter i tried to augment these
by a summarizing explanation, but it seems i'm not very good at that...

>
> Peter did you do the copyright assigment ? That's probably
> the second part, which needs to be done.

Yes, the assignment process became complete on May 22 2006
(though apparently i missed to notify Richard Sandiford about it)

>
> Thomas.
>
> --
> Crap can work. Given enough thrust pigs will fly, but it's not necessary a
> good idea.                                                [ RFC1925, 2.3 ]
>
>
>

kind regards

peter

^ permalink raw reply

* Re: [PATCH 0/2] Alchemy: fix interrupt routing
From: Sergei Shtylyov @ 2007-12-05 19:22 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Manuel Lauss, linux-mips
In-Reply-To: <20071205191208.GA12547@linux-mips.org>

Ralf Baechle wrote:

>>   It works:

>>41 total events, 5.109 events/sec

> That's the expected behaviour, good.

> One of the remaining problems on some platforms with tickless kernels is
> that not all clocksource / clockevent driver combinations are playing
> nicely with each other.  You can switch the clocksource driver manually
> at runtime.  First let's see what clocksource we have:
> 
>   # cd /sys/devices/system/clocksource/clocksource0/
>   # cat available_clocksource 
>   MIPS pit jiffies 

    I only have MIPS and jiffies of course. :-)

>   # cat current_clocksource 
>   MIPS 

> MIPS is the CP0 count register.  pit is the i8259 and jiffies simply counts
> interrupts like in the old days so has problems with lost timer interrupts
> and generally not such a great idea for tickless.  You should be able to
> switch between all these drivers by something like:

>   # echo jiffies > current_clocksource
>   Time: jiffies clocksource has been installed.
>   #

> Try switching between all the available clocksources a few times to see if
> that's working right also.

    It died after I selected jiffies.

>    Ralf

WBR, Sergei

^ permalink raw reply

* Re: [PATCH 0/2] Alchemy: fix interrupt routing
From: Ralf Baechle @ 2007-12-05 19:12 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: Manuel Lauss, linux-mips
In-Reply-To: <4756F494.8090207@ru.mvista.com>

On Wed, Dec 05, 2007 at 09:57:24PM +0300, Sergei Shtylyov wrote:

>    It works:

> 41 total events, 5.109 events/sec

That's the expected behaviour, good.

One of the remaining problems on some platforms with tickless kernels is
that not all clocksource / clockevent driver combinations are playing
nicely with each other.  You can switch the clocksource driver manually
at runtime.  First let's see what clocksource we have:

  # cd /sys/devices/system/clocksource/clocksource0/
  # cat available_clocksource 
  MIPS pit jiffies 
  # cat current_clocksource 
  MIPS 

MIPS is the CP0 count register.  pit is the i8259 and jiffies simply counts
interrupts like in the old days so has problems with lost timer interrupts
and generally not such a great idea for tickless.  You should be able to
switch between all these drivers by something like:

  # echo jiffies > current_clocksource
  Time: jiffies clocksource has been installed.
  #

Try switching between all the available clocksources a few times to see if
that's working right also.

   Ralf

^ permalink raw reply

* Re: [PATCH 0/2] Alchemy: fix interrupt routing
From: Sergei Shtylyov @ 2007-12-05 18:57 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Manuel Lauss, linux-mips
In-Reply-To: <20071205182353.GC10697@linux-mips.org>

Ralf Baechle wrote:

>>Thanks a billion!
>>Finally I can boot linux-2.6.24-rc on my Au1200 again!

> And with a bit of luck Alchemy will now support tickless, too.

    It works:

Timer Stats Version: v0.2
Sample period: 8.024 s
     8,     1 swapper          __netdev_watchdog_up (dev_watchdog)
     8,     1 swapper          phy_connect (phy_timer)
     8,     1 swapper          phy_connect (phy_timer)
     7,     0 swapper          receive_chars (delayed_work_timer_fn)
     1,     1 swapper          cache_register (delayed_work_timer_fn)
     1,     1 swapper          neigh_table_init_no_netlink (neigh_periodic_timer)
     4,     1 swapper          queue_delayed_work_on (delayed_work_timer_fn)
     2,   866 mvltd            schedule_timeout (process_timeout)
     1,     0 swapper          page_writeback_init (wb_timer_fn)
     1,     1 init             schedule_timeout (process_timeout)
41 total events, 5.109 events/sec

>   Ralf

WBR, Sergei

^ permalink raw reply

* Re: [PATCH 0/2] Alchemy: fix interrupt routing
From: Sergei Shtylyov @ 2007-12-05 18:29 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Manuel Lauss, linux-mips
In-Reply-To: <20071205182353.GC10697@linux-mips.org>

Ralf Baechle wrote:

>>Thanks a billion!
>>Finally I can boot linux-2.6.24-rc on my Au1200 again!

> And with a bit of luck Alchemy will now support tickless, too.

    Sigh. If only it had working PCI... :-(

>   Ralf

WBR, Sergei

^ permalink raw reply

* Re: [PATCH 0/2] Alchemy: fix interrupt routing
From: Ralf Baechle @ 2007-12-05 18:23 UTC (permalink / raw)
  To: Manuel Lauss; +Cc: Sergei Shtylyov, linux-mips
In-Reply-To: <4756D42E.9040609@fh-hagenberg.at>

On Wed, Dec 05, 2007 at 05:39:10PM +0100, Manuel Lauss wrote:

> Thanks a billion!
> Finally I can boot linux-2.6.24-rc on my Au1200 again!

And with a bit of luck Alchemy will now support tickless, too.

  Ralf

^ permalink raw reply

* Re: [PATCH 2/2] Alchemy: fix IRQ bases
From: Ralf Baechle @ 2007-12-05 18:21 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: linux-mips
In-Reply-To: <200712051908.26703.sshtylyov@ru.mvista.com>

On Wed, Dec 05, 2007 at 07:08:26PM +0300, Sergei Shtylyov wrote:

> Do what the commits commits f3e8d1da389fe2e514e31f6e93c690c8e1243849 and
> 9d360ab4a7568a8d177280f651a8a772ae52b9b9 failed to achieve -- actually
> convert the Alchemy code to irq_cpu.

Applied, thanks.

  Ralf

^ permalink raw reply

* Bug in Au1x00 UART or USB drivers for 2.6 kernels?
From: Nathan Eggan @ 2007-12-05 18:20 UTC (permalink / raw)
  To: linux-mips


All,

After some thorough testing and exploration, I believe I have uncovered a bug in the Au1x00 driver code of either the UART or the USB host in the Linux 2.6 kernels.  In short, this bug causes corruption of the data being returned from the UART whenever both it and the USB are in use.

The issue I’m seeing is pretty simple to describe.  When I have a data stream running over a UART, and I introduce traffic on the USB, the data returning from my UART is corrupted.  (I will describe what the corruption looks like shortly.)  Even simple events such as hotplugging a device can and will create the corruption in the UART’s serial stream.  As expected, the amount of corruption seems dependent upon the amount of traffic on the USB.
 
I discovered this issue while working with a DBAu1500 running a buildroot package that contains a Linux 2.6.21 kernel (patched for the MIPS from the linux-mips.org site) and Busybox 1.7.3.  To keep YAMON from bombing during builds, I’m still using a trusty gcc 3.4.5 compiler to build it all.

To determine if the issue was particular to just that board or that kernel source, I ran the same tests on two other DBAu1500s I have lying around here.  I tested two 2.6 kernels (a 2.6.17 and the 2.6.21) and one 2.4 kernel I used several years ago.  Both 2.6 kernels displayed the same issue.  The 2.4.26 kernel, on the other hand, worked flawlessly.  This does not really surprise me, as I’m presently tempted to believe that the issue somehow has to do with the interplay between the USB and the Au1x00 UART support that is now integrated into the standard 8250 driver.

To really monitor the byte sequences returning, I wrote a simple, multi-threaded test app designed to test the loopback of the UART.  It works by generating a 4k packet containing a repeating alphabet sequence [ABCDEF…XYZAB…], sending it over the UART, and then reading it back again.  (The loopback is achieved by tying the TX and RX leads of the UART together.)  On the receive side, the receive buffer is initialized with (0x20) characters, so I know whether bytes were skipped or misread.  Once an entire 4k packet has been sent and received, the TX and RX threads exit and the main application compares their results byte-for-byte.  Any discrepancies are reported, and then the process repeats.

(To aid in testing, I’ve included the code from this test app, as well as instructions for its use, at the conclusion of this email.)

Now, the corruption I’m seeing looks like this:  (All of this data was taken by running my test code on ttyS1(tts/1) and simply plugging and unplugging a USB 802.11 wireless device and connecting it to a WAP.)

<<<<<<<<<<< start: code output>>>>>>>>>>>>>
Iteration: 197...done, cross-checking...done, MATCHED!
- RX ERROR: '' found in read return.  Byte 81 of the 113 bytes read does not fit between 'A' & 'Z'!
done, cross-checking...

Index:  TX:     RX:
3568    'G'[47] ''[00]
3569    'H'[48] 'G'[47]
3570    'I'[49] 'H'[48]
3571    'J'[4a] 'I'[49]
3572    'K'[4b] 'J'[4a]
3573    'L'[4c] 'K'[4b]
3574    'M'[4d] 'L'[4c]
3575    'N'[4e] 'M'[4d]
3576    'O'[4f] 'N'[4e]
3577    'P'[50] 'O'[4f]
3578    'Q'[51] 'P'[50]
3579    'R'[52] 'Q'[51]
3580    'S'[53] 'R'[52]
3581    'T'[54] 'S'[53]
3582    'U'[55] 'T'[54]
3583    'V'[56] 'U'[55]

        *** 16 Errors detected @ iteration 197! ***
Iteration: 200...done, cross-checking...done, MATCHED!
- RX ERROR: '' found in read return.  Byte 57 of the 105 bytes read does not fit between 'A' & 'Z'!
done, cross-checking...

Index:  TX:     RX:
2176    'S'[53] ''[00]
2177    'T'[54] 'S'[53]
2178    'U'[55] 'T'[54]
2179    'V'[56] 'U'[55]
2180    'W'[57] 'V'[56]
2181    'X'[58] 'W'[57]
2182    'Y'[59] 'X'[58]
2183    'Z'[5a] 'Y'[59]
2184    'A'[41] 'Z'[5a]
2185    'B'[42] 'A'[41]
2186    'C'[43] 'B'[42]
2187    'D'[44] 'C'[43]
2188    'E'[45] 'D'[44]
2189    'F'[46] 'E'[45]
2190    'G'[47] 'F'[46]
2191    'H'[48] 'G'[47]

        *** 16 Errors detected @ iteration 200! ***
Iteration: 203...done, cross-checking...done, MATCHED!
- RX ERROR: '' found in read return.  Byte 81 of the 129 bytes read does not fit between 'A' & 'Z'!

- RX ERROR: '' found in read return.  Byte 113 of the 129 bytes read does not fit between 'A' & 'Z'!
done, cross-checking...

Index:  TX:     RX:
0832    'A'[41] ''[00]
0833    'B'[42] 'A'[41]
0834    'C'[43] 'B'[42]
0835    'D'[44] 'C'[43]
0836    'E'[45] 'D'[44]
0837    'F'[46] 'E'[45]
0838    'G'[47] 'F'[46]
0839    'H'[48] 'G'[47]
0840    'I'[49] 'H'[48]
0841    'J'[4a] 'I'[49]
0842    'K'[4b] 'J'[4a]
0843    'L'[4c] 'K'[4b]
0844    'M'[4d] 'L'[4c]
0845    'N'[4e] 'M'[4d]
0846    'O'[4f] 'N'[4e]
0847    'P'[50] 'O'[4f]
0864    'G'[47] ''[00]
0865    'H'[48] 'G'[47]
0866    'I'[49] 'H'[48]
0867    'J'[4a] 'I'[49]
0868    'K'[4b] 'J'[4a]
0869    'L'[4c] 'K'[4b]
0870    'M'[4d] 'L'[4c]
0871    'N'[4e] 'M'[4d]
0872    'O'[4f] 'N'[4e]
0873    'P'[50] 'O'[4f]
0874    'Q'[51] 'P'[50]
0875    'R'[52] 'Q'[51]
0876    'S'[53] 'R'[52]
0877    'T'[54] 'S'[53]
0878    'U'[55] 'T'[54]
0879    'V'[56] 'U'[55]

        *** 32 Errors detected @ iteration 203! ***
Iteration: 204...
<<<<<<<<<<< end: code output>>>>>>>>>>>>>

As you can see, when the error occurs it effects an entire 16-byte block, and only that 16-byte block.  If you look at the byte index numbers above, you will notice that the stream always resyncs after taking a hit.  So, the error is not just a dropped or inserted byte.  If either of those events occurred, I would expect the entire subsequent serial stream to be off by the number of characters dropped or added.  That does not seem to be happening here.

Moreover, as you can see, there is a definite pattern to the corruption within the block.  It is not random.  In a corrupted block, the first byte is cleared to “0” (a value my test code is not permitted to use.)  All subsequent bytes are then shifted 1 location to the right with the last byte being lost.

This is where my current work has brought me.  I am beginning to dive into the kernel source to see if I can track down the issue, but before doing so I figured I would pass this around to the gurus here to see what you thought.  By providing a solid description of the issue, as well as instructions for easily reproducing it, I’m hopeful that a resolution to it can be found soon.

Thanks for your help!
Nathan Eggan



PS - Here is the test code I’ve been using.  Please review it, and feel free to comment on it.  To compile it, I’ve been issuing “mipsel-linux-g++  -static –lpthread”.  (I ran -static against it to make it library independent when I was switching between 2.4 and 2.6 kernels.)

Test Code:
<<<<<<<<<<< start: test code>>>>>>>>>>>>>
// standard includes
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

// custom includes


/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

enum PARITY_TYPE
{
	NO_PARITY,
	PARITY
};


/******************************************************************************
 *
 * Name: OpenSerialPort
 *
 * Purpose: This function opens a standard serial port
 *
 *****************************************************************************/
int OpenSerialPort (
    char *dev_name,
    int baud_rate,
    int num_bytes,
    PARITY_TYPE parity
    )
{
    struct termios options;
    int ret_val = 0, fd = -1;

    // open the proper port
	char full_dev_name[256];
	ret_val = sprintf(full_dev_name, "/dev/%s", dev_name);
	if ( (ret_val <= 0) || (full_dev_name == NULL) )
	{
		printf("OpenSerialPort(): Failed to open serial port: '%s': errno = '%s'\n", full_dev_name, strerror(errno));
		// will return fd = -1
	}
	else
	{
		fd = open(full_dev_name, O_RDWR | O_NOCTTY| O_NDELAY);

		// error checking
		if (fd < 0)
		{
			printf ("OpenSerialPort(): Failed to open serial port: '%s': errno = '%s'\n", full_dev_name, strerror(errno));
		}
		else // success, now configure the port
		{
			// set the port to block on read
			fcntl(fd, F_SETFL, 0);

			// get the port's current attribute set
			tcgetattr(fd, &options);
			// set up the baud rate - lock at 115200 for now
			int desired_baud_rate = 0;
			switch (baud_rate)
			{
				// put the most likely first
				case 57600:
						desired_baud_rate = B57600;
						break;

				case 115200:
						desired_baud_rate = B115200;
						break;

				case 230400:
						desired_baud_rate = B230400;
						break;

#if !defined(HOST)
				case 460800:
						desired_baud_rate = B460800;
						break;

				case 500000:
						desired_baud_rate = B500000;
						break;

				case 576000:
						desired_baud_rate = B576000;
						break;

				case 921600:
						desired_baud_rate = B921600;
						break;

				case 1000000:
						desired_baud_rate = B1000000;
						break;

				case 1152000:
						desired_baud_rate = B1152000;
						break;

				case 1500000:
						desired_baud_rate = B1500000;
						break;

				case 2000000:
						desired_baud_rate = B2000000;
						break;

				case 2500000:
						desired_baud_rate = B2500000;
						break;

				case 3000000:
						desired_baud_rate = B3000000;
						break;

				case 3500000:
						desired_baud_rate = B3500000;
						break;

				case 4000000:
						desired_baud_rate = B4000000;
						break;
#endif

				case 50:
						desired_baud_rate = B50;
						break;

				case 75:
						desired_baud_rate = B75;
						break;

				case 110:
						desired_baud_rate = B110;
						break;

				case 134:
						desired_baud_rate = B134;
						break;

				case 150:
						desired_baud_rate = B150;
						break;

				case 200:
						desired_baud_rate = B200;
						break;

				case 300:
						desired_baud_rate = B300;
						break;

				case 600:
						desired_baud_rate = B600;
						break;

				case 1200:
						desired_baud_rate = B1200;
						break;

				case 1800:
						desired_baud_rate = B1800;
						break;

				case 2400:
						desired_baud_rate = B2400;
						break;

				case 4800:
						desired_baud_rate = B4800;
						break;

				case 9600:
						desired_baud_rate = B9600;
						break;

				case 19200:
						desired_baud_rate = B19200;
						break;

				case 38400:
						desired_baud_rate = B38400;
						break;

			}

			if (desired_baud_rate)
			{
				cfsetispeed(&options, desired_baud_rate);
				cfsetospeed(&options, desired_baud_rate);
			}
			else
			{
				/* set baud to something that is defined */
				cfsetispeed(&options, B115200);
				cfsetospeed(&options, B115200);
			}

			// enable the receiver and set local mode
			options.c_cflag |= (CLOCAL | CREAD); // NEVER set this directly, use "|="
			// set the 8N1
			options.c_cflag &= ~(PARENB); // disable parity checking [N]
			options.c_cflag &= ~(CSTOPB); // disable 2 stop bits (means 1 stop bit) [1]
			options.c_cflag &= ~(CSIZE);  // mask the character bits
			options.c_cflag |= num_bytes;     // select 8 data bits [8]

			// output options -- post process output and map new lines to
			// carriage return-new lines
			options.c_oflag |= OPOST | ONLCR;

			// lock in the options
			tcsetattr(fd, TCSANOW, &options);


		}
	}

    return(fd);
}

/******************************************************************************
 *
 * Name: OpenRawSerialPort
 *
 * Purpose: This function opens a raw serial port
 *
 *****************************************************************************/
int OpenRawSerialPort (
    char *dev_name,
    int baud_rate,
    int num_bytes,
    PARITY_TYPE parity,
	unsigned char vmin,
	unsigned char vtime
    )
{

#define ALT_SERIAL_SETUP	(1)

    int fd = OpenSerialPort (dev_name, baud_rate, num_bytes, parity);

    if (fd>= 0)
    {
        struct termios options;

        // get the port's current attribute set
        tcgetattr(fd, &options);

#if ALT_SERIAL_SETUP
		options.c_lflag = 0;
		// ignore framing and parity errors
		options.c_iflag = IGNPAR;
        // disable output post-processing
		options.c_oflag = 0;
#else
        
		// disable H/W flow control
        options.c_cflag &= ~(CRTSCTS);
        // use RAW input - i.e. do NOT process the stream, simply pump the bytes in/out
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        // disable input parity check
        options.c_iflag &= ~(INPCK);
        // disable S/W flow control
        options.c_iflag &= ~(IXON | IXOFF | IXANY);
        // disable a bunch of stuff
        options.c_iflag &= ~(IGNBRK | BRKINT | INLCR | IGNCR | ICRNL | IUCLC | IMAXBEL);
        // disable output post-processing
        options.c_oflag &= ~(OPOST);
#endif
        // set the return rules for read()
        options.c_cc[VMIN] = vmin; // defaults to MAX_INPUT; at least MAX_INPUT bytes must be read;
        options.c_cc[VTIME] = vtime; // defaults to 1 => inter-byte delay = 1/10 sec

		// flush read or written data
		tcflush(fd, TCIFLUSH);
        // lock in the options
        tcsetattr(fd, TCSANOW, &options);
    }

    return (fd);
}


/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

//#define DEBUG


#define STRING_SIZE (4096)
#define MAX_TIMEOUTS (10)

#ifdef DEBUG
#define DEBUG_PRINT		(printf)
#else
#define DEBUG_PRINT(...)
#endif

// globals
int fd;
pthread_t tx_thread, rx_thread;
unsigned char *send_string = NULL;
unsigned char *recv_string = NULL;

/******************************************************************************
 *
 * Name:	catchControlC
 *
 * Purpose:	Catches the control-c and triggers a shutdown event so the
 *			application shuts down gracefully.
 *
 *****************************************************************************/
void catchControlC(int)
{
	printf("\n- killing tx_thread...\n");fflush(stdout);
	pthread_kill(tx_thread, 0);
	printf("\n- killing rx_thread...\n");fflush(stdout);
	pthread_kill(rx_thread, 0);
	printf("\n- closing fd...\n");fflush(stdout);
	close(fd);

	if (send_string)
	{
		delete (send_string);
	}
	if (recv_string)
	{
		delete (recv_string);
	}

	exit(1);
}


void *tx(void *params)
{
	DEBUG_PRINT("TX thread\n");

	// unsigned char *send_string = (char *)params;
	if (send_string == NULL)
	{
		printf("ERROR: send_string = NULL\n");
		pthread_exit(NULL);
	}

	// scan for non-alphabet characters in received string
	for (int x=0; x < STRING_SIZE; x++)
	{
		if ( (send_string[x] < 'A') || (send_string[x]> 'Z') )
		{
			printf("\n- TX ERROR: '%c' found in read return!\n", send_string[x]);
		}
	}

	int num_bytes_written = 0, num_timeouts = 0;
	while ( (num_bytes_written < STRING_SIZE) && (num_timeouts < MAX_TIMEOUTS) )
	{
		int z = write(fd, &send_string[num_bytes_written], (STRING_SIZE - num_bytes_written));
		if (z == 0) // timed out
		{
			num_timeouts++;
			printf("- TX: %d of %d sent, timeouts: %d\n", num_bytes_written, STRING_SIZE, num_timeouts);fflush(stdout);
		}
		else if ( num_bytes_written < 0 )
		{
			printf("*** ERROR: Failed to send!\n");fflush(stdout);
			pthread_exit(NULL);
		}
		num_bytes_written += z;
		DEBUG_PRINT("- TX: %d of %d sent, timeouts: %d\n", num_bytes_written, STRING_SIZE, num_timeouts);fflush(stdout);
	}
	
	if (num_timeouts> MAX_TIMEOUTS)
	{
		printf("-- TX: Exceeded timeout allotment (%d)\n", MAX_TIMEOUTS);
	}

	pthread_exit(NULL);
}


void *rx(void *params)
{
	DEBUG_PRINT("RX thread\n");

	// unsigned char *recv_string = (char *)params;
	if (recv_string == NULL)
	{
		printf("ERROR: recv_string = NULL\n");
		pthread_exit(NULL);
	}

	int num_bytes_read = 0, num_timeouts = 0;
	while ( (num_bytes_read < STRING_SIZE) && (num_timeouts < MAX_TIMEOUTS) )
	{
		int y = read(fd, &recv_string[num_bytes_read], (STRING_SIZE - num_bytes_read));
		if (y == 0) // timed out
		{
			num_timeouts++;
			printf("- RX: %d of %d received, timeouts: %d\n", num_bytes_read, STRING_SIZE, num_timeouts);fflush(stdout);
		}
		else if ( y < 0 ) // error
		{
			printf("*** ERROR: Read Error!\n");fflush(stdout);
			pthread_exit(NULL);
		}

		// scan for non-alphabet characters in received string
		for (int x=0; x < y; x++)
		{
			if ( (recv_string[num_bytes_read + x] < 'A') || (recv_string[num_bytes_read + x]> 'Z') )
			{
				printf("\n- RX ERROR: '%c' found in read return.  Byte %d of the %d bytes read does not fit between 'A' & 'Z'!\n", recv_string[num_bytes_read + x], x, y);
			}
		}

		num_bytes_read += y;
		DEBUG_PRINT("- RX: %d of %d received, timeouts: %d\n", num_bytes_read, STRING_SIZE, num_timeouts);fflush(stdout);
	}
	
	if (num_timeouts> MAX_TIMEOUTS)
	{
		printf("-- TX: Exceeded timeout allotment (%d)\n", MAX_TIMEOUTS);
	}

	pthread_exit(NULL);
}


int main (int argc, char *argv[])
{
	int ret_val = -1;

	unsigned char c;
	send_string = (unsigned char*) new unsigned char[STRING_SIZE];
	recv_string = (unsigned char*) new unsigned char[STRING_SIZE];

	// random seed
	srand(time(NULL));

	// -- set up signal controls --
	if(signal(SIGINT, SIG_IGN) != SIG_IGN)
	{
		signal(SIGINT, catchControlC);
	}

	if (argc == 2) // app name + serial port
	{
		int num_loops = 0;

		DEBUG_PRINT("starting...\n");fflush(stdout);

		fd = OpenRawSerialPort(argv[1], 115200, CS8, NO_PARITY, 0, 10);
		if (fd < 0)
		{
			printf("*** ERROR: Failed to open serial port: '%s',(%d)\n", strerror(errno), fd);fflush(stdout);
			exit(-1);
		}

		while(1)
		{
			printf("Iteration: %d...", num_loops);fflush(stdout);

			/* setup send string */
// cap alphabet
			c = 'A';
			for (int x = 0; x < STRING_SIZE; x++)
			{
				send_string[x] = c++;
				if (c == '[') // 1 step past 'Z'
				{
					c = 'A';
				}
			}
	
			/* clear recv string */
			// fill with  characters
			memset(recv_string, ' ', STRING_SIZE);

	        /* create both threads - receiver first since its the consumer */
			if ( pthread_create(&rx_thread, NULL, rx, (void *)recv_string) != 0 )
			{
				exit(-1);
			}
			if ( pthread_create(&tx_thread, NULL, tx, (void *)send_string) != 0 )
			{
				exit(-1);
			}

			/* wait for threads to complete */
			pthread_join(tx_thread, NULL);
			pthread_join(rx_thread, NULL);
	
			printf("done, cross-checking...");fflush(stdout);
			
			int num_errors = 0, offset = 0;

			for (unsigned int x = 0; x < STRING_SIZE; x++)
			{
				if ( send_string[x] != recv_string[x] )
				{
					if (num_errors == 0)
					{
						printf("\n\nIndex:\tTX:\tRX:\n");fflush(stdout);
					}
					printf("%04d\t'%c'[%02x]\t'%c'[%02x]\n", x, send_string[x], send_string[x], recv_string[x], recv_string[x]);fflush(stdout);
					num_errors++;
				}
			}

			if (num_errors == 0)
			{
				printf("done, MATCHED!");
			}
			else
			{
				printf("\n\t*** %d Errors detected @ iteration %d! ***\n", num_errors, num_loops);
			}

			printf("\r");
			usleep(10);
			num_loops++;
		}
	}
	else // show usage
	{
		printf("Error: Usage: '%s ttySx'\n", argv[0]);
	}

	return(ret_val);
}

<<<<<<<<<<< end: test code>>>>>>>>>>>>>

_________________________________________________________________
Your smile counts. The more smiles you share, the more we donate.  Join in.
www.windowslive.com/smile?ocid=TXT_TAGLM_Wave2_oprsmilewlhmtagline
From ralf@linux-mips.org Wed Dec  5 18:22:32 2007
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 05 Dec 2007 18:22:34 +0000 (GMT)
Received: from localhost.localdomain ([127.0.0.1]:21412 "EHLO
	dl5rb.ham-radio-op.net") by ftp.linux-mips.org with ESMTP
	id S20030716AbXLESWc (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 5 Dec 2007 18:22:32 +0000
Received: from denk.linux-mips.net (denk.linux-mips.net [127.0.0.1])
	by dl5rb.ham-radio-op.net (8.14.1/8.13.8) with ESMTP id lB5IL7pD011316;
	Wed, 5 Dec 2007 18:21:32 GMT
Received: (from ralf@localhost)
	by denk.linux-mips.net (8.14.1/8.14.1/Submit) id lB5IL6hH011315;
	Wed, 5 Dec 2007 18:21:06 GMT
Date:	Wed, 5 Dec 2007 18:21:06 +0000
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH 2/2] Alchemy: fix IRQ bases
Message-ID: <20071205182106.GB10697@linux-mips.org>
References: <200712051908.26703.sshtylyov@ru.mvista.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <200712051908.26703.sshtylyov@ru.mvista.com>
User-Agent: Mutt/1.5.17 (2007-11-01)
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 17706
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Wed, Dec 05, 2007 at 07:08:26PM +0300, Sergei Shtylyov wrote:

> Do what the commits commits f3e8d1da389fe2e514e31f6e93c690c8e1243849 and
> 9d360ab4a7568a8d177280f651a8a772ae52b9b9 failed to achieve -- actually
> convert the Alchemy code to irq_cpu.

Applied, thanks.

  Ralf

^ permalink raw reply

* Bug in Au1x00 UART or USB drivers for 2.6 kernels?
From: Nathan Eggan @ 2007-12-05 18:20 UTC (permalink / raw)
  To: linux-mips


All,

After some thorough testing and exploration, I believe I have uncovered a bug in the Au1x00 driver code of either the UART or the USB host in the Linux 2.6 kernels.  In short, this bug causes corruption of the data being returned from the UART whenever both it and the USB are in use.

The issue I’m seeing is pretty simple to describe.  When I have a data stream running over a UART, and I introduce traffic on the USB, the data returning from my UART is corrupted.  (I will describe what the corruption looks like shortly.)  Even simple events such as hotplugging a device can and will create the corruption in the UART’s serial stream.  As expected, the amount of corruption seems dependent upon the amount of traffic on the USB.
 
I discovered this issue while working with a DBAu1500 running a buildroot package that contains a Linux 2.6.21 kernel (patched for the MIPS from the linux-mips.org site) and Busybox 1.7.3.  To keep YAMON from bombing during builds, I’m still using a trusty gcc 3.4.5 compiler to build it all.

To determine if the issue was particular to just that board or that kernel source, I ran the same tests on two other DBAu1500s I have lying around here.  I tested two 2.6 kernels (a 2.6.17 and the 2.6.21) and one 2.4 kernel I used several years ago.  Both 2.6 kernels displayed the same issue.  The 2.4.26 kernel, on the other hand, worked flawlessly.  This does not really surprise me, as I’m presently tempted to believe that the issue somehow has to do with the interplay between the USB and the Au1x00 UART support that is now integrated into the standard 8250 driver.

To really monitor the byte sequences returning, I wrote a simple, multi-threaded test app designed to test the loopback of the UART.  It works by generating a 4k packet containing a repeating alphabet sequence [ABCDEF…XYZAB…], sending it over the UART, and then reading it back again.  (The loopback is achieved by tying the TX and RX leads of the UART together.)  On the receive side, the receive buffer is initialized with (0x20) characters, so I know whether bytes were skipped or misread.  Once an entire 4k packet has been sent and received, the TX and RX threads exit and the main application compares their results byte-for-byte.  Any discrepancies are reported, and then the process repeats.

(To aid in testing, I’ve included the code from this test app, as well as instructions for its use, at the conclusion of this email.)

Now, the corruption I’m seeing looks like this:  (All of this data was taken by running my test code on ttyS1(tts/1) and simply plugging and unplugging a USB 802.11 wireless device and connecting it to a WAP.)

<<<<<<<<<<< start: code output>>>>>>>>>>>>>
Iteration: 197...done, cross-checking...done, MATCHED!
- RX ERROR: '' found in read return.  Byte 81 of the 113 bytes read does not fit between 'A' & 'Z'!
done, cross-checking...

Index:  TX:     RX:
3568    'G'[47] ''[00]
3569    'H'[48] 'G'[47]
3570    'I'[49] 'H'[48]
3571    'J'[4a] 'I'[49]
3572    'K'[4b] 'J'[4a]
3573    'L'[4c] 'K'[4b]
3574    'M'[4d] 'L'[4c]
3575    'N'[4e] 'M'[4d]
3576    'O'[4f] 'N'[4e]
3577    'P'[50] 'O'[4f]
3578    'Q'[51] 'P'[50]
3579    'R'[52] 'Q'[51]
3580    'S'[53] 'R'[52]
3581    'T'[54] 'S'[53]
3582    'U'[55] 'T'[54]
3583    'V'[56] 'U'[55]

        *** 16 Errors detected @ iteration 197! ***
Iteration: 200...done, cross-checking...done, MATCHED!
- RX ERROR: '' found in read return.  Byte 57 of the 105 bytes read does not fit between 'A' & 'Z'!
done, cross-checking...

Index:  TX:     RX:
2176    'S'[53] ''[00]
2177    'T'[54] 'S'[53]
2178    'U'[55] 'T'[54]
2179    'V'[56] 'U'[55]
2180    'W'[57] 'V'[56]
2181    'X'[58] 'W'[57]
2182    'Y'[59] 'X'[58]
2183    'Z'[5a] 'Y'[59]
2184    'A'[41] 'Z'[5a]
2185    'B'[42] 'A'[41]
2186    'C'[43] 'B'[42]
2187    'D'[44] 'C'[43]
2188    'E'[45] 'D'[44]
2189    'F'[46] 'E'[45]
2190    'G'[47] 'F'[46]
2191    'H'[48] 'G'[47]

        *** 16 Errors detected @ iteration 200! ***
Iteration: 203...done, cross-checking...done, MATCHED!
- RX ERROR: '' found in read return.  Byte 81 of the 129 bytes read does not fit between 'A' & 'Z'!

- RX ERROR: '' found in read return.  Byte 113 of the 129 bytes read does not fit between 'A' & 'Z'!
done, cross-checking...

Index:  TX:     RX:
0832    'A'[41] ''[00]
0833    'B'[42] 'A'[41]
0834    'C'[43] 'B'[42]
0835    'D'[44] 'C'[43]
0836    'E'[45] 'D'[44]
0837    'F'[46] 'E'[45]
0838    'G'[47] 'F'[46]
0839    'H'[48] 'G'[47]
0840    'I'[49] 'H'[48]
0841    'J'[4a] 'I'[49]
0842    'K'[4b] 'J'[4a]
0843    'L'[4c] 'K'[4b]
0844    'M'[4d] 'L'[4c]
0845    'N'[4e] 'M'[4d]
0846    'O'[4f] 'N'[4e]
0847    'P'[50] 'O'[4f]
0864    'G'[47] ''[00]
0865    'H'[48] 'G'[47]
0866    'I'[49] 'H'[48]
0867    'J'[4a] 'I'[49]
0868    'K'[4b] 'J'[4a]
0869    'L'[4c] 'K'[4b]
0870    'M'[4d] 'L'[4c]
0871    'N'[4e] 'M'[4d]
0872    'O'[4f] 'N'[4e]
0873    'P'[50] 'O'[4f]
0874    'Q'[51] 'P'[50]
0875    'R'[52] 'Q'[51]
0876    'S'[53] 'R'[52]
0877    'T'[54] 'S'[53]
0878    'U'[55] 'T'[54]
0879    'V'[56] 'U'[55]

        *** 32 Errors detected @ iteration 203! ***
Iteration: 204...
<<<<<<<<<<< end: code output>>>>>>>>>>>>>

As you can see, when the error occurs it effects an entire 16-byte block, and only that 16-byte block.  If you look at the byte index numbers above, you will notice that the stream always resyncs after taking a hit.  So, the error is not just a dropped or inserted byte.  If either of those events occurred, I would expect the entire subsequent serial stream to be off by the number of characters dropped or added.  That does not seem to be happening here.

Moreover, as you can see, there is a definite pattern to the corruption within the block.  It is not random.  In a corrupted block, the first byte is cleared to “0” (a value my test code is not permitted to use.)  All subsequent bytes are then shifted 1 location to the right with the last byte being lost.

This is where my current work has brought me.  I am beginning to dive into the kernel source to see if I can track down the issue, but before doing so I figured I would pass this around to the gurus here to see what you thought.  By providing a solid description of the issue, as well as instructions for easily reproducing it, I’m hopeful that a resolution to it can be found soon.

Thanks for your help!
Nathan Eggan



PS - Here is the test code I’ve been using.  Please review it, and feel free to comment on it.  To compile it, I’ve been issuing “mipsel-linux-g++  -static –lpthread”.  (I ran -static against it to make it library independent when I was switching between 2.4 and 2.6 kernels.)

Test Code:
<<<<<<<<<<< start: test code>>>>>>>>>>>>>
// standard includes
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

// custom includes


/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

enum PARITY_TYPE
{
	NO_PARITY,
	PARITY
};


/******************************************************************************
 *
 * Name: OpenSerialPort
 *
 * Purpose: This function opens a standard serial port
 *
 *****************************************************************************/
int OpenSerialPort (
    char *dev_name,
    int baud_rate,
    int num_bytes,
    PARITY_TYPE parity
    )
{
    struct termios options;
    int ret_val = 0, fd = -1;

    // open the proper port
	char full_dev_name[256];
	ret_val = sprintf(full_dev_name, "/dev/%s", dev_name);
	if ( (ret_val <= 0) || (full_dev_name == NULL) )
	{
		printf("OpenSerialPort(): Failed to open serial port: '%s': errno = '%s'\n", full_dev_name, strerror(errno));
		// will return fd = -1
	}
	else
	{
		fd = open(full_dev_name, O_RDWR | O_NOCTTY| O_NDELAY);

		// error checking
		if (fd < 0)
		{
			printf ("OpenSerialPort(): Failed to open serial port: '%s': errno = '%s'\n", full_dev_name, strerror(errno));
		}
		else // success, now configure the port
		{
			// set the port to block on read
			fcntl(fd, F_SETFL, 0);

			// get the port's current attribute set
			tcgetattr(fd, &options);
			// set up the baud rate - lock at 115200 for now
			int desired_baud_rate = 0;
			switch (baud_rate)
			{
				// put the most likely first
				case 57600:
						desired_baud_rate = B57600;
						break;

				case 115200:
						desired_baud_rate = B115200;
						break;

				case 230400:
						desired_baud_rate = B230400;
						break;

#if !defined(HOST)
				case 460800:
						desired_baud_rate = B460800;
						break;

				case 500000:
						desired_baud_rate = B500000;
						break;

				case 576000:
						desired_baud_rate = B576000;
						break;

				case 921600:
						desired_baud_rate = B921600;
						break;

				case 1000000:
						desired_baud_rate = B1000000;
						break;

				case 1152000:
						desired_baud_rate = B1152000;
						break;

				case 1500000:
						desired_baud_rate = B1500000;
						break;

				case 2000000:
						desired_baud_rate = B2000000;
						break;

				case 2500000:
						desired_baud_rate = B2500000;
						break;

				case 3000000:
						desired_baud_rate = B3000000;
						break;

				case 3500000:
						desired_baud_rate = B3500000;
						break;

				case 4000000:
						desired_baud_rate = B4000000;
						break;
#endif

				case 50:
						desired_baud_rate = B50;
						break;

				case 75:
						desired_baud_rate = B75;
						break;

				case 110:
						desired_baud_rate = B110;
						break;

				case 134:
						desired_baud_rate = B134;
						break;

				case 150:
						desired_baud_rate = B150;
						break;

				case 200:
						desired_baud_rate = B200;
						break;

				case 300:
						desired_baud_rate = B300;
						break;

				case 600:
						desired_baud_rate = B600;
						break;

				case 1200:
						desired_baud_rate = B1200;
						break;

				case 1800:
						desired_baud_rate = B1800;
						break;

				case 2400:
						desired_baud_rate = B2400;
						break;

				case 4800:
						desired_baud_rate = B4800;
						break;

				case 9600:
						desired_baud_rate = B9600;
						break;

				case 19200:
						desired_baud_rate = B19200;
						break;

				case 38400:
						desired_baud_rate = B38400;
						break;

			}

			if (desired_baud_rate)
			{
				cfsetispeed(&options, desired_baud_rate);
				cfsetospeed(&options, desired_baud_rate);
			}
			else
			{
				/* set baud to something that is defined */
				cfsetispeed(&options, B115200);
				cfsetospeed(&options, B115200);
			}

			// enable the receiver and set local mode
			options.c_cflag |= (CLOCAL | CREAD); // NEVER set this directly, use "|="
			// set the 8N1
			options.c_cflag &= ~(PARENB); // disable parity checking [N]
			options.c_cflag &= ~(CSTOPB); // disable 2 stop bits (means 1 stop bit) [1]
			options.c_cflag &= ~(CSIZE);  // mask the character bits
			options.c_cflag |= num_bytes;     // select 8 data bits [8]

			// output options -- post process output and map new lines to
			// carriage return-new lines
			options.c_oflag |= OPOST | ONLCR;

			// lock in the options
			tcsetattr(fd, TCSANOW, &options);


		}
	}

    return(fd);
}

/******************************************************************************
 *
 * Name: OpenRawSerialPort
 *
 * Purpose: This function opens a raw serial port
 *
 *****************************************************************************/
int OpenRawSerialPort (
    char *dev_name,
    int baud_rate,
    int num_bytes,
    PARITY_TYPE parity,
	unsigned char vmin,
	unsigned char vtime
    )
{

#define ALT_SERIAL_SETUP	(1)

    int fd = OpenSerialPort (dev_name, baud_rate, num_bytes, parity);

    if (fd>= 0)
    {
        struct termios options;

        // get the port's current attribute set
        tcgetattr(fd, &options);

#if ALT_SERIAL_SETUP
		options.c_lflag = 0;
		// ignore framing and parity errors
		options.c_iflag = IGNPAR;
        // disable output post-processing
		options.c_oflag = 0;
#else
        
		// disable H/W flow control
        options.c_cflag &= ~(CRTSCTS);
        // use RAW input - i.e. do NOT process the stream, simply pump the bytes in/out
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        // disable input parity check
        options.c_iflag &= ~(INPCK);
        // disable S/W flow control
        options.c_iflag &= ~(IXON | IXOFF | IXANY);
        // disable a bunch of stuff
        options.c_iflag &= ~(IGNBRK | BRKINT | INLCR | IGNCR | ICRNL | IUCLC | IMAXBEL);
        // disable output post-processing
        options.c_oflag &= ~(OPOST);
#endif
        // set the return rules for read()
        options.c_cc[VMIN] = vmin; // defaults to MAX_INPUT; at least MAX_INPUT bytes must be read;
        options.c_cc[VTIME] = vtime; // defaults to 1 => inter-byte delay = 1/10 sec

		// flush read or written data
		tcflush(fd, TCIFLUSH);
        // lock in the options
        tcsetattr(fd, TCSANOW, &options);
    }

    return (fd);
}


/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

//#define DEBUG


#define STRING_SIZE (4096)
#define MAX_TIMEOUTS (10)

#ifdef DEBUG
#define DEBUG_PRINT		(printf)
#else
#define DEBUG_PRINT(...)
#endif

// globals
int fd;
pthread_t tx_thread, rx_thread;
unsigned char *send_string = NULL;
unsigned char *recv_string = NULL;

/******************************************************************************
 *
 * Name:	catchControlC
 *
 * Purpose:	Catches the control-c and triggers a shutdown event so the
 *			application shuts down gracefully.
 *
 *****************************************************************************/
void catchControlC(int)
{
	printf("\n- killing tx_thread...\n");fflush(stdout);
	pthread_kill(tx_thread, 0);
	printf("\n- killing rx_thread...\n");fflush(stdout);
	pthread_kill(rx_thread, 0);
	printf("\n- closing fd...\n");fflush(stdout);
	close(fd);

	if (send_string)
	{
		delete (send_string);
	}
	if (recv_string)
	{
		delete (recv_string);
	}

	exit(1);
}


void *tx(void *params)
{
	DEBUG_PRINT("TX thread\n");

	// unsigned char *send_string = (char *)params;
	if (send_string == NULL)
	{
		printf("ERROR: send_string = NULL\n");
		pthread_exit(NULL);
	}

	// scan for non-alphabet characters in received string
	for (int x=0; x < STRING_SIZE; x++)
	{
		if ( (send_string[x] < 'A') || (send_string[x]> 'Z') )
		{
			printf("\n- TX ERROR: '%c' found in read return!\n", send_string[x]);
		}
	}

	int num_bytes_written = 0, num_timeouts = 0;
	while ( (num_bytes_written < STRING_SIZE) && (num_timeouts < MAX_TIMEOUTS) )
	{
		int z = write(fd, &send_string[num_bytes_written], (STRING_SIZE - num_bytes_written));
		if (z == 0) // timed out
		{
			num_timeouts++;
			printf("- TX: %d of %d sent, timeouts: %d\n", num_bytes_written, STRING_SIZE, num_timeouts);fflush(stdout);
		}
		else if ( num_bytes_written < 0 )
		{
			printf("*** ERROR: Failed to send!\n");fflush(stdout);
			pthread_exit(NULL);
		}
		num_bytes_written += z;
		DEBUG_PRINT("- TX: %d of %d sent, timeouts: %d\n", num_bytes_written, STRING_SIZE, num_timeouts);fflush(stdout);
	}
	
	if (num_timeouts> MAX_TIMEOUTS)
	{
		printf("-- TX: Exceeded timeout allotment (%d)\n", MAX_TIMEOUTS);
	}

	pthread_exit(NULL);
}


void *rx(void *params)
{
	DEBUG_PRINT("RX thread\n");

	// unsigned char *recv_string = (char *)params;
	if (recv_string == NULL)
	{
		printf("ERROR: recv_string = NULL\n");
		pthread_exit(NULL);
	}

	int num_bytes_read = 0, num_timeouts = 0;
	while ( (num_bytes_read < STRING_SIZE) && (num_timeouts < MAX_TIMEOUTS) )
	{
		int y = read(fd, &recv_string[num_bytes_read], (STRING_SIZE - num_bytes_read));
		if (y == 0) // timed out
		{
			num_timeouts++;
			printf("- RX: %d of %d received, timeouts: %d\n", num_bytes_read, STRING_SIZE, num_timeouts);fflush(stdout);
		}
		else if ( y < 0 ) // error
		{
			printf("*** ERROR: Read Error!\n");fflush(stdout);
			pthread_exit(NULL);
		}

		// scan for non-alphabet characters in received string
		for (int x=0; x < y; x++)
		{
			if ( (recv_string[num_bytes_read + x] < 'A') || (recv_string[num_bytes_read + x]> 'Z') )
			{
				printf("\n- RX ERROR: '%c' found in read return.  Byte %d of the %d bytes read does not fit between 'A' & 'Z'!\n", recv_string[num_bytes_read + x], x, y);
			}
		}

		num_bytes_read += y;
		DEBUG_PRINT("- RX: %d of %d received, timeouts: %d\n", num_bytes_read, STRING_SIZE, num_timeouts);fflush(stdout);
	}
	
	if (num_timeouts> MAX_TIMEOUTS)
	{
		printf("-- TX: Exceeded timeout allotment (%d)\n", MAX_TIMEOUTS);
	}

	pthread_exit(NULL);
}


int main (int argc, char *argv[])
{
	int ret_val = -1;

	unsigned char c;
	send_string = (unsigned char*) new unsigned char[STRING_SIZE];
	recv_string = (unsigned char*) new unsigned char[STRING_SIZE];

	// random seed
	srand(time(NULL));

	// -- set up signal controls --
	if(signal(SIGINT, SIG_IGN) != SIG_IGN)
	{
		signal(SIGINT, catchControlC);
	}

	if (argc == 2) // app name + serial port
	{
		int num_loops = 0;

		DEBUG_PRINT("starting...\n");fflush(stdout);

		fd = OpenRawSerialPort(argv[1], 115200, CS8, NO_PARITY, 0, 10);
		if (fd < 0)
		{
			printf("*** ERROR: Failed to open serial port: '%s',(%d)\n", strerror(errno), fd);fflush(stdout);
			exit(-1);
		}

		while(1)
		{
			printf("Iteration: %d...", num_loops);fflush(stdout);

			/* setup send string */
// cap alphabet
			c = 'A';
			for (int x = 0; x < STRING_SIZE; x++)
			{
				send_string[x] = c++;
				if (c == '[') // 1 step past 'Z'
				{
					c = 'A';
				}
			}
	
			/* clear recv string */
			// fill with  characters
			memset(recv_string, ' ', STRING_SIZE);

	        /* create both threads - receiver first since its the consumer */
			if ( pthread_create(&rx_thread, NULL, rx, (void *)recv_string) != 0 )
			{
				exit(-1);
			}
			if ( pthread_create(&tx_thread, NULL, tx, (void *)send_string) != 0 )
			{
				exit(-1);
			}

			/* wait for threads to complete */
			pthread_join(tx_thread, NULL);
			pthread_join(rx_thread, NULL);
	
			printf("done, cross-checking...");fflush(stdout);
			
			int num_errors = 0, offset = 0;

			for (unsigned int x = 0; x < STRING_SIZE; x++)
			{
				if ( send_string[x] != recv_string[x] )
				{
					if (num_errors == 0)
					{
						printf("\n\nIndex:\tTX:\tRX:\n");fflush(stdout);
					}
					printf("%04d\t'%c'[%02x]\t'%c'[%02x]\n", x, send_string[x], send_string[x], recv_string[x], recv_string[x]);fflush(stdout);
					num_errors++;
				}
			}

			if (num_errors == 0)
			{
				printf("done, MATCHED!");
			}
			else
			{
				printf("\n\t*** %d Errors detected @ iteration %d! ***\n", num_errors, num_loops);
			}

			printf("\r");
			usleep(10);
			num_loops++;
		}
	}
	else // show usage
	{
		printf("Error: Usage: '%s ttySx'\n", argv[0]);
	}

	return(ret_val);
}

<<<<<<<<<<< end: test code>>>>>>>>>>>>>

_________________________________________________________________
Your smile counts. The more smiles you share, the more we donate.  Join in.
www.windowslive.com/smile?ocid=TXT_TAGLM_Wave2_oprsmilewlhmtagline

^ permalink raw reply

* Re: [PATCH 1/2] Alchemy: replace ffs() with __ffs()
From: Ralf Baechle @ 2007-12-05 18:06 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: linux-mips
In-Reply-To: <200712051908.24027.sshtylyov@ru.mvista.com>

On Wed, Dec 05, 2007 at 07:08:24PM +0300, Sergei Shtylyov wrote:

> Fix havoc wrought by commit 56f621c7f6f735311eed3f36858b402013023c18 --
> au_ffs() and ffs() are equivalent, that patch should have just replaced
> one with another.  Now replace ffs() with __ffs() which returns an
> unbiased bit number.

Thanks, applied.

  Ralf

^ permalink raw reply

* Re: [PATCH 0/2] Alchemy: fix interrupt routing
From: Manuel Lauss @ 2007-12-05 16:39 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: ralf, linux-mips
In-Reply-To: <200712051908.18780.sshtylyov@ru.mvista.com>

Sergei,

Sergei Shtylyov schrieb:
> Hello.
> 
>    The two following patches together fix the interrupt routing currently broken
> and causing boot failure with such messages:
> 
> unexpected IRQ # 8
> irq 8, desc: 80406dd0, depth: 1, count: 0, unhandled: 0
> ->handle_irq():  80157d70, handle_bad_irq+0x0/0x38c
> ->chip(): 804016d0, 0x804016d0
> ->action(): 00000000
>   IRQ_DISABLED set
> 
>    The patches are against the Linus' tree...
> 
> WBR, Sergei

Thanks a billion!
Finally I can boot linux-2.6.24-rc on my Au1200 again!

-- 
Manuel Lauss
HSSE / FH Hagenberg

^ permalink raw reply

* [PATCH 2/2] Alchemy: fix IRQ bases
From: Sergei Shtylyov @ 2007-12-05 16:08 UTC (permalink / raw)
  To: ralf; +Cc: linux-mips

Do what the commits commits f3e8d1da389fe2e514e31f6e93c690c8e1243849 and
9d360ab4a7568a8d177280f651a8a772ae52b9b9 failed to achieve -- actually
convert the Alchemy code to irq_cpu.

 arch/mips/au1000/common/irq.c         |    8 ++++----
 include/asm-mips/mach-au1x00/au1000.h |   21 +++++++++++----------
 2 files changed, 15 insertions(+), 14 deletions(-)

Index: linux-2.6/arch/mips/au1000/common/irq.c
===================================================================
--- linux-2.6.orig/arch/mips/au1000/common/irq.c
+++ linux-2.6/arch/mips/au1000/common/irq.c
@@ -464,7 +464,7 @@ static void intc0_req0_irqdispatch(void)
 #endif
 	bit = __ffs(intc0_req0);
 	intc0_req0 &= ~(1 << bit);
-	do_IRQ(MIPS_CPU_IRQ_BASE + bit);
+	do_IRQ(AU1000_INTC0_INT_BASE + bit);
 }
 
 
@@ -480,7 +480,7 @@ static void intc0_req1_irqdispatch(void)
 
 	bit = __ffs(intc0_req1);
 	intc0_req1 &= ~(1 << bit);
-	do_IRQ(bit);
+	do_IRQ(AU1000_INTC0_INT_BASE + bit);
 }
 
 
@@ -500,7 +500,7 @@ static void intc1_req0_irqdispatch(void)
 
 	bit = __ffs(intc1_req0);
 	intc1_req0 &= ~(1 << bit);
-	do_IRQ(MIPS_CPU_IRQ_BASE + 32 + bit);
+	do_IRQ(AU1000_INTC1_INT_BASE + bit);
 }
 
 
@@ -516,7 +516,7 @@ static void intc1_req1_irqdispatch(void)
 
 	bit = __ffs(intc1_req1);
 	intc1_req1 &= ~(1 << bit);
-	do_IRQ(MIPS_CPU_IRQ_BASE + 32 + bit);
+	do_IRQ(AU1000_INTC1_INT_BASE + bit);
 }
 
 asmlinkage void plat_irq_dispatch(void)
Index: linux-2.6/include/asm-mips/mach-au1x00/au1000.h
===================================================================
--- linux-2.6.orig/include/asm-mips/mach-au1x00/au1000.h
+++ linux-2.6/include/asm-mips/mach-au1x00/au1000.h
@@ -526,7 +526,7 @@ extern struct au1xxx_irqmap au1xxx_irq_m
 /* Au1000 */
 #ifdef CONFIG_SOC_AU1000
 enum soc_au1000_ints {
-	AU1000_FIRST_INT	= MIPS_CPU_IRQ_BASE,
+	AU1000_FIRST_INT	= MIPS_CPU_IRQ_BASE + 8,
 	AU1000_UART0_INT	= AU1000_FIRST_INT,
 	AU1000_UART1_INT,				/* au1000 */
 	AU1000_UART2_INT,				/* au1000 */
@@ -605,7 +605,7 @@ enum soc_au1000_ints {
 /* Au1500 */
 #ifdef CONFIG_SOC_AU1500
 enum soc_au1500_ints {
-	AU1500_FIRST_INT	= MIPS_CPU_IRQ_BASE,
+	AU1500_FIRST_INT	= MIPS_CPU_IRQ_BASE + 8,
 	AU1500_UART0_INT	= AU1500_FIRST_INT,
 	AU1000_PCI_INTA,				/* au1500 */
 	AU1000_PCI_INTB,				/* au1500 */
@@ -686,7 +686,7 @@ enum soc_au1500_ints {
 /* Au1100 */
 #ifdef CONFIG_SOC_AU1100
 enum soc_au1100_ints {
-	AU1100_FIRST_INT	= MIPS_CPU_IRQ_BASE,
+	AU1100_FIRST_INT	= MIPS_CPU_IRQ_BASE + 8,
 	AU1100_UART0_INT,
 	AU1100_UART1_INT,
 	AU1100_SD_INT,
@@ -761,7 +761,7 @@ enum soc_au1100_ints {
 
 #ifdef CONFIG_SOC_AU1550
 enum soc_au1550_ints {
-	AU1550_FIRST_INT	= MIPS_CPU_IRQ_BASE,
+	AU1550_FIRST_INT	= MIPS_CPU_IRQ_BASE + 8,
 	AU1550_UART0_INT	= AU1550_FIRST_INT,
 	AU1550_PCI_INTA,
 	AU1550_PCI_INTB,
@@ -851,7 +851,7 @@ enum soc_au1550_ints {
 
 #ifdef CONFIG_SOC_AU1200
 enum soc_au1200_ints {
-	AU1200_FIRST_INT	= MIPS_CPU_IRQ_BASE,
+	AU1200_FIRST_INT	= MIPS_CPU_IRQ_BASE + 8,
 	AU1200_UART0_INT	= AU1200_FIRST_INT,
 	AU1200_SWT_INT,
 	AU1200_SD_INT,
@@ -948,11 +948,12 @@ enum soc_au1200_ints {
 
 #endif /* CONFIG_SOC_AU1200 */
 
-#define AU1000_INTC0_INT_BASE	(MIPS_CPU_IRQ_BASE + 0)
-#define AU1000_INTC0_INT_LAST	(MIPS_CPU_IRQ_BASE + 31)
-#define AU1000_INTC1_INT_BASE	(MIPS_CPU_IRQ_BASE + 32)
-#define AU1000_INTC1_INT_LAST	(MIPS_CPU_IRQ_BASE + 63)
-#define AU1000_MAX_INTR		(MIPS_CPU_IRQ_BASE + 63)
+#define AU1000_INTC0_INT_BASE	(MIPS_CPU_IRQ_BASE + 8)
+#define AU1000_INTC0_INT_LAST	(AU1000_INTC0_INT_BASE + 31)
+#define AU1000_INTC1_INT_BASE	(AU1000_INTC0_INT_BASE + 32)
+#define AU1000_INTC1_INT_LAST	(AU1000_INTC1_INT_BASE + 31)
+
+#define AU1000_MAX_INTR 	AU1000_INTC1_INT_LAST
 #define INTX			0xFF			/* not valid */
 
 /* Programmable Counters 0 and 1 */

^ permalink raw reply

* [PATCH 1/2] Alchemy: replace ffs() with __ffs()
From: Sergei Shtylyov @ 2007-12-05 16:08 UTC (permalink / raw)
  To: ralf; +Cc: linux-mips

Fix havoc wrought by commit 56f621c7f6f735311eed3f36858b402013023c18 -- au_ffs()
and ffs() are equivalent, that patch should have just replaced one with another.
Now replace ffs() with __ffs() which returns an unbiased bit number.

 arch/mips/au1000/common/dbdma.c  |    2 +-
 arch/mips/au1000/common/irq.c    |    8 ++++----
 arch/mips/au1000/pb1200/irqmap.c |    2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

Index: linux-2.6/arch/mips/au1000/common/dbdma.c
===================================================================
--- linux-2.6.orig/arch/mips/au1000/common/dbdma.c
+++ linux-2.6/arch/mips/au1000/common/dbdma.c
@@ -859,7 +859,7 @@ dbdma_interrupt(int irq, void *dev_id)
 
 	intstat = dbdma_gptr->ddma_intstat;
 	au_sync();
-	chan_index = ffs(intstat);
+	chan_index = __ffs(intstat);
 
 	ctp = chan_tab_ptr[chan_index];
 	cp = ctp->chan_ptr;
Index: linux-2.6/arch/mips/au1000/common/irq.c
===================================================================
--- linux-2.6.orig/arch/mips/au1000/common/irq.c
+++ linux-2.6/arch/mips/au1000/common/irq.c
@@ -462,7 +462,7 @@ static void intc0_req0_irqdispatch(void)
 		return;
 	}
 #endif
-	bit = ffs(intc0_req0);
+	bit = __ffs(intc0_req0);
 	intc0_req0 &= ~(1 << bit);
 	do_IRQ(MIPS_CPU_IRQ_BASE + bit);
 }
@@ -478,7 +478,7 @@ static void intc0_req1_irqdispatch(void)
 	if (!intc0_req1)
 		return;
 
-	bit = ffs(intc0_req1);
+	bit = __ffs(intc0_req1);
 	intc0_req1 &= ~(1 << bit);
 	do_IRQ(bit);
 }
@@ -498,7 +498,7 @@ static void intc1_req0_irqdispatch(void)
 	if (!intc1_req0)
 		return;
 
-	bit = ffs(intc1_req0);
+	bit = __ffs(intc1_req0);
 	intc1_req0 &= ~(1 << bit);
 	do_IRQ(MIPS_CPU_IRQ_BASE + 32 + bit);
 }
@@ -514,7 +514,7 @@ static void intc1_req1_irqdispatch(void)
 	if (!intc1_req1)
 		return;
 
-	bit = ffs(intc1_req1);
+	bit = __ffs(intc1_req1);
 	intc1_req1 &= ~(1 << bit);
 	do_IRQ(MIPS_CPU_IRQ_BASE + 32 + bit);
 }
Index: linux-2.6/arch/mips/au1000/pb1200/irqmap.c
===================================================================
--- linux-2.6.orig/arch/mips/au1000/pb1200/irqmap.c
+++ linux-2.6/arch/mips/au1000/pb1200/irqmap.c
@@ -74,7 +74,7 @@ irqreturn_t pb1200_cascade_handler( int 
 	bcsr->int_status = bisr;
 	for( ; bisr; bisr &= (bisr-1) )
 	{
-		extirq_nr = PB1200_INT_BEGIN + ffs(bisr);
+		extirq_nr = PB1200_INT_BEGIN + __ffs(bisr);
 		/* Ack and dispatch IRQ */
 		do_IRQ(extirq_nr);
 	}

^ permalink raw reply

* [PATCH 0/2] Alchemy: fix interrupt routing
From: Sergei Shtylyov @ 2007-12-05 16:08 UTC (permalink / raw)
  To: ralf; +Cc: linux-mips

Hello.

   The two following patches together fix the interrupt routing currently broken
and causing boot failure with such messages:

unexpected IRQ # 8
irq 8, desc: 80406dd0, depth: 1, count: 0, unhandled: 0
->handle_irq():  80157d70, handle_bad_irq+0x0/0x38c
->chip(): 804016d0, 0x804016d0
->action(): 00000000
  IRQ_DISABLED set

   The patches are against the Linus' tree...

WBR, Sergei

^ permalink raw reply

* Re: [UPDATED PATCH] IP28 support
From: Thomas Bogendoerfer @ 2007-12-05  9:39 UTC (permalink / raw)
  To: Kumba; +Cc: Ralf Baechle, linux-mips
In-Reply-To: <4756422D.6070305@gentoo.org>

On Wed, Dec 05, 2007 at 01:16:13AM -0500, Kumba wrote:
> I've been out of it lately -- did the gcc side of things ever make it in, 
> or do we need to go push on that some more?

We need push on that. Looking at 

http://gcc.gnu.org/ml/gcc-patches/2006-04/msg00291.html

there seems to be a missing understanding, why the cache
barriers are needed. I guess the patch could be improved
by pointing directly to the errata section of the R10k
user manual. Or even better copy the text out of the user
manual. That should make clear why this patch is needed.

Peter did you do the copyright assigment ? That's probably
the second part, which needs to be done.

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessary a
good idea.                                                [ RFC1925, 2.3 ]

^ permalink raw reply

* Re: [PATCH] SC26XX: New serial driver for SC2681 uarts
From: Thomas Bogendoerfer @ 2007-12-05  9:25 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, linux-mips, Andy Whitcroft, Alan Cox
In-Reply-To: <20071204192738.54e79a97.akpm@linux-foundation.org>

On Tue, Dec 04, 2007 at 07:27:38PM -0800, Andrew Morton wrote:
> grumble.
> 
> These:
> 
> > +#define READ_SC(p, r)        readb((p)->membase + RD_##r)
> > +#define WRITE_SC(p, r, v)    writeb((v), (p)->membase + WR_##r)
> 
> and these:
> 
> > +#define READ_SC_PORT(p, r)     read_sc_port(p, RD_PORT_##r)
> > +#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
> 
> really don't need to exist.  All they do is make the code harder to read.

but they make the code safer. The chip has common register and port
registers, which are randomly splattered over the address range. And
some of them are read only, some write only. Read only and Write
only register live at the same register offset and their function
usually doesn't have anything in common. By using these macros I'll
get compile errors when doing a READ_SC from a write only register
and vice versa. I will also get compile errors, if I try to access a
common register via READ_SC_PORT/WRITE_SC_PORT. 

If there is a better way to get more readable code for you and
the safety I'd like, just tell me.

> Think of the poor reader who sees this:
> 
> 		status = READ_SC_PORT(port, SR);
> 
> and then goes madly searching for "SR".

which he then finds by this name in the data sheet. All the register
names are named as close to the datasheet as possible. And I consider
consulting datasheets when looking at drivers a pretty good idea.

> Code is written once and is read a thousand times.  Please optimise for
> reading.

it's no big deal to change that, but is getting bitten by stupid chips
worth it ? I'd prefer to get a compile error than debugging a runtime
error.

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessary a
good idea.                                                [ RFC1925, 2.3 ]

^ permalink raw reply

* Re: [UPDATED PATCH] IP28 support
From: Kumba @ 2007-12-05  6:16 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Thomas Bogendoerfer, linux-mips
In-Reply-To: <20071129130130.GA14655@linux-mips.org>

Ralf Baechle wrote:
> On Thu, Nov 29, 2007 at 10:54:42AM +0100, Thomas Bogendoerfer wrote:
> 
>> Add support for SGI IP28 machines (Indigo 2 with R10k CPUs)
>> This work is mainly based on Peter Fuersts work.
> 
> Queued for 2.6.25.  There clearly is work remaining to be done but the
> code is now in an acceptable shape and the best way to push it forward
> is integrating it.  Thanks for all the work and especially to Peter
> Fürst for the initial heavyweight lifting!
> 
>   Ralf

Seconded.  Peter is made of Win.

I've been out of it lately -- did the gcc side of things ever make it in, or do 
we need to go push on that some more?


--Kumba

-- 
Gentoo/MIPS Team Lead

"Such is oft the course of deeds that move the wheels of the world: small hands 
do them because they must, while the eyes of the great are elsewhere."  --Elrond

^ permalink raw reply

* Re: [PATCH] Add support for SB1 hardware watchdog.
From: Kaz Kylheku @ 2007-12-05  3:50 UTC (permalink / raw)
  To: linux-mips
In-Reply-To: <20071203230828.GA17960@linux-mips.org>

On Mon, Dec 03, 2007, Ralf Baechle wrote:
> On Mon, Dec 03, 2007 at 10:17:04AM -0800, Andrew Sharp wrote:
>
>> +   Watchdog driver for the built in watchdog hardware in Sibyte
>> +   SoC processors.  There are apparently two watchdog timers
>> +   on such processors; this driver supports only the first one,
>> +   because currently Linux only supports exporting one watchdog
>> +   to userspace.
>
> And even four watchdogs in the BCM1480.
>
> You'd think they'd trust their hardware more than that ;-)

Maybe the dogs can be daisy-chained together. After all, who watches the 
watcher? And who watches him?

Did I ever tell you how lucky you are?

http://www.drseussart.com/beewatcher.html

http://www.webpages.ttu.edu/sbaugues/fin4323/dr.seuss.pdf

^ permalink raw reply

* Re: [PATCH] Add support for SB1 hardware watchdog.
From: Kaz Kylheku @ 2007-12-05  3:41 UTC (permalink / raw)
  To: linux-mips
In-Reply-To: <20071203230828.GA17960@linux-mips.org>

On Mon, Dec 03, 2007, Ralf Baechle wrote:
> On Mon, Dec 03, 2007 at 10:17:04AM -0800, Andrew Sharp wrote:
>
>> +   Watchdog driver for the built in watchdog hardware in Sibyte
>> +   SoC processors.  There are apparently two watchdog timers
>> +   on such processors; this driver supports only the first one,
>> +   because currently Linux only supports exporting one watchdog
>> +   to userspace.
>
> And even four watchdogs in the BCM1480.
>
> You'd think they'd trust their hardware more than that ;-)

Maybe the dogs can be daisy-chained together. After all, who watches the 
watcher? And who watches him?

Did I ever tell you how lucky you are?

http://www.drseussart.com/beewatcher.html

http://www.webpages.ttu.edu/sbaugues/fin4323/dr.seuss.pdf

^ permalink raw reply

* Re: [PATCH] Add support for SB1 hardware watchdog.
From: Kaz Kylheku @ 2007-12-05  3:50 UTC (permalink / raw)
  To: linux-mips
In-Reply-To: <20071203230828.GA17960@linux-mips.org>

On Mon, Dec 03, 2007, Ralf Baechle wrote:
> On Mon, Dec 03, 2007 at 10:17:04AM -0800, Andrew Sharp wrote:
>
>> +   Watchdog driver for the built in watchdog hardware in Sibyte
>> +   SoC processors.  There are apparently two watchdog timers
>> +   on such processors; this driver supports only the first one,
>> +   because currently Linux only supports exporting one watchdog
>> +   to userspace.
>
> And even four watchdogs in the BCM1480.
>
> You'd think they'd trust their hardware more than that ;-)

Maybe the dogs can be daisy-chained together. After all, who watches the 
watcher? And who watches him?

Did I ever tell you how lucky you are?

http://www.drseussart.com/beewatcher.html

http://www.webpages.ttu.edu/sbaugues/fin4323/dr.seuss.pdf

^ permalink raw reply

* Re: [PATCH] Add support for SB1 hardware watchdog.
From: Kaz Kylheku @ 2007-12-05  3:41 UTC (permalink / raw)
  To: linux-mips
In-Reply-To: <20071203230828.GA17960@linux-mips.org>

On Mon, Dec 03, 2007, Ralf Baechle wrote:
> On Mon, Dec 03, 2007 at 10:17:04AM -0800, Andrew Sharp wrote:
>
>> +   Watchdog driver for the built in watchdog hardware in Sibyte
>> +   SoC processors.  There are apparently two watchdog timers
>> +   on such processors; this driver supports only the first one,
>> +   because currently Linux only supports exporting one watchdog
>> +   to userspace.
>
> And even four watchdogs in the BCM1480.
>
> You'd think they'd trust their hardware more than that ;-)

Maybe the dogs can be daisy-chained together. After all, who watches the 
watcher? And who watches him?

Did I ever tell you how lucky you are?

http://www.drseussart.com/beewatcher.html

http://www.webpages.ttu.edu/sbaugues/fin4323/dr.seuss.pdf

^ permalink raw reply

* Re: [PATCH] SC26XX: New serial driver for SC2681 uarts
From: Andrew Morton @ 2007-12-05  3:27 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-kernel, linux-mips, Andy Whitcroft, Alan Cox
In-Reply-To: <20071204234112.GA12352@alpha.franken.de>

On Wed, 5 Dec 2007 00:41:12 +0100 tsbogend@alpha.franken.de (Thomas Bogendoerfer) wrote:

> On Mon, Dec 03, 2007 at 03:53:17PM -0800, Andrew Morton wrote:
> > On Sun,  2 Dec 2007 20:43:46 +0100 (CET)
> > Thomas Bogendoerfer <tsbogend@alpha.franken.de> wrote:
> > 
> > > New serial driver for SC2681/SC2691 uarts. Older SNI RM400 machines are
> > > using these chips for onboard serial ports.
> > > 
> > 
> > Little things...
> 
> here is an updated version.
> 
> Changes:
>    - use container_of
>    - remove not needed locking
>    - remove inlines
>    - fix macros with double argument reference
> 
> Thomas.
> --
> 
> New serial driver for SC2681/SC2691 uarts. Older SNI RM400 machines are
> using these chips for onboard serial ports.
> 

grumble.

These:

> +#define READ_SC(p, r)        readb((p)->membase + RD_##r)
> +#define WRITE_SC(p, r, v)    writeb((v), (p)->membase + WR_##r)

and these:

> +#define READ_SC_PORT(p, r)     read_sc_port(p, RD_PORT_##r)
> +#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)

really don't need to exist.  All they do is make the code harder to read.

Think of the poor reader who sees this:

		status = READ_SC_PORT(port, SR);

and then goes madly searching for "SR".  After a while, our confused reader
might think to go look at the definition of READ_SC_PORT, after which our
reader will emulate a C preprocessor in wetware and will eventually construct
then hunt down RD_PORT_SR and will then hopefully remember what the heck he was
trying to do in the first place.

This sucks.

Code is written once and is read a thousand times.  Please optimise for
reading.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox