* RE: Floating point math in kernel interrupt -- am I doing thisright?(repost)
From: Josu Onandia @ 2006-02-07 9:44 UTC (permalink / raw)
To: linuxppc-embedded
Hi,
In the RTAI scheduler there are routines (save_fpenv, restore_fpenv) =
that are very similar to your functions. I'd suggest to look in more =
detail if there are any subtle difference.
I think also that Sylvain can be right about the stack, so it could be a =
good idea to place saved_fpr in static storage, not in the stack.
My 2 cents
Josu
-----Mensaje original-----
De: linuxppc-embedded-bounces@ozlabs.org
[mailto:linuxppc-embedded-bounces@ozlabs.org]En nombre de Joyeau Sylvain
Enviado el: martes, 07 de febrero de 2006 8:20
Para: Jeremy Friesner
CC: linuxppc-embedded@ozlabs.org
Asunto: RE: Floating point math in kernel interrupt -- am I doing
thisright?(repost)
Jeremy,
What about kernel stack overflow ?
You mention that the occurrence of the crash is proportional to the =
amount of embraced code, which generally use more stack space too... but =
you aren't very accurate about the call context of your DoMix() =
function: it can be called depth enough to tickle the interrupted thread =
control block and issue indirect spurious behavior is userland.
Hope this help.
--
sj
> -----Original Message-----
> From: linuxppc-embedded-bounces@ozlabs.org =
[mailto:linuxppc-embedded-bounces@ozlabs.org] On Behalf Of Jeremy =
Friesner
> Sent: lundi 6 f=E9vrier 2006 17:55
> To: Dan Malek
> Cc: linuxppc-embedded@ozlabs.org
> Subject: Re: Floating point math in kernel interrupt -- am I doing =
this right?(repost)
>=20
> >
> > On Feb 5, 2006, at 9:29 PM, Jeremy Friesner wrote:
> >
> > > .... and the mixing is done inside an
> > > interrupt routine that runs 6000 times per second, and calculates =
8
> > > samples
> > > per interrupt.
> >
> > Bad news. No Floating Point allowed in the kernel.
>=20
> I'm aware of that rule, and also why -- because the Linux kernel =
doesn't want to have to save and restore the state of the
> floating point registers on every context switch. I'm also aware that =
it is nonetheless possible to use floating point in
> the kernel if you are careful to manually save and restore the proper =
state yourself, and that in fact floating point is
> sometimes used in the kernel as a means of doing 64-bit writes, as =
mentioned here:
>=20
> http://www.tldp.org/LDP/cpg/html/x295.html
>=20
> So it seems to me that it is possible to do floating point in the =
kernel, if you are careful to save and restore the proper
> context/state before and afterwards. But if it isn't, can you explain =
to me why it can't be made to work?
>=20
> > > In order to do the necessary floating point math, without =
corrupting
> > > the state
> > > of any other processes that might be using the FPU, the interrupt
> > > routine
> > > first saves the state of the FPU registers to the stack, then does =
the
> > > math,
> > > then restores FPU registers again, before returning.
> >
> > Not on 82xx. All floating point is done in hardware.
>=20
> Right; it is the hardware registers' state that I am saving to the =
stack, and then restoring afterwards.
>=20
> > > So my question is, is there some minor detail that my
> > > FPU-state-save/restore
> > > code is missing, that would cause these sort of symptoms?
> >
> > Just get all of this out of the kernel. If you used the standard =
ALSA
> > drivers and framework, lots of mixing features are available to you.
> > If you need some custom mixing, just write a plug-in to do it.
> > Your data rates are so low they don't justify making any hacks
> > like this.
>=20
> I suppose that is an option, but I'd rather understand why my hack =
isn't working before I give up and redesign my
> application, which is already working the way I want it to, 99.9999% =
of the time.
>=20
> Jeremy
>=20
>=20
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* RE: Floating point math in kernel interrupt -- am I doing this right?(repost)
From: Joyeau Sylvain @ 2006-02-07 7:20 UTC (permalink / raw)
To: Jeremy Friesner; +Cc: linuxppc-embedded
Jeremy,
What about kernel stack overflow ?
You mention that the occurrence of the crash is proportional to the =
amount of embraced code, which generally use more stack space too... but =
you aren't very accurate about the call context of your DoMix() =
function: it can be called depth enough to tickle the interrupted thread =
control block and issue indirect spurious behavior is userland.
Hope this help.
--
sj
> -----Original Message-----
> From: linuxppc-embedded-bounces@ozlabs.org =
[mailto:linuxppc-embedded-bounces@ozlabs.org] On Behalf Of Jeremy =
Friesner
> Sent: lundi 6 f=E9vrier 2006 17:55
> To: Dan Malek
> Cc: linuxppc-embedded@ozlabs.org
> Subject: Re: Floating point math in kernel interrupt -- am I doing =
this right?(repost)
>=20
> >
> > On Feb 5, 2006, at 9:29 PM, Jeremy Friesner wrote:
> >
> > > .... and the mixing is done inside an
> > > interrupt routine that runs 6000 times per second, and calculates =
8
> > > samples
> > > per interrupt.
> >
> > Bad news. No Floating Point allowed in the kernel.
>=20
> I'm aware of that rule, and also why -- because the Linux kernel =
doesn't want to have to save and restore the state of the
> floating point registers on every context switch. I'm also aware that =
it is nonetheless possible to use floating point in
> the kernel if you are careful to manually save and restore the proper =
state yourself, and that in fact floating point is
> sometimes used in the kernel as a means of doing 64-bit writes, as =
mentioned here:
>=20
> http://www.tldp.org/LDP/cpg/html/x295.html
>=20
> So it seems to me that it is possible to do floating point in the =
kernel, if you are careful to save and restore the proper
> context/state before and afterwards. But if it isn't, can you explain =
to me why it can't be made to work?
>=20
> > > In order to do the necessary floating point math, without =
corrupting
> > > the state
> > > of any other processes that might be using the FPU, the interrupt
> > > routine
> > > first saves the state of the FPU registers to the stack, then does =
the
> > > math,
> > > then restores FPU registers again, before returning.
> >
> > Not on 82xx. All floating point is done in hardware.
>=20
> Right; it is the hardware registers' state that I am saving to the =
stack, and then restoring afterwards.
>=20
> > > So my question is, is there some minor detail that my
> > > FPU-state-save/restore
> > > code is missing, that would cause these sort of symptoms?
> >
> > Just get all of this out of the kernel. If you used the standard =
ALSA
> > drivers and framework, lots of mixing features are available to you.
> > If you need some custom mixing, just write a plug-in to do it.
> > Your data rates are so low they don't justify making any hacks
> > like this.
>=20
> I suppose that is an option, but I'd rather understand why my hack =
isn't working before I give up and redesign my
> application, which is already working the way I want it to, 99.9999% =
of the time.
>=20
> Jeremy
>=20
>=20
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* Re: merge these lists?
From: Michael Ellerman @ 2006-02-07 4:29 UTC (permalink / raw)
To: linuxppc64-dev; +Cc: linuxppc-dev
In-Reply-To: <20060207041243.GC7626@pb15.lixom.net>
[-- Attachment #1: Type: text/plain, Size: 1291 bytes --]
On Tue, 7 Feb 2006 15:12, Olof Johansson wrote:
> On Tue, Feb 07, 2006 at 02:45:45PM +1100, Jeremy Kerr wrote:
> > Paul,
> >
> > > If we do this, we would set up the new list with the union of the
> > > subscribers of the old lists, and make emails sent to linuxppc-dev
> > > and linuxppc64-dev go to the new list, so it should be painless.
> > >
> > > Thoughts? Comments? Objections?
> >
> > How about the patchwork lists? Should I look at merging those too?
>
> I get a feeling that our maintainers might not be using them much any
> more (most patches since August of last year are still "New"), but I
> find it convenient to search for a patch that you know has gone by but
> can't find in your list mbox.
>
> I would appreciate either a merge, or a new archive started for the new
> list. It's useful.
And while Jk has nothing else to do .. I'd like to be able to managed my own
patches, ie. set them as obsolete etc etc.
Oh and yeah I think we should merge the lists :D
cheers
--
Michael Ellerman
IBM OzLabs
email: michael:ellerman.id.au
inmsg: mpe:jabber.org
wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)
We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: merge these lists?
From: Olof Johansson @ 2006-02-07 4:12 UTC (permalink / raw)
To: Jeremy Kerr; +Cc: linuxppc64-dev, linuxppc-dev
In-Reply-To: <200602071445.45805.jk@ozlabs.org>
On Tue, Feb 07, 2006 at 02:45:45PM +1100, Jeremy Kerr wrote:
> Paul,
>
> > If we do this, we would set up the new list with the union of the
> > subscribers of the old lists, and make emails sent to linuxppc-dev
> > and linuxppc64-dev go to the new list, so it should be painless.
> >
> > Thoughts? Comments? Objections?
>
> How about the patchwork lists? Should I look at merging those too?
I get a feeling that our maintainers might not be using them much any
more (most patches since August of last year are still "New"), but I
find it convenient to search for a patch that you know has gone by but
can't find in your list mbox.
I would appreciate either a merge, or a new archive started for the new
list. It's useful.
-Olof
^ permalink raw reply
* Re: merge these lists?
From: Jeremy Kerr @ 2006-02-07 3:45 UTC (permalink / raw)
To: linuxppc64-dev, linuxppc-dev
In-Reply-To: <17384.5875.790692.127762@cargo.ozlabs.ibm.com>
Paul,
> If we do this, we would set up the new list with the union of the
> subscribers of the old lists, and make emails sent to linuxppc-dev
> and linuxppc64-dev go to the new list, so it should be painless.
>
> Thoughts? Comments? Objections?
How about the patchwork lists? Should I look at merging those too?
Jeremy
^ permalink raw reply
* merge these lists?
From: Paul Mackerras @ 2006-02-07 3:41 UTC (permalink / raw)
To: linuxppc-dev, linuxppc64-dev
A lot of messages seem to get cross-posted to both linuxppc-dev and
linuxppc64-dev these days, since we are all working in the one tree.
Rather than having to cross-post, I propose that we create a single
powerpc-dev@ozlabs.org list to replace linuxppc-dev and
linuxppc64-dev. (The linuxppc-embedded list would continue as at
present.)
If we do this, we would set up the new list with the union of the
subscribers of the old lists, and make emails sent to linuxppc-dev and
linuxppc64-dev go to the new list, so it should be painless.
Thoughts? Comments? Objections?
Paul.
^ permalink raw reply
* Common Flash Interface v1.4 and MTD support in Linux-2.4.4 kernel
From: David Antliff @ 2006-02-07 3:33 UTC (permalink / raw)
To: linuxppc-embedded
Hello,
Just to be clear, this email is related to work that I do for a
commercial enterprise, however I am writing on behalf of myself.
I am working on an MPC852 embedded platform based on the Denx
Linux-2.4.4 port.
We have an existing device with a fixed-flash (AMD-type) conforming to
CFI (Common Flash Interface) version 1.2. Linux-2.4.4 supports this
device when used by the Memory Tech Device Driver (MTD). This device has
a single region ('plane'?) or at least constant geometry across the
device. MTD in 2.4.4 has no problems dividing this up into a bunch of
block devices (partitions for read-only filesystems).
A newer version has a different flash chip - an Intel P30 flash with
multiple regions - it has two types of geometries as it is configured
for 'boot' operation. It also conforms to CFI version 1.4. Unfortunately
the Linux-2.4.4 MTD driver rejects this as unsupported based on CFI
version and hard-coding it in "kinda" works - the partition devices are
readable but the driver complains bitterly about non-alignment with
erase blocks. I suspect the driver is picking up parameters from the
first region (which covers the first set of blocks) and trying to use
this across the device. One thing I don't understand yet - as the first
region uses block sizes that are an integer division of those in the
second region I'm not sure why the boundaries don't align when I am
using the 2nd-region block size to define the partition boundaries.
What I am looking for is some advice please - what do you think is the
best course of action in this situation?
There will be others but so far I am considering:
1. back-port the CFI code from a newer 2.4 kernel to support CFI v1.4.
- does anybody know the state of MTD in later versions? What would be a
good version to source from?
2. integrate code found here and try and understand how it works:
http://lists.infradead.org/pipermail/linux-mtd/2001-November/003645.html
3. unfortunately upgrading the entire kernel is not an option at this
stage, unless absolutely necessary.
What would you suggest? Yes, I am happy for a 'quick fix' but if there
isn't one or it's too risky I am willing to invest the time in doing it
right.
Thank you,
David Antliff
Stratex Networks Ltd.
New Zealand
^ permalink raw reply
* List etiquette
From: David Antliff @ 2006-02-07 2:59 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 594 bytes --]
Hello,
I'm a new subscriber to this list and looking to ask a specific question
shortly. However I would like to bring two things up based on this page:
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
1. The list rules and posting guidelines URLs are out of service:
- http://lists.linuxppc.org/rules.html
- http://lists.linuxppc.org/guidelines.html
2. There is a recommendation to look for answers to questions in the
list archives. There does not seem to be any way to search these, except
with Google site: syntax. Am I missing something here?
Regards,
David
[-- Attachment #2: Type: text/html, Size: 1207 bytes --]
^ permalink raw reply
* [PATCH] powerpc: wire up the *at system calls
From: Stephen Rothwell @ 2006-02-06 23:59 UTC (permalink / raw)
To: paulus; +Cc: Andrew Morton, LKML, ppc-dev, Linus, ppc64-dev
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
arch/powerpc/kernel/systbl.S | 13 +++++++++++++
include/asm-powerpc/unistd.h | 15 ++++++++++++++-
2 files changed, 27 insertions(+), 1 deletions(-)
This depend on the patch that creates all the compat wrappers.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
d02d8208813d8cae2c814a85734a1a31fed2f3ac
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S
index 007b15e..fe16d9c 100644
--- a/arch/powerpc/kernel/systbl.S
+++ b/arch/powerpc/kernel/systbl.S
@@ -323,3 +323,16 @@ SYSCALL(spu_run)
SYSCALL(spu_create)
COMPAT_SYS(pselect6)
COMPAT_SYS(ppoll)
+COMPAT_SYS(openat)
+COMPAT_SYS(mkdirat)
+COMPAT_SYS(mknodat)
+COMPAT_SYS(fchownat)
+COMPAT_SYS(futimesat)
+COMPAT_SYS(newfstatat)
+COMPAT_SYS(unlinkat)
+COMPAT_SYS(renameat)
+COMPAT_SYS(linkat)
+COMPAT_SYS(symlinkat)
+COMPAT_SYS(readlinkat)
+COMPAT_SYS(fchmodat)
+COMPAT_SYS(faccessat)
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index a40cdff..d05b85e 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -300,8 +300,21 @@
#define __NR_spu_create 279
#define __NR_pselect6 280
#define __NR_ppoll 281
+#define __NR_openat 282
+#define __NR_mkdirat 283
+#define __NR_mknodat 284
+#define __NR_fchownat 285
+#define __NR_futimesat 286
+#define __NR_newfstatat 287
+#define __NR_unlinkat 288
+#define __NR_renameat 289
+#define __NR_linkat 290
+#define __NR_symlinkat 291
+#define __NR_readlinkat 292
+#define __NR_fchmodat 293
+#define __NR_faccessat 294
-#define __NR_syscalls 282
+#define __NR_syscalls 295
#ifdef __KERNEL__
#define __NR__exit __NR_exit
--
1.1.5
^ permalink raw reply related
* [PATCH] documentation: add bus-frequency property to SOC node
From: Becky Bruce @ 2006-02-06 20:26 UTC (permalink / raw)
To: linuxppc-dev, linuxppc64-dev
Updated SOC node definition in documentation to include bus-frequency
property. Also extended mdio example to match specification.
Signed-off-by: Becky Bruce <becky.bruce@freescale.com>
Signed-off-by: Kumar Gala <galak@gate.crashing.org>
---
commit 3441bf59c7e1dc3823f9be57838a2536c78f6f8f
tree 2901a0e19418f1fe904ff0d041c630b3af048961
parent 66c490c9b00c52cd0f1e088ad689c9148e46f49e
author Becky Bruce <becky.bruce@freescale.com> Thu, 02 Feb 2006 15:41:11 -0600
committer Becky Bruce <becky.bruce@freescale.com> Thu, 02 Feb 2006 15:41:11 -0600
Documentation/powerpc/booting-without-of.txt | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 1284498..54e5f9b 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -880,6 +880,10 @@ address which can extend beyond that lim
- device_type : Should be "soc"
- ranges : Should be defined as specified in 1) to describe the
translation of SOC addresses for memory mapped SOC registers.
+ - bus-frequency: Contains the bus frequency for the SOC node.
+ Typically, the value of this field is filled in by the boot
+ loader.
+
Recommended properties:
@@ -919,6 +923,7 @@ SOC.
device_type = "soc";
ranges = <00000000 e0000000 00100000>
reg = <e0000000 00003000>;
+ bus-frequency = <0>;
}
@@ -1170,6 +1175,8 @@ platforms are moved over to use the flat
mdio@24520 {
reg = <24520 20>;
+ device_type = "mdio";
+ compatible = "gianfar";
ethernet-phy@0 {
......
@@ -1317,6 +1324,7 @@ not necessary as they are usually the sa
device_type = "soc";
ranges = <00000000 e0000000 00100000>
reg = <e0000000 00003000>;
+ bus-frequency = <0>;
mdio@24520 {
reg = <24520 20>;
^ permalink raw reply related
* Re: Yosemite/440EP PLB4 vs PLB3 DMA to PCI issue
From: David Hawkins @ 2006-02-06 19:09 UTC (permalink / raw)
To: Stefan Roese; +Cc: linuxppc-embedded
In-Reply-To: <200602061931.25370.sr@denx.de>
Hi Stefan,
> I never used DMA on 440EP/GP till now so I just noticed the two different
> PLB's and their DMA controllers. Never seen this on any 4xx PPC so far. I
> suspect that the PLB4 is integrated mainly because of the USB interface.
That sounds about right. In my app I won't be using USB, and since the
PLB4 DMA controller has larger DMA buffers, I thought it might have an
edge over the PLB3 controller.
> What version of the user manual are you referring to? Could you please give
> the pages for the current manual (Revision 1.18).
Oh, sorry, I was looking at the version 1.14 manual. I've just
downloaded the 1.18 manual. Whoa! The 1.14 manual has 1696 pages,
whereas the 1.18 manual has only 794 - I hope that means things
have got simpler ;)
(nope, looks like the 440 core just got moved into another document)
Anyways, here are the v1.18 page references;
v1.18 p365-6 has the PLB-to-PCI Transaction Handling section
showing the cases where MRL and MRM will be used.
v1.18 p407 has the PCI Memory to SDRAM DMA transfer section
with comments and forward references to the timing
diagram pages.
>>(I hope you had a nice vacation Stefan!)
>
> Thanks. Very nice. One week of sunshine in the snow. :-)
I hope that means you got some nice snowboarding or skiing!
We have a fun mountain just up the road;
http://www.mammothmountain.com/
Feel free to come and visit if you are in California anytime!
Cheers
Dave
^ permalink raw reply
* Re: Yosemite/440EP PLB4 vs PLB3 DMA to PCI issue
From: Stefan Roese @ 2006-02-06 18:31 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <43E68E85.3080100@ovro.caltech.edu>
Hi David,
I never used DMA on 440EP/GP till now so I just noticed the two different
PLB's and their DMA controllers. Never seen this on any 4xx PPC so far. I
suspect that the PLB4 is integrated mainly because of the USB interface.
On Monday 06 February 2006 00:47, David Hawkins wrote:
> I took a look at the 440EP user manual, and I haven't been
> able to explain the PLB4 DMA controller observations.
>
> Here's what I've got so far;
>
> p595: PLB-to-PCI transaction handling
> Shows the two situations where the PCI bridge will
> generate memory-read-line (MRL) and memory-read-multiple (MRM)
What version of the user manual are you referring to? Could you please give
the pages for the current manual (Revision 1.18).
<snip>
> (I hope you had a nice vacation Stefan!)
Thanks. Very nice. One week of sunshine in the snow. :-)
Ciao,
Stefan
^ permalink raw reply
* Re: Floating point math in kernel interrupt -- am I doing this right? (repost)
From: Jeremy Friesner @ 2006-02-06 16:55 UTC (permalink / raw)
To: Dan Malek; +Cc: linuxppc-embedded
In-Reply-To: <3c13d56389dfcf9f45ca87167295e933@embeddedalley.com>
>
> On Feb 5, 2006, at 9:29 PM, Jeremy Friesner wrote:
>
> > .... and the mixing is done inside an
> > interrupt routine that runs 6000 times per second, and calculates 8
> > samples
> > per interrupt.
>
> Bad news. No Floating Point allowed in the kernel.
I'm aware of that rule, and also why -- because the Linux kernel doesn't want to have to save and restore the state of the floating point registers on every context switch. I'm also aware that it is nonetheless possible to use floating point in the kernel if you are careful to manually save and restore the proper state yourself, and that in fact floating point is sometimes used in the kernel as a means of doing 64-bit writes, as mentioned here:
http://www.tldp.org/LDP/cpg/html/x295.html
So it seems to me that it is possible to do floating point in the kernel, if you are careful to save and restore the proper context/state before and afterwards. But if it isn't, can you explain to me why it can't be made to work=3F
> > In order to do the necessary floating point math, without corrupting
> > the state
> > of any other processes that might be using the FPU, the interrupt
> > routine
> > first saves the state of the FPU registers to the stack, then does the
> > math,
> > then restores FPU registers again, before returning.
>
> Not on 82xx. All floating point is done in hardware.
Right; it is the hardware registers' state that I am saving to the stack, and then restoring afterwards.
> > So my question is, is there some minor detail that my
> > FPU-state-save/restore
> > code is missing, that would cause these sort of symptoms=3F
>
> Just get all of this out of the kernel. If you used the standard ALSA
> drivers and framework, lots of mixing features are available to you.
> If you need some custom mixing, just write a plug-in to do it.
> Your data rates are so low they don't justify making any hacks
> like this.
I suppose that is an option, but I'd rather understand why my hack isn't working before I give up and redesign my application, which is already working the way I want it to, 99.9999% of the time.
Jeremy
^ permalink raw reply
* Re: mv-linux: Problem to implement custom driver interrupt handling
From: Andrei Konovalov @ 2006-02-06 15:14 UTC (permalink / raw)
To: Eckart Göhler; +Cc: linuxppc-embedded
In-Reply-To: <43E74FB2.6010603@ifen.com>
Hi,
In the Linux driver you should not access the interrupt controller directly.
The relevant XIntc_* calls are done by arch/ppc/syslib/xilinx_pic.c code.
E.g. the particular interrupt is unmasked when one calls request_irq().
Few more comments below.
Thanks,
Andrei
Eckart Göhler wrote:
> Hi,
>
> We try to run montavista Linux pro 3.1 on an ml300 like embedded system
> on an Virtex V2-Pro system. The system works fine with UART, Xilinx enet
> driver (booting with Das U-Boot).
> Now we try to implement some custom GPIO driver that must be triggered
> from outside interrupts. Polling for data works fine but the handler for
> HW-timer interrupts does behaves strange.
>
> The relevant Linux driver part that requests the interrupt and starts
> the timer look like below.
>
> Installing such a driver works but
> - No report of driver interrupt called is sent
> - installing the driver results in a system that almost gets stuck and
> has poor response (~sec) till the driver is rmmodded.
>
> Checking the implementation with native Xilinx example timer application
> works fine, provided the Xilinx exception handling is implemented.
>
> Its not clear for me whether on ppc environment something specific must
> be done for custom interrupts, though implementation of
> xilinx_enet/xilinx_uartlite does not hint for something specific.
>
>
> sincerely
>
> eckart goehler
>
>
> -----------------------------------------------------------------(snip)
>
> // driver snippet that reacts on timer interrupts:
>
> // timer\interrupt base addresses, modified by ioremap:
> unsigned long timer_base, interrupt_base;
>
>
> /* interrupt handler: */
> static
> void drv_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
> {
> printk(KERN_INFO DEVICE_NAME "interrupt occurred\n");
Most probably you should clear the interrupt source here.
Otherwise you could get back into the interrupt handler as
soon as you return from it due to the interrupt request still
being active.
> }
>
>
>
> static int __init drv_init_module(void)
> {
>
> interrupt_base = (unsigned long)
> ioremap(XPAR_INTC_BASEADDR,XPAR_INTC_HIGHADDR-XPAR_INTC_BASEADDR);
> timer_base = (unsigned long)
> ioremap(XPAR_TIMER_BASEADDR,XPAR_TIMER_HIGHADDR-XPAR_TIMER_BASEADDR);
>
> // install interrupt handler:
> if (request_irq(DRV_IRQ, commdrv_interrupt_handler,
> 0, DEVICE_NAME, NULL)
> )
You call request_irq() (i.e. unmask this interrupt) too early.
Configure the timer first.
> {
> printk(KERN_INFO DEVICE_NAME ": can¢t get assigned irq %i\n",
> COMM_IRQ
> );
> }
> else { /* enable interrupt */
>
> printk(KERN_INFO DEVICE_NAME ": interrupt installed\n");
>
> /* Start the interrupt controller */
> XIntc_mMasterEnable(interrupt_base);
- must not be used in the driver
> // here: enable timer interrupt:
> /* Set the number of cycles the timer counts before interrupting */
> XTmrCtr_mSetLoadReg(timer_base, 0, TIMER_VALUE * 80000000l);
>
>
> printk(KERN_INFO DEVICE_NAME ": clear timer\n");
>
> /* Reset the timers, and clear interrupts */
> XTmrCtr_mSetControlStatusReg(timer_base, 0, XTC_CSR_INT_OCCURED_MASK
> | XTC_CSR_LOAD_MASK );
>
> printk(KERN_INFO DEVICE_NAME ": enable interrupt\n");
>
> /* Enable timer interrupts in the interrupt controller */
>
> XIntc_mEnableIntr(interrupt_base, DRV_IRQ_MASK);
- must not be used in the driver. Unmasking the interrupt is done inside request_irq().
> //printk(KERN_INFO DEVICE_NAME ": start timer\n");
> /* Start the timers */
> XTmrCtr_mSetControlStatusReg(timer_base, 0, XTC_CSR_ENABLE_TMR_MASK
> | XTC_CSR_ENABLE_INT_MASK
> | XTC_CSR_AUTO_RELOAD_MASK |
> XTC_CSR_DOWN_COUNT_MASK);
>
> }
> }
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* mv-linux: Problem to implement custom driver interrupt handling
From: Eckart Göhler @ 2006-02-06 13:31 UTC (permalink / raw)
To: linuxppc-embedded
Hi,
We try to run montavista Linux pro 3.1 on an ml300 like embedded system
on an Virtex V2-Pro system. The system works fine with UART, Xilinx enet
driver (booting with Das U-Boot).
Now we try to implement some custom GPIO driver that must be triggered
from outside interrupts. Polling for data works fine but the handler for
HW-timer interrupts does behaves strange.
The relevant Linux driver part that requests the interrupt and starts
the timer look like below.
Installing such a driver works but
- No report of driver interrupt called is sent
- installing the driver results in a system that almost gets stuck and
has poor response (~sec) till the driver is rmmodded.
Checking the implementation with native Xilinx example timer application
works fine, provided the Xilinx exception handling is implemented.
Its not clear for me whether on ppc environment something specific must
be done for custom interrupts, though implementation of
xilinx_enet/xilinx_uartlite does not hint for something specific.
sincerely
eckart goehler
-----------------------------------------------------------------(snip)
// driver snippet that reacts on timer interrupts:
// timer\interrupt base addresses, modified by ioremap:
unsigned long timer_base, interrupt_base;
/* interrupt handler: */
static
void drv_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
{
printk(KERN_INFO DEVICE_NAME "interrupt occurred\n");
}
static int __init drv_init_module(void)
{
interrupt_base = (unsigned long)
ioremap(XPAR_INTC_BASEADDR,XPAR_INTC_HIGHADDR-XPAR_INTC_BASEADDR);
timer_base = (unsigned long)
ioremap(XPAR_TIMER_BASEADDR,XPAR_TIMER_HIGHADDR-XPAR_TIMER_BASEADDR);
// install interrupt handler:
if (request_irq(DRV_IRQ, commdrv_interrupt_handler,
0, DEVICE_NAME, NULL)
)
{
printk(KERN_INFO DEVICE_NAME ": can¢t get assigned irq %i\n",
COMM_IRQ
);
}
else { /* enable interrupt */
printk(KERN_INFO DEVICE_NAME ": interrupt installed\n");
/* Start the interrupt controller */
XIntc_mMasterEnable(interrupt_base);
// here: enable timer interrupt:
/* Set the number of cycles the timer counts before interrupting */
XTmrCtr_mSetLoadReg(timer_base, 0, TIMER_VALUE * 80000000l);
printk(KERN_INFO DEVICE_NAME ": clear timer\n");
/* Reset the timers, and clear interrupts */
XTmrCtr_mSetControlStatusReg(timer_base, 0, XTC_CSR_INT_OCCURED_MASK
| XTC_CSR_LOAD_MASK );
printk(KERN_INFO DEVICE_NAME ": enable interrupt\n");
/* Enable timer interrupts in the interrupt controller */
XIntc_mEnableIntr(interrupt_base, DRV_IRQ_MASK);
//printk(KERN_INFO DEVICE_NAME ": start timer\n");
/* Start the timers */
XTmrCtr_mSetControlStatusReg(timer_base, 0, XTC_CSR_ENABLE_TMR_MASK
| XTC_CSR_ENABLE_INT_MASK
| XTC_CSR_AUTO_RELOAD_MASK |
XTC_CSR_DOWN_COUNT_MASK);
}
}
^ permalink raw reply
* RE: Floating point math in kernel interrupt -- am I doing this right?(repost)
From: Fillod Stephane @ 2006-02-06 12:57 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: Jeremy Friesner
Dan Malek wrote:
>> So my question is, is there some minor detail that my=20
>> FPU-state-save/restore
>> code is missing, that would cause these sort of symptoms?
>
>Just get all of this out of the kernel. If you used the standard ALSA
>drivers and framework, lots of mixing features are available to you.
>If you need some custom mixing, just write a plug-in to do it.
>Your data rates are so low they don't justify making any hacks
>like this.
.. or if you *do* need hard-realtime feedback, you may consider
using Xenomai[1] (formerly known as RTAI/Fusion) instead of=20
a hack of the interrupt handler. Thanks to this nice project,=20
FPU on PQ2 works fine in kernel-land, and if need be, it will=20
let you move to user-land seamlessly while keeping the constraints.
Feel free to join the xenomai-help mailing list to get more help=20
on specific questions. Disclaimer: I'm not affiliated with Xenomai,
I am just a happy user :-)
[1] http://xenomai.org
Regards,
--=20
Stephane
^ permalink raw reply
* Re: Floating point math in kernel interrupt -- am I doing this right? (repost)
From: Dan Malek @ 2006-02-06 12:27 UTC (permalink / raw)
To: Jeremy Friesner; +Cc: linuxppc-embedded
In-Reply-To: <200602051829.47824.jaf@lcsaudio.com>
On Feb 5, 2006, at 9:29 PM, Jeremy Friesner wrote:
> .... and the mixing is done inside an
> interrupt routine that runs 6000 times per second, and calculates 8
> samples
> per interrupt.
Bad news. No Floating Point allowed in the kernel.
> In order to do the necessary floating point math, without corrupting
> the state
> of any other processes that might be using the FPU, the interrupt
> routine
> first saves the state of the FPU registers to the stack, then does the
> math,
> then restores FPU registers again, before returning.
Not on 82xx. All floating point is done in hardware.
> .... The oops
> looks like this:
These aren't helpful without some supporting information, like
symbols, or learn to use ksymoops.
> So my question is, is there some minor detail that my
> FPU-state-save/restore
> code is missing, that would cause these sort of symptoms?
Just get all of this out of the kernel. If you used the standard ALSA
drivers and framework, lots of mixing features are available to you.
If you need some custom mixing, just write a plug-in to do it.
Your data rates are so low they don't justify making any hacks
like this.
Thanks.
-- Dan
^ permalink raw reply
* [PATCH] make powerbook_sleep_grackle static
From: Olaf Hering @ 2006-02-06 12:10 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Andrew Morton, linuxppc-dev
powerbook_sleep_grackle is only called inside via-pmu,
from pmu_ioctl()
Signed-off-by: Olaf Hering <olh@suse.de>
---
drivers/macintosh/via-pmu.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
Index: linux-2.6.15/drivers/macintosh/via-pmu.c
===================================================================
--- linux-2.6.15.orig/drivers/macintosh/via-pmu.c
+++ linux-2.6.15/drivers/macintosh/via-pmu.c
@@ -2200,8 +2200,7 @@ pmac_wakeup_devices(void)
#define GRACKLE_NAP (1<<4)
#define GRACKLE_SLEEP (1<<3)
-int
-powerbook_sleep_grackle(void)
+static int powerbook_sleep_grackle(void)
{
unsigned long save_l2cr;
unsigned short pmcr1;
--
short story of a lazy sysadmin:
alias appserv=wotan
^ permalink raw reply
* Re: [patch 14/44] generic hweight{64,32,16,8}()
From: Akinobu Mita @ 2006-02-06 11:52 UTC (permalink / raw)
To: Gabriel Paubert
Cc: linux-mips, linux-m68k, linux-ia64, Ian Molton, Balbir Singh,
Andi Kleen, David Howells, linuxppc-dev, Greg Ungerer, sparclinux,
Miles Bader, Yoshinori Sato, Hirokazu Takata, linuxsh-dev,
Linus Torvalds, Ivan Kokshaysky, linux, Richard Henderson,
Chris Zankel, dev-etrax, ultralinux, linux-kernel,
linuxsh-shmedia-dev, linux390, Russell King, parisc-linux
In-Reply-To: <20060202012637.GA25093@iram.es>
On Thu, Feb 02, 2006 at 02:26:38AM +0100, Gabriel Paubert wrote:
>
> The first step can be implemented slightly better:
>
> unsigned int res = w-((w>>1)&0x55555555);
>
Yes. I've got many advices about hweight speedup.
static unsigned int hweight32(unsigned int w)
{
unsigned int res = w - ((w >> 1) & 0x55555555);
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
res = (res + (res >> 4)) & 0x0F0F0F0F;
res = res + (res >> 8);
return (res + (res >> 16)) & 0x000000FF;
}
static unsigned int hweight16(unsigned int w)
{
unsigned int res = w - ((w >> 1) & 0x5555);
res = (res & 0x3333) + ((res >> 2) & 0x3333);
res = (res + (res >> 4)) & 0x0F0F;
return (res + (res >> 8)) & 0x00FF;
}
static unsigned int hweight8(unsigned int w)
{
unsigned int res = w - ((w >> 1) & 0x55);
res = (res & 0x33) + ((res >> 2) & 0x33);
return (res + (res >> 4)) & 0x0F;
}
static unsigned long hweight64(__u64 w)
{
#if BITS_PER_LONG < 64
return hweight32((unsigned int)(w >> 32)) +
hweight32((unsigned int)w);
#else
__u64 res = w - ((w >> 1) & 0x5555555555555555ul);
res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
res = res + (res >> 8);
res = res + (res >> 16);
return (res + (res >> 32)) & 0x00000000000000FFul;
#endif
}
^ permalink raw reply
* Re: Floating point math in kernel interrupt -- am I doing this right?
From: Roger Larsson @ 2006-02-06 8:41 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <200602051140.51759.jaf@lcsaudio.com>
On s=F6ndag 05 februari 2006 20.40, Jeremy Friesner wrote:
> If I disable the saving and restoring of the FPU registers=20
> entirely, they don't seem to occur at all (at least within the bounds of =
my
> testing so far -- 15+ hours).
Is this with full mix?
Then I would really suspect the save/restore code.
Saving and restoring floating point state can be very tricky.
Do try to find an example in the manual (or possibly in the kernel itself -=
=20
context switch code)
Until this works reliably there is no point in looking for other error=20
sources. You could also try to add code inside the save-resore that destro=
ys=20
all of the floating point registers to be able to spot errors.
/RogerL
^ permalink raw reply
* Floating point math in kernel interrupt -- am I doing this right? (repost)
From: Jeremy Friesner @ 2006-02-06 2:29 UTC (permalink / raw)
To: linuxppc-embedded
(Sorry if this is dupe, my first posting didn't seem to make it through)
Hi all,
Can someone who is well-versed in PowerPC kernel issues give me some advice?
First, a bit of background: I'm working on an audio mixing/playback engine
that runs on an embedded PowerPC chip (82xx) using the 2.4.23 kernel. The
audio output format is 48kHz floating point, and the mixing is done inside an
interrupt routine that runs 6000 times per second, and calculates 8 samples
per interrupt.
In order to do the necessary floating point math, without corrupting the state
of any other processes that might be using the FPU, the interrupt routine
first saves the state of the FPU registers to the stack, then does the math,
then restores FPU registers again, before returning.
In general this seems to work fine, i.e. I get the audio output I expect and
user processes aren't effected. However, I've noticed that every so often I
will get a kernel oops and my userland application will crash. The oops
looks like this:
<4>Oops: kernel access of bad area, sig: 11
<4>NIP: C001D408 XER: 20000000 LR: C001D3E0 SP: C6091E30 REGS: c6091d80 TRAP:
0300 Not tainted
<4>MSR: 00001032 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 11
<4>DAR: 3FE8228D, DSISR: 20000000
<4>TASK = c6090000[118] 'wtrxd' Last syscall: 178
<4>last math c6054000 last altivec 00000000
<4>GPR00: 0000001F C6091E30 C6090000 00000020 C6090398 C6055DE8 C017AB4C
00000000
<4>GPR08: 408CC599 3FE8228D 0000001F 00000000 84022884 10510E98 105800BC
308259E8
<4>GPR16: 1057302C 1058006C 00000000 00000000 00009032 06091F40 00000000
C0005DE8
<4>GPR24: C0005B40 00000020 00008000 00000000 C6091F50 C6091F20 C6091E78
00000020
<4>Call backtrace:
<4>00000400 C0009AB8 C0009CC0 C0009060 C0005B9C 0FC1BBA4 0FEF51D0
<4>0FEF6F58 0FEF3C3C 10366F34 10365C64 103572A0 103895D8 0FEF37EC
<4>0FCCDE2C
The frequency of the 'oops' occurrences appears to be proportional to the
amount of code that is present in the FPU-enabled section of the interrupt
routine. If I enable all of the mixing code, they appear every 10-20
minutes. If I disable all of the mixing code except the saving and restoring
of the FPU registers, they only occur about once every 6-12 hours. If I
disable the saving and restoring of the FPU registers entirely, they don't
seem to occur at all (at least within the bounds of my testing so far -- 15+
hours).
So my question is, is there some minor detail that my FPU-state-save/restore
code is missing, that would cause these sort of symptoms? I just enough
about kernel/assembly/PowerPC issues to be dangerous, so I thought maybe
there was something obvious that I am missing. The relevant code is shown
below.
Many thanks for any help or hints you can provide,
Jeremy Friesner
--------------- begin code snippet ----------------------
[... in interrupt routine...]
uint32 saved_msr;
uint32 saved_fpr[32*2]; // temp storage space for the current floating
point registers
/* Set up floating point enabled mode -- NO FLOATING POINT OPS ALLOWED
ABOVE THIS POINT! */
{
// Save existing MSR
uint32 msr;
__asm__ __volatile__ ("mfmsr %0" : "=r" (msr) : );
saved_msr = msr;
// Enable floating point
msr |= MSR_FP;
msr &= ~(MSR_FE0 | MSR_FE1);
__asm__ __volatile__ ("mtmsr %0\n\tisync" : : "r" (msr));
/* Save the floating point registers that the mix code uses, so that we
won't screw up the user process */
#define SAVE_FPR(x) {uint32 * saveTo = &saved_fpr[x*2]; __asm__ __volatile__
("stfd " #x ", 0(%0)\n" : : "b" (saveTo));}
SAVE_FPR(0); SAVE_FPR(1); SAVE_FPR(2); SAVE_FPR(3); SAVE_FPR(4);
SAVE_FPR(5); SAVE_FPR(6); SAVE_FPR(7); SAVE_FPR(8); SAVE_FPR(9);
SAVE_FPR(10); SAVE_FPR(11); SAVE_FPR(12); SAVE_FPR(13);
/* Note that I only save/restore the first 13 FP registers, since gcc's
generated code doesn't use the other ones anyway(!) */
}
[... the actual mixing routine is called here. I compile the mix function
in a separate file, without the -msoft-float flag ...]
[... but note that I get crashes even if I comment out the call to the
mixing routine, which suggests the problem is somewhere else...]
DoMixing();
/* Exit floating point enabled mode -- NO FLOATING POINT OPS ALLOWED BELOW
THIS POINT! */
{
/* Restore the FP registers back to their original state */
#define RESTORE_FPR(x) {uint32 * restoreFrom = &saved_fpr[x*2]; __asm__
__volatile__ ("lfd " #x ", 0(%0)\n" : : "b" (restoreFrom));}
RESTORE_FPR(0); RESTORE_FPR(1); RESTORE_FPR(2); RESTORE_FPR(3);
RESTORE_FPR(4);
RESTORE_FPR(5); RESTORE_FPR(6); RESTORE_FPR(7); RESTORE_FPR(8);
RESTORE_FPR(9);
RESTORE_FPR(10); RESTORE_FPR(11); RESTORE_FPR(12); RESTORE_FPR(13);
/* Restore MSR */
__asm__ __volatile__ ("mtmsr %0\n" "isync" : : "r" (saved_msr));
}
^ permalink raw reply
* Re: [CFT] Don't use ASYNC_* nor SERIAL_IO_* with serial_core
From: Hirokazu Takata @ 2006-02-06 1:34 UTC (permalink / raw)
To: rmk+lkml; +Cc: pfg, linux-mips, takata, linux-kernel, linuxppc-dev
In-Reply-To: <20060205000136.GF24887@flint.arm.linux.org.uk>
From: Russell King <rmk+lkml@arm.linux.org.uk>
Subject: Re: [CFT] Don't use ASYNC_* nor SERIAL_IO_* with serial_core
Date: Sun, 05 Feb 2006 00:01:36 +0000
> On Thu, Feb 02, 2006 at 11:10:33PM +0900, Hirokazu Takata wrote:
> > On m32r,
> > compile and boot test: OK
>
> Is that an Acked-by ?
>
> --
> Russell King
> Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
> maintainer of: 2.6 Serial core
>
Yes.
Acked-by: Hirokazu Takata <takata@linux-m32r.org>
Thanks,
--
Hirokazu Takata <takata@linux-m32r.org>
Linux/M32R Project: http://www.linux-m32r.org/
^ permalink raw reply
* Re: Yosemite/440EP PLB4 vs PLB3 DMA to PCI issue
From: David Hawkins @ 2006-02-05 23:47 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <20060205103958.284003535FD@atlas.denx.de>
Wolfgang Denk wrote:
> In message <43E58202.8020000@ovro.caltech.edu> you wrote:
>
>>MRM/MRL commands. I'll do that next. I just figured I'd
>>post these results now, so that others reading this
>>list might comment (Stefan from Denx comes to mind :))
>
>
> He's on vacation; he will be back on Monday, but certainly needs some
> time to catch up. Please stay tuned.
No rush, I just wanted to get the question on the list.
I took a look at the 440EP user manual, and I haven't been
able to explain the PLB4 DMA controller observations.
Here's what I've got so far;
p595: PLB-to-PCI transaction handling
Shows the two situations where the PCI bridge will
generate memory-read-line (MRL) and memory-read-multiple (MRM)
p646: has comments on PCI Memory to SDRAM DMA Transfer
and SDRAM to PCI memory DMA transfer. The figures
for those comments are further on.
The figures for the PCI read transactions on p663 and p691
show the PCI command MRL (Eh) being generated on the PCI
bus, and PCI data bursts occurring in lengths of 32-bytes.
These figures confirm what was observed with the PLB3 DMA
controller. Since the figures show the reads and the writes
on the PLB bus, and do not comment on the PLB bridge,
I can only assume that the figures assume the DMA controller
in use is the PLB3 DMA controller.
As to the PLB4 DMA controller observation of reads to PCI
causing the PCI read command to toggle between MRL and MRM,
I've no idea ... from p595 the transactions are considered
a burst read (MRM), then a burst read of 8-words (MRL),
then repeating. Since each read results in a PCI read burst of
length 32-bytes, there's clearly nothing different between
them on the PCI bus. But perhaps the transaction looks
different on the 440EP internal buses.
The test transfers were to a page-aligned block of SDRAM,
so I don't think the transactions are generating any alignment
issues.
(I hope you had a nice vacation Stefan!)
Cheers
Dave
^ permalink raw reply
* Floating point math in kernel interrupt -- am I doing this right?
From: Jeremy Friesner @ 2006-02-05 19:40 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: jeffk, Stephen Noftall
Hi all,
Can someone who is well-versed in PowerPC kernel issues give me some advice?
First, a bit of background: I'm working on an audio mixing/playback engine that runs on an embedded PowerPC chip (82xx) using the 2.4.23 kernel. The audio output format is 48kHz floating point, and the mixing is done inside an interrupt routine that runs 6000 times per second, and calculates 8 samples per interrupt.
In order to do the necessary floating point math, without corrupting the state of any other processes that might be using the FPU, the interrupt routine first saves the state of the FPU registers to the stack, then does the math, then restores FPU registers again, before returning.
In general this seems to work fine, i.e. I get the audio output I expect and user processes aren't effected. However, I've noticed that every so often I will get a kernel oops and my userland application will crash. The oops looks like this:
<4>Oops: kernel access of bad area, sig: 11
<4>NIP: C001D408 XER: 20000000 LR: C001D3E0 SP: C6091E30 REGS: c6091d80 TRAP: 0300 Not tainted
<4>MSR: 00001032 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 11
<4>DAR: 3FE8228D, DSISR: 20000000
<4>TASK = c6090000[118] 'wtrxd' Last syscall: 178
<4>last math c6054000 last altivec 00000000
<4>GPR00: 0000001F C6091E30 C6090000 00000020 C6090398 C6055DE8 C017AB4C 00000000
<4>GPR08: 408CC599 3FE8228D 0000001F 00000000 84022884 10510E98 105800BC 308259E8
<4>GPR16: 1057302C 1058006C 00000000 00000000 00009032 06091F40 00000000 C0005DE8
<4>GPR24: C0005B40 00000020 00008000 00000000 C6091F50 C6091F20 C6091E78 00000020
<4>Call backtrace:
<4>00000400 C0009AB8 C0009CC0 C0009060 C0005B9C 0FC1BBA4 0FEF51D0
<4>0FEF6F58 0FEF3C3C 10366F34 10365C64 103572A0 103895D8 0FEF37EC
<4>0FCCDE2C
The frequency of the 'oops' occurrences appears to be proportional to the amount of code that is present in the FPU-enabled section of the interrupt routine. If I enable all of the mixing code, they appear every 10-20 minutes. If I disable all of the mixing code except the saving and restoring of the FPU registers, they only occur about once every 6-12 hours. If I disable the saving and restoring of the FPU registers entirely, they don't seem to occur at all (at least within the bounds of my testing so far -- 15+ hours).
So my question is, is there some minor detail that my FPU-state-save/restore code is missing, that would cause these sort of symptoms? I just enough about kernel/assembly/PowerPC issues to be dangerous, so I thought maybe there was something obvious that I am missing. The relevant code is shown below.
Many thanks for any help or hints you can provide,
Jeremy Friesner
--------------- begin code snippet ----------------------
[... in interrupt routine...]
uint32 saved_msr;
uint32 saved_fpr[32*2]; // temp storage space for the current floating point registers
/* Set up floating point enabled mode -- NO FLOATING POINT OPS ALLOWED ABOVE THIS POINT! */
{
// Save existing MSR
uint32 msr;
__asm__ __volatile__ ("mfmsr %0" : "=r" (msr) : );
saved_msr = msr;
// Enable floating point
msr |= MSR_FP;
msr &= ~(MSR_FE0 | MSR_FE1);
__asm__ __volatile__ ("mtmsr %0\n\tisync" : : "r" (msr));
/* Save the floating point registers that the mix code uses, so that we won't screw up the user process */
#define SAVE_FPR(x) {uint32 * saveTo = &saved_fpr[x*2]; __asm__ __volatile__ ("stfd " #x ", 0(%0)\n" : : "b" (saveTo));}
SAVE_FPR(0); SAVE_FPR(1); SAVE_FPR(2); SAVE_FPR(3); SAVE_FPR(4);
SAVE_FPR(5); SAVE_FPR(6); SAVE_FPR(7); SAVE_FPR(8); SAVE_FPR(9);
SAVE_FPR(10); SAVE_FPR(11); SAVE_FPR(12); SAVE_FPR(13);
/* Note that I only save/restore the first 13 FP registers, since gcc's generated code doesn't use the other ones anyway(!) */
}
[... the actual mixing routine is called here. I compile the mix function in a separate file, without the -msoft-float flag ...]
[... but note that I get crashes even if I comment out the call to the mixing routine, which suggests the problem is somewhere else...]
DoMixing();
/* Exit floating point enabled mode -- NO FLOATING POINT OPS ALLOWED BELOW THIS POINT! */
{
/* Restore the FP registers back to their original state */
#define RESTORE_FPR(x) {uint32 * restoreFrom = &saved_fpr[x*2]; __asm__ __volatile__ ("lfd " #x ", 0(%0)\n" : : "b" (restoreFrom));}
RESTORE_FPR(0); RESTORE_FPR(1); RESTORE_FPR(2); RESTORE_FPR(3); RESTORE_FPR(4);
RESTORE_FPR(5); RESTORE_FPR(6); RESTORE_FPR(7); RESTORE_FPR(8); RESTORE_FPR(9);
RESTORE_FPR(10); RESTORE_FPR(11); RESTORE_FPR(12); RESTORE_FPR(13);
/* Restore MSR */
__asm__ __volatile__ ("mtmsr %0\n" "isync" : : "r" (saved_msr));
}
^ permalink raw reply
* [RFC] IDE support for the MPC5200
From: Sylvain Munaut @ 2006-02-05 19:50 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 894 bytes --]
Hello,
Here is a patch that adds PIO mode IDE support for the MPC5200.
It's a rewrite based on the 2.4 code by Benjamin Herrenschmidt and
a patch sent by Bernard Khun from metrowerks.
Obviously the patch works for me (I wouldn't post it if it didn't ...),
but I'd like people to test it and/or comment the code (as my experience
with the ide subsystem is limited I might have missed an obvious mistake).
The patch is here for test & review only. To test, you should fetch the
'ide' head of my git repository directly as the patch depends on some
trivial fixes that are not in vanilla right now (I intend to push those
along the IDE patch once reviewed).
To fetch: (just fetch, cloning the whole tree might take a while)
http://gitbits.246tnt.com/gitbits/linux-2.6-mpc52xx.git#ide
To view online:
http://gitbits.246tNt.com/gitweb.cgi?p=linux-2.6-mpc52xx.git;a=shortlog;h=ide
Sylvain
[-- Attachment #2: mpc52xx-ide-pio-20060205.diff --]
[-- Type: text/x-patch, Size: 21875 bytes --]
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 1c81174..e391cee 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -969,6 +969,10 @@ config IDE_EXT_DIRECT
endchoice
+config BLK_DEV_MPC52xx_IDE
+ tristate "MPC52xx Builtin IDE support"
+ depends on PPC_MPC52xx && IDE=y
+
# no isa -> no vlb
config IDE_CHIPSETS
bool "Other IDE chipset support"
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 569fae7..fcca1f3 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -34,6 +34,7 @@ ide-core-$(CONFIG_BLK_DEV_MAC_IDE) += le
ide-core-$(CONFIG_BLK_DEV_Q40IDE) += legacy/q40ide.o
# built-in only drivers from ppc/
+ide-core-$(CONFIG_BLK_DEV_MPC52xx_IDE) += ppc/mpc52xx_ide.o ppc/mpc52xx_ide_iops.o
ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ppc/mpc8xx.o
ide-core-$(CONFIG_BLK_DEV_IDE_PMAC) += ppc/pmac.o
diff --git a/drivers/ide/ppc/mpc52xx_ide.c b/drivers/ide/ppc/mpc52xx_ide.c
new file mode 100644
index 0000000..5970f7b
--- /dev/null
+++ b/drivers/ide/ppc/mpc52xx_ide.c
@@ -0,0 +1,420 @@
+/*
+ * drivers/ide/ppc/mpc52xx_ide.h
+ *
+ * Driver for the Freescale MPC52xx on-chip IDE interface
+ *
+ *
+ * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/config.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/ppcboot.h>
+
+#include "mpc52xx_ide.h"
+
+
+
+/* Private structures used by the driver */
+struct mpc52xx_ata_timings {
+ u32 pio1;
+ u32 pio2;
+ u32 mdma1;
+ u32 mdma2;
+ u32 udma1;
+ u32 udma2;
+ u32 udma3;
+ u32 udma4;
+ u32 udma5;
+ int using_udma;
+};
+
+struct mpc52xx_ide_priv {
+ unsigned int ipb_period; /* in ps */
+ struct mpc52xx_ata __iomem *ata_regs;
+ struct mpc52xx_ata_timings timings[2];
+};
+
+/* ATAPI-4 PIO specs (arranged for the 5200, cfr User Manual) */
+/* numbers in ns, extrapolation done by code */
+static int ataspec_t0[5] = {600, 383, 240, 180, 120};
+static int ataspec_t1[5] = { 70, 50, 30, 30, 25};
+static int ataspec_t2_8[5] = {290, 290, 290, 80, 70};
+static int ataspec_t2_16[5] = {165, 125, 100, 80, 70};
+static int ataspec_t2i[5] = { 0, 0, 0, 70, 25};
+static int ataspec_t4[5] = { 30, 20, 15, 10, 10};
+static int ataspec_ta[5] = { 35, 35, 35, 35, 35};
+
+/* Helpers to compute timing parameters */
+#define CALC_CLK_VALUE_UP(c,v) (((v) + c - 1) / c)
+
+
+/* ======================================================================== */
+/* IDE Driver & Aux functions */
+/* ======================================================================== */
+
+static void
+mpc52xx_ide_apply_timing(
+ struct mpc52xx_ata __iomem *regs, struct mpc52xx_ata_timings *timing)
+{
+ out_be32(®s->pio1, timing->pio1);
+ out_be32(®s->pio2, timing->pio2);
+ out_be32(®s->mdma1, timing->mdma1);
+ out_be32(®s->mdma2, timing->mdma2);
+ out_be32(®s->udma1, timing->udma1);
+ out_be32(®s->udma2, timing->udma2);
+ out_be32(®s->udma3, timing->udma3);
+ out_be32(®s->udma4, timing->udma4);
+ out_be32(®s->udma5, timing->udma5);
+}
+
+static void
+mpc52xx_ide_compute_pio_timing(
+ struct mpc52xx_ata_timings *timing, unsigned int ipb_period, u8 pio)
+{
+ u32 t0, t2_8, t2_16, t2i, t4, t1, ta;
+
+ /* We add 1 as a 'margin' */
+ t0 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t0[pio]);
+ t2_8 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2_8[pio]);
+ t2_16 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2_16[pio]);
+ t2i = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2i[pio]);
+ t4 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t4[pio]);
+ t1 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t1[pio]);
+ ta = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_ta[pio]);
+
+ timing->pio1 = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8) | (t2i);
+ timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8);
+}
+
+
+static void
+mpc52xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+ struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+ int w = drive->select.b.unit & 0x01;
+
+ pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+
+ printk("%s: Setting PIO %d timings\n", drive->name, pio);
+
+ mpc52xx_ide_compute_pio_timing(&priv->timings[w], priv->ipb_period, pio);
+
+ if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG))
+ mpc52xx_ide_apply_timing(regs, &priv->timings[w]);
+
+ /* Should we do it here or only in speedproc ? */
+ ide_config_drive_speed(drive, pio + XFER_PIO_0);
+}
+
+static int
+mpc52xx_ide_speedproc(ide_drive_t *drive, u8 speed)
+{
+ /* Configure PIO Mode */
+ if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
+ mpc52xx_ide_tuneproc(drive, speed - XFER_PIO_0);
+ return 0;
+ }
+
+ /* DMA settings currently unsupported */
+ printk(KERN_ERR
+ "mpc52xx-ide: speedproc called with unsupported mode %d\n",
+ speed);
+
+ return 1;
+}
+
+static void
+mpc52xx_ide_selectproc(ide_drive_t *drive)
+{
+ /* Change the PIO timings to the ones of the
+ currently selected drive */
+ struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+
+ mpc52xx_ide_apply_timing(regs,
+ &priv->timings[drive->select.b.unit & 0x01]);
+}
+
+
+static int
+mpc52xx_ide_setup(
+ struct mpc52xx_ata __iomem *regs, struct mpc52xx_ide_priv *priv)
+{
+ /* Vars */
+ extern bd_t __res;
+ bd_t *bd = (bd_t *)&__res;
+ int tslot;
+
+ /* All sample code do this */
+ out_be32(®s->share_cnt, 0);
+
+ /* Configure & Reset host */
+ out_be32(®s->config,
+ MPC52xx_ATA_HOSTCONF_IE |
+ MPC52xx_ATA_HOSTCONF_IORDY |
+ MPC52xx_ATA_HOSTCONF_SMR |
+ MPC52xx_ATA_HOSTCONF_FR);
+ udelay(10);
+ out_be32(®s->config,
+ MPC52xx_ATA_HOSTCONF_IE |
+ MPC52xx_ATA_HOSTCONF_IORDY);
+
+ /* Get IPB bus period */
+ priv->ipb_period = 1000000000 / (bd->bi_ipbfreq/1000);
+
+ /* Try to set the time slot to around 1us = 1000000 ps */
+ tslot = CALC_CLK_VALUE_UP(priv->ipb_period, 1000000);
+ out_be32(®s->share_cnt, tslot << 16);
+
+ /* Init imings to PIO0 (safest) */
+ memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
+
+ mpc52xx_ide_compute_pio_timing(&priv->timings[0], priv->ipb_period, 0);
+ mpc52xx_ide_compute_pio_timing(&priv->timings[1], priv->ipb_period, 0);
+
+ mpc52xx_ide_apply_timing(regs, &priv->timings[0]);
+
+ return 0;
+}
+
+static void
+mpc52xx_ide_setup_hwif_ports(hw_regs_t *hw, struct mpc52xx_ata __iomem *regs)
+{
+ /* It's MMIO and we handle all the io ops ourself, */
+ /* so theses address are really virtual addresses */
+ hw->io_ports[IDE_DATA_OFFSET] = (unsigned long) ®s->tf_data;
+ hw->io_ports[IDE_ERROR_OFFSET] = (unsigned long) ®s->tf_features;
+ hw->io_ports[IDE_NSECTOR_OFFSET] = (unsigned long) ®s->tf_sec_count;
+ hw->io_ports[IDE_SECTOR_OFFSET] = (unsigned long) ®s->tf_sec_num;
+ hw->io_ports[IDE_LCYL_OFFSET] = (unsigned long) ®s->tf_cyl_low;
+ hw->io_ports[IDE_HCYL_OFFSET] = (unsigned long) ®s->tf_cyl_high;
+ hw->io_ports[IDE_SELECT_OFFSET] = (unsigned long) ®s->tf_dev_head;
+ hw->io_ports[IDE_STATUS_OFFSET] = (unsigned long) ®s->tf_command;
+ hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long) ®s->tf_control;
+}
+
+
+/* ======================================================================== */
+/* Platform Driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_ide_probe(struct platform_device *dev)
+{
+ /* Vars */
+ ide_hwif_t *hwif;
+ struct mpc52xx_ide_priv *priv;
+ struct mpc52xx_gpio __iomem *gpio_regs = NULL;
+ struct mpc52xx_ata __iomem *ata_regs = NULL;
+ int ata_irq;
+ struct resource *res_mem;
+ u32 reg;
+ int i, rv;
+
+ /* Get an empty slot */
+ for (i=0; i<MAX_HWIFS && ide_hwifs[i].io_ports[IDE_DATA_OFFSET]; i++);
+ if (i >= MAX_HWIFS) {
+ printk(KERN_ERR "mpc52xx-ide: No free hwif slot !\n");
+ return -ENOMEM;
+ }
+
+ hwif = &ide_hwifs[i];
+
+ /* Check port muxing for compatibility */
+ gpio_regs = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
+ if (!gpio_regs) {
+ printk(KERN_ERR
+ "mpc52xx-ide: Unable to ioremap MPC52xx_GPIO zone\n");
+ return -ENOMEM;
+ }
+
+ reg = in_be32(&gpio_regs->port_config);
+ iounmap(gpio_regs);
+
+ if (!(reg & 0x03000000ul)) {
+ printk(KERN_ERR
+ "mpc52xx-ide: Invalid port config, no ATA CS !\n");
+ return -ENODEV;
+ }
+
+ /* Get the resources of this device */
+ ata_irq = platform_get_irq(dev, 0);
+ res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+
+ if (ata_irq<0 || res_mem==NULL) {
+ printk(KERN_ERR "mpc52xx-ide: Invalid resource set !\n");
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(res_mem->start, sizeof(struct mpc52xx_ata),
+ "mpc52xx-ide")) {
+ printk(KERN_ERR "mpc52xx-ide: Memory zone unavailable !\n");
+ return -EBUSY;
+ }
+
+ ata_regs = ioremap(res_mem->start, sizeof(struct mpc52xx_ata));
+ if (!ata_regs) {
+ printk(KERN_ERR
+ "mpc52xx-ide: Unable to ioremap ATA registers\n");
+ rv = -ENOMEM;
+ goto error;
+ }
+
+ /* Setup private structure */
+ priv = kmalloc(sizeof(struct mpc52xx_ide_priv), GFP_ATOMIC);
+ if (!priv) {
+ printk(KERN_ERR
+ "mpc52xx-ide: Can't allocate private structure !\n");
+ rv = -ENOMEM;
+ goto error;
+ }
+
+ priv->ata_regs = ata_regs;
+
+ /* Setup the ATA controller */
+ rv = mpc52xx_ide_setup(ata_regs, priv);
+ if (rv) {
+ printk(KERN_ERR "mpc52xx-ide: Controller setup failed !\n");
+ goto error;
+ }
+
+ /* Setup the hwif structure */
+ hwif->irq = ata_irq;
+ hwif->mmio = 2;
+ mpc52xx_ide_setup_hwif_iops(hwif);
+ mpc52xx_ide_setup_hwif_ports(&hwif->hw, ata_regs);
+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+
+ hwif->atapi_dma = 0;
+ hwif->ultra_mask = 0x00;
+ hwif->mwdma_mask = 0x00;
+ hwif->swdma_mask = 0x00;
+ hwif->chipset = ide_mpc52xx;
+ hwif->tuneproc = mpc52xx_ide_tuneproc;
+ hwif->speedproc = mpc52xx_ide_speedproc;
+ hwif->selectproc = mpc52xx_ide_selectproc;
+ hwif->noprobe = 0;
+ hwif->hold = 1;
+ hwif->autodma = 0;
+ hwif->udma_four = 0;
+ hwif->no_lba48 = 1; /* FIXME ? Did some one test that ? */
+ hwif->no_lba48_dma = 1;
+
+ hwif->drives[0].unmask = 1;
+ hwif->drives[0].autotune = 0; /* default */
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[0].no_io_32bit = 1; /* Anyone tried ? */
+
+ hwif->drives[1].unmask = 1;
+ hwif->drives[1].autotune = 0; /* default */
+ hwif->drives[1].autodma = hwif->autodma;
+ hwif->drives[1].no_io_32bit = 1; /* Anyone tried ? */
+
+ hwif->hwif_data = priv;
+ platform_set_drvdata(dev, hwif);
+
+ /* Lauch probe */
+ probe_hwif_init(hwif);
+
+ /* We're good ! */
+ printk(KERN_INFO
+ "mpc52xx-ide: Setup successful for %s (mem=%08lx-%08lx irq=%d)\n",
+ hwif->name, res_mem->start, res_mem->end, ata_irq);
+
+ return 0;
+
+
+ /* Error path */
+error:
+ if (ata_regs)
+ iounmap(ata_regs);
+
+ release_mem_region(res_mem->start, sizeof(struct mpc52xx_ata));
+
+ return rv;
+}
+
+static int
+mpc52xx_ide_remove(struct platform_device *dev)
+{
+ ide_hwif_t *hwif = platform_get_drvdata(dev);
+ struct mpc52xx_ide_priv *priv = hwif->hwif_data;
+ struct resource *res_mem;
+
+ ide_unregister(hwif - ide_hwifs);
+
+ iounmap(priv->ata_regs);
+
+ res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ release_mem_region(res_mem->start, sizeof(struct mpc52xx_ata));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+mpc52xx_ide_suspend(struct platform_device *dev, pm_message_t state)
+{
+ return 0; /* FIXME : What to do here ? */
+}
+
+static int
+mpc52xx_ide_resume(struct platform_device *dev)
+{
+ return 0; /* FIXME : What to do here ? */
+}
+#endif
+
+static struct platform_driver mpc52xx_ide_platform_driver = {
+ .probe = mpc52xx_ide_probe,
+ .remove = mpc52xx_ide_remove,
+#ifdef CONFIG_PM
+ .suspend = mpc52xx_ide_suspend,
+ .resume = mpc52xx_ide_resume,
+#endif
+ .driver = {
+ .name = "mpc52xx-ata",
+ },
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_ide_init(void)
+{
+ printk(KERN_INFO "ide: MPC52xx IDE/ATA driver\n");
+ return platform_driver_register(&mpc52xx_ide_platform_driver);
+}
+
+static void __exit
+mpc52xx_ide_exit(void)
+{
+ platform_driver_unregister(&mpc52xx_ide_platform_driver);
+}
+
+
+module_init(mpc52xx_ide_init);
+module_exit(mpc52xx_ide_exit);
+
+MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
+MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/ppc/mpc52xx_ide.h b/drivers/ide/ppc/mpc52xx_ide.h
new file mode 100644
index 0000000..e2490a8
--- /dev/null
+++ b/drivers/ide/ppc/mpc52xx_ide.h
@@ -0,0 +1,129 @@
+/*
+ * drivers/ide/ppc/mpc52xx_ide.h
+ *
+ * Definitions for the Freescale MPC52xx on-chip IDE interface
+ *
+ *
+ * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __MPC52xx_IDE_H__
+#define __MPC52xx_IDE_H__
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+
+
+/* Bit definitions inside the registers */
+
+#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */
+#define MPC52xx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */
+#define MPC52xx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt in PIO */
+#define MPC52xx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports IORDY protocol */
+
+#define MPC52xx_ATA_HOSTSTAT_TIP 0x80000000UL /* Transaction in progress */
+#define MPC52xx_ATA_HOSTSTAT_UREP 0x40000000UL /* UDMA Read Extended Pause */
+#define MPC52xx_ATA_HOSTSTAT_RERR 0x02000000UL /* Read Error */
+#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */
+
+#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */
+
+#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */
+#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */
+#define MPC52xx_ATA_DMAMODE_UDMA 0x04 /* UDMA enabled */
+#define MPC52xx_ATA_DMAMODE_IE 0x08 /* Enable drive interrupt to CPU in DMA mode */
+#define MPC52xx_ATA_DMAMODE_FE 0x10 /* FIFO Flush enable in Rx mode */
+#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */
+#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */
+
+
+/* Structure of the hardware registers */
+struct mpc52xx_ata {
+
+ /* Host interface registers */
+ u32 config; /* ATA + 0x00 Host configuration */
+ u32 host_status; /* ATA + 0x04 Host controller status */
+ u32 pio1; /* ATA + 0x08 PIO Timing 1 */
+ u32 pio2; /* ATA + 0x0c PIO Timing 2 */
+ u32 mdma1; /* ATA + 0x10 MDMA Timing 1 */
+ u32 mdma2; /* ATA + 0x14 MDMA Timing 2 */
+ u32 udma1; /* ATA + 0x18 UDMA Timing 1 */
+ u32 udma2; /* ATA + 0x1c UDMA Timing 2 */
+ u32 udma3; /* ATA + 0x20 UDMA Timing 3 */
+ u32 udma4; /* ATA + 0x24 UDMA Timing 4 */
+ u32 udma5; /* ATA + 0x28 UDMA Timing 5 */
+ u32 share_cnt; /* ATA + 0x2c ATA share counter */
+ u32 reserved0[3];
+
+ /* FIFO registers */
+ u32 fifo_data; /* ATA + 0x3c */
+ u8 fifo_status_frame; /* ATA + 0x40 */
+ u8 fifo_status; /* ATA + 0x41 */
+ u16 reserved7[1];
+ u8 fifo_control; /* ATA + 0x44 */
+ u8 reserved8[5];
+ u16 fifo_alarm; /* ATA + 0x4a */
+ u16 reserved9;
+ u16 fifo_rdp; /* ATA + 0x4e */
+ u16 reserved10;
+ u16 fifo_wrp; /* ATA + 0x52 */
+ u16 reserved11;
+ u16 fifo_lfrdp; /* ATA + 0x56 */
+ u16 reserved12;
+ u16 fifo_lfwrp; /* ATA + 0x5a */
+
+ /* Drive TaskFile registers */
+ u8 tf_control; /* ATA + 0x5c TASKFILE Control/Alt Status */
+ u8 reserved13[3];
+ u16 tf_data; /* ATA + 0x60 TASKFILE Data */
+ u16 reserved14;
+ u8 tf_features; /* ATA + 0x64 TASKFILE Features/Error */
+ u8 reserved15[3];
+ u8 tf_sec_count; /* ATA + 0x68 TASKFILE Sector Count */
+ u8 reserved16[3];
+ u8 tf_sec_num; /* ATA + 0x6c TASKFILE Sector Number */
+ u8 reserved17[3];
+ u8 tf_cyl_low; /* ATA + 0x70 TASKFILE Cylinder Low */
+ u8 reserved18[3];
+ u8 tf_cyl_high; /* ATA + 0x74 TASKFILE Cylinder High */
+ u8 reserved19[3];
+ u8 tf_dev_head; /* ATA + 0x78 TASKFILE Device/Head */
+ u8 reserved20[3];
+ u8 tf_command; /* ATA + 0x7c TASKFILE Command/Status */
+ u8 dma_mode; /* ATA + 0x7d ATA Host DMA Mode configuration */
+ u8 reserved21[2];
+};
+
+
+/* Function definition */
+
+static inline void
+mpc52xx_ide_wait_tip_bit_clear(struct mpc52xx_ata __iomem *regs)
+{
+ int timeout = 1000;
+
+ while (in_be32(®s->host_status) & MPC52xx_ATA_HOSTSTAT_TIP)
+ if (timeout-- == 0) {
+ printk(KERN_ERR
+ "mpc52xx-ide: Timeout waiting for TIP clear\n");
+ break;
+ }
+ udelay(10); /* FIXME: Necessary ??? */
+}
+
+extern void mpc52xx_ide_setup_hwif_iops(ide_hwif_t *hwif);
+
+
+#endif /* __MPC52xx_IDE_H__ */
+
diff --git a/drivers/ide/ppc/mpc52xx_ide_iops.c b/drivers/ide/ppc/mpc52xx_ide_iops.c
new file mode 100644
index 0000000..6ced54e
--- /dev/null
+++ b/drivers/ide/ppc/mpc52xx_ide_iops.c
@@ -0,0 +1,151 @@
+/*
+ * drivers/ide/ppc/mpc52xx_ide_iops.c
+ *
+ * Utility functions for MPC52xx on-chip IDE interface
+ *
+ *
+ * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#include "mpc52xx_ide.h"
+
+
+
+static u8
+mpc52xx_ide_inb(unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ return (u8) readb((void __iomem *) port);
+}
+
+static u16
+mpc52xx_ide_inw(unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ return (u16) readw((void __iomem *) port);
+}
+
+static void
+mpc52xx_ide_insw(unsigned long port, void *addr, u32 count)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ __ide_mm_insw((void __iomem *) port, addr, count);
+}
+
+static u32
+mpc52xx_ide_inl(unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ return (u32) readl((void __iomem *) port);
+}
+
+static void
+mpc52xx_ide_insl(unsigned long port, void *addr, u32 count)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ __ide_mm_insl((void __iomem *) port, addr, count);
+}
+
+static void
+mpc52xx_ide_outb(u8 value, unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ writeb(value, (void __iomem *) port);
+}
+
+static void
+mpc52xx_ide_outbsync(ide_drive_t *drive, u8 value, unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ writeb(value, (void __iomem *) port);
+}
+
+
+static void
+mpc52xx_ide_outw(u16 value, unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ writew(value, (void __iomem *) port);
+}
+
+static void
+mpc52xx_ide_outsw(unsigned long port, void *addr, u32 count)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ __ide_mm_outsw((void __iomem *) port, addr, count);
+}
+
+static void
+mpc52xx_ide_outl(u32 value, unsigned long port)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ writel(value, (void __iomem *) port);
+}
+
+static void
+mpc52xx_ide_outsl(unsigned long port, void *addr, u32 count)
+{
+ struct mpc52xx_ata __iomem *ata_regs =
+ (struct mpc52xx_ata __iomem *)(port & ~0xfful);
+
+ mpc52xx_ide_wait_tip_bit_clear(ata_regs);
+ __ide_mm_outsl((void __iomem *) port, addr, count);
+}
+
+
+void
+mpc52xx_ide_setup_hwif_iops(ide_hwif_t *hwif)
+{
+ hwif->OUTB = mpc52xx_ide_outb;
+ hwif->OUTBSYNC = mpc52xx_ide_outbsync;
+ hwif->OUTW = mpc52xx_ide_outw;
+ hwif->OUTL = mpc52xx_ide_outl;
+ hwif->OUTSW = mpc52xx_ide_outsw;
+ hwif->OUTSL = mpc52xx_ide_outsl;
+ hwif->INB = mpc52xx_ide_inb;
+ hwif->INW = mpc52xx_ide_inw;
+ hwif->INL = mpc52xx_ide_inl;
+ hwif->INSW = mpc52xx_ide_insw;
+ hwif->INSL = mpc52xx_ide_insl;
+}
+
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 110b3cf..4cc9608 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -203,7 +203,7 @@ typedef enum { ide_unknown, ide_generic,
ide_rz1000, ide_trm290,
ide_cmd646, ide_cy82c693, ide_4drives,
ide_pmac, ide_etrax100, ide_acorn,
- ide_au1xxx, ide_forced
+ ide_au1xxx, ide_mpc52xx, ide_forced
} hwif_chipset_t;
/*
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox