LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH]: e1000: prevent statistics from getting garbled during reset.
From: Linas Vepstas @ 2006-03-31  0:35 UTC (permalink / raw)
  To: Jeff V. Merkey
  Cc: netdev, linux-kernel, jesse.brandeburg, linuxppc-dev,
	john.ronciak, jeffrey.t.kirsher, linux-pci, Jeff Garzik
In-Reply-To: <442C8069.507@wolfmountaingroup.com>

On Thu, Mar 30, 2006 at 06:05:45PM -0700, Jeff V. Merkey wrote:
> 
> Linas Vepstas wrote:

Well, these comments have nothing to do with my patch, but ... 
anyway ... 

> The driver also needs to be fixed to allow clearing of the stats (like 
> all the other adapter drivers). At present, when I run performance
> and packet drop counts on the cards, I cannot reset the stats with this 
> code because the driver stores them in the e100_adapter
> structure. This is busted.
> 
> This function:
> 
> int clear_network_device_stats(BYTE *name)

I couldn't find such a function in the kernel.
 
> does not work on e1000 due to this section of code:
> 
> void
> e1000_update_stats(struct e1000_adapter *adapter)
> {
> 
> adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC);
> adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC);

These are hardware stats ... presumably useless without
a detailed understanding of the guts of the e1000.

> //NOTE These stats need to be stored in the stats structure so they can 
> be cleared by
> statistics monitoring programs.

I can't imagine what generic interface would allow these 
to be viewed.

> /* Fill out the OS statistics structure */
> 
> adapter->net_stats.rx_packets = adapter->stats.gprc;
> adapter->net_stats.tx_packets = adapter->stats.gptc;
> adapter->net_stats.rx_bytes = adapter->stats.gorcl;
> adapter->net_stats.tx_bytes = adapter->stats.gotcl;

Now *these* are generic ... and fixing this so that the 
stats increment instead of over-riding would take 
maybe half-an-hour or so; this is not hard to do ... !? 

Do you want me to write a patch to do this?

--linas

^ permalink raw reply

* Re: [PATCH]: e1000: prevent statistics from getting garbled during reset.
From: Linas Vepstas @ 2006-03-31  0:02 UTC (permalink / raw)
  To: john.ronciak, jesse.brandeburg, jeffrey.t.kirsher
  Cc: netdev, linux-pci, Jeff Garzik, linux-kernel, linuxppc-dev
In-Reply-To: <20060330213928.GQ2172@austin.ibm.com>

On Thu, Mar 30, 2006 at 03:39:28PM -0600, Linas Vepstas wrote:
> 
> Please review, sign-off/ack, and forward upstream.
> --linas

Per feedback, here's a slightly more human-readable version.
--linas

[PATCH]: e1000: prevent statistics from getting garbled during reset.

If a PCI bus error/fault triggers a PCI bus reset, attempts to get the
ethernet packet count statistics from the hardware will fail, returning
garbage data upstream.  This patch skips statistics data collection
if the PCI device is not on the bus. 

This patch presumes that an earlier patch,
[PATCH] PCI Error Recovery: e1000 network device driver
has already been applied.

Signed-off-by: Linas Vepstas <linas@austin.ibm.com>

----
 drivers/net/e1000/e1000_main.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletion(-)

Index: linux-2.6.16-git6/drivers/net/e1000/e1000_main.c
===================================================================
--- linux-2.6.16-git6.orig/drivers/net/e1000/e1000_main.c	2006-03-30 17:51:37.924162779 -0600
+++ linux-2.6.16-git6/drivers/net/e1000/e1000_main.c	2006-03-30 17:54:07.659188391 -0600
@@ -3069,14 +3069,18 @@ void
 e1000_update_stats(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
+	struct pci_dev *pdev = adapter->pdev;
 	unsigned long flags;
 	uint16_t phy_tmp;
 
 #define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
 
-	/* Prevent stats update while adapter is being reset */
+	/* Prevent stats update while adapter is being reset,
+	 * or if the pci connection is down. */
 	if (adapter->link_speed == 0)
 		return;
+   if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+		return;
 
 	spin_lock_irqsave(&adapter->stats_lock, flags);
 

^ permalink raw reply

* Re: [PATCH 3/5] powerpc: Move create_(instruction|branch|function_call) into util.h
From: Michael Ellerman @ 2006-03-30 22:43 UTC (permalink / raw)
  To: Linas Vepstas; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <20060330181049.GN2172@austin.ibm.com>

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

On Thu, 2006-03-30 at 12:10 -0600, Linas Vepstas wrote:
> Hi,
> A minor quibble from the dept. of naming things:
> 
> On Thu, Mar 30, 2006 at 05:12:59PM +1100, Michael Ellerman wrote:
> > ===================================================================
> > --- /dev/null
> > +++ to-merge/include/asm-powerpc/util.h
> > @@ -0,0 +1,56 @@
> > +
> > +#ifndef _ASM_POWERPC_UTIL_H
> > +#define _ASM_POWERPC_UTIL_H
> > +
> > +static inline void create_instruction(unsigned long addr, unsigned int instr)
> 
> 
> Surely there is a more descriptive name for this new file than "util.h"?
> 
> How about "dynamic_insn.h" or "insn_patch.h" or "dyn_fixup.h" or
> something like that? 

That would be more descriptive of what's in there now, but I actually
intended it to be a place where we can put util-ish code. Obviously
we'll have to make sure it doesn't get abused, but I think it's valid to
have one header file for random stuff that doesn't belong elsewhere.
Others may disagree?

cheers

-- 
Michael Ellerman
IBM OzLabs

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: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH] PowerMac11,2 i2c-bus@0 duplicate dev-tree workaround
From: Johannes Berg @ 2006-03-30 22:38 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev
In-Reply-To: <1143700119.23392.27.camel@localhost.localdomain>

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

On Thu, 2006-03-30 at 17:28 +1100, Michael Ellerman wrote:

> I don't understand why we need this patch? If we care about getting the
> "right" node why not check for that where we care?

It's not just a single node but also contains sub-nodes. In one of them,
one of those sub nodes is there but contains bogus info, and in the
other both are there and contain the right info. Some things that work
off these bus nodes are detected twice if they're there, and they're
used in at least two places that I know of.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]

^ permalink raw reply

* Re: [PATCH] PowerMac11,2 i2c-bus@0 duplicate dev-tree workaround
From: Michael Ellerman @ 2006-03-30  6:28 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linuxppc-dev
In-Reply-To: <1143631816.9481.5.camel@localhost>

On Wed, 2006-03-29 at 13:30 +0200, Johannes Berg wrote:
> On a PowerMac11,2, there are two i2c-bus@0 nodes of which only the first
> is correct. This patch makes the device tree unflattening code ignore
> the second one on those machines.
> 
> Signed-Off-By: Johannes Berg <johannes@sipsolutions.net>
> 
> --- 
> I'm not sure this is the right way to do it. Maybe we should have some
> 'dev-tree quirks fixer' that makes a third pass through the device tree
> after the allnodes chain has been set up, and fixes it up. On the other
> hand, as long as there aren't too many workarounds, this works fine.
> 
> The patch looks longer than it is because some code changed indentation
> level.

I don't understand why we need this patch? If we care about getting the
"right" node why not check for that where we care?

cheers

-- 
Michael Ellerman
IBM OzLabs

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

^ permalink raw reply

* Bestcomm Firmware update
From: bennett78 @ 2006-03-30 22:23 UTC (permalink / raw)
  To: linuxppc-embedded, Wolfgang Denk, John Rigby, Dale Farnsworth,
	Andrey Volkov
  Cc: Sylvain Munaut

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

SoSoComm Dudes:

  I was able to contact Davide Santo, AN2604 "Introduction to BestComm". 
He admitted
the short commings of his document in the area of Firmware instruction 
info and gave
me a name of a guy, Ed in the ASIC design area in Austin.  Ed has agreed 
to answer
questions, push for resources to provide a support tool and provided me 
with a document
from their head programmer "SmartDMA Hand-Assembly Guides" (see attached 
pdf).

With this secret decoded ring I was able to put together a disassembler, 
see attached
disasm.c. Cut and paste your favorite Task into fw[] array at the 
beginning,
"cc -o d disasm.c ; d"  It's not perfect, but useful- Enjoy.  Sorry I'm not
sure where or if you guys want to check this stuff into a git 
repository, somewhere
and hope ozlabs is not fussy about attachments!

If we can formulate a list of questions Ed might be able to help, I'll 
start:
    o what does init=31 mean?
       AN2604 say init=0 means always requestor and 31 is reserved but 
referenced
       alot in the F/W comments
    o Need more info on how MORE works
    o Tell us about LCD levels. Only 2? (let's call a LCD indent a level)
      LCD seems to reset DRD to 1A. DRD2B1or2 follow a DRD2A (ext=1)?
    o LCD[28:23]orLCD[20:15] or LCD[11:6] what is extraN?
        drop 101nnn - extraN
        add  1nnnnn - indexN
    o how many DRD2B1[2] can be stacked up?
    o when is/can a LDC Literal used? and how?

*/Frank Bennett
Technical Contractor/*

/Triad Systems Engineering
200 West Mountain Avenue
Fort. Collins, CO 80521
/http://www.traidsyseng.com <http://www.triadsyseng.com>
frank.bennett@triadsyseng.com <mailto:frank.bennett@triadsyseng.com>/
/office: 970-493-7586

*//*


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

/*
 * disasm.c - disassembler for MPC5200 Bestcomm DMA Firmware
 *            copy and paste task code into fw, compile a run
 * by Frank bennett, 3/29/2006
 *
 * Based on Freescale pdf "SmartDMA Hand-Assembly Guides"
 *
 * TODO:
 *  o add inc[0:7] array (maybe var) to deternmine proper term condition (upper 3 bits)
 *  o need to review sheet 3 of the pdf
 *  o simulator would be nice
 *
 */
// Task12 (TASK_GEN_TX_BD) : Start of TDT -> 0xf0008528
// linuxppc_2_4_devel/arch/ppc/5xxx_io/bestcomm/code_dma/image_rtos1/"dma_image.reloc.c
//
// 31,30,29,28|27,26,25,24|23,22,21,20|19,18,17,16|15,14,13,12|11,10, 9, 8| 7, 6, 5, 4| 3, 2, 1, 0
//  0  0  0  1  0  0| 0  0  0  0  0| 0  0| 0  0| 0| 0  0  0  1  0  0| 1| 1  0  0  0  0  1| 0  0  0
// 0x10001308, /* 000C      DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=2 */
//  1  0  0| 1  1  0  0  1  0| 0| 0| 1  1  0  0  1  0| 0  0| 0| 0  0  0  0  0  0| 1  1  0| 1  1  0
// 0x99190036, /* 002C    LCD: idx2 = idx2; idx2 once var0; idx2 += inc6 */
// 31,30,29,28|27,26,25,24|23,22,21,20|19,18,17,16|15,14,13,12|11,10, 9, 8| 7, 6, 5, 4| 3, 2, 1, 0
// 1   0| 0  1  1  0, 0  1  0  1,    1  0  0, 0  0  1| 1  0| 1  0  0  1  0  0  0  0  1  0  0  0  0
// 0x9950d210

/* Task12(TASK_GEN_TX_BD): Start of TDT -> 0xf0008528 */
unsigned long fw[] = {
    0x800220e3, /* 0000  LCD: idx0 = var0, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */
    0x13e01010, /* 0004    DRD1A: var4 = var2; FN=0 MORE init=24 WS=0 RS=0 */
    0xb8808264, /* 0008    LCD: idx2 = *idx1, idx3 = var1; idx2 < var9; idx2 += inc4, idx3 += inc4 */
    0x10001308, /* 000C      DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=2 */
    0x60140002, /* 0010      DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
    0x0cccfcca, /* 0014      DRD2B1: *idx3 = EU3(); EU3(*idx3,var10)  */
    0xd9190300, /* 0018    LCDEXT: idx2 = idx2; idx2 > var12; idx2 += inc0 */
    0xb8c5e009, /* 001C    LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */
    0x03fec398, /* 0020      DRD1A: *idx0 = *idx3; FN=0 init=24 WS=3 RS=2 */
    0x9919826a, /* 0024    LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc5, idx3 += inc2 */
    0x0feac398, /* 0028      DRD1A: *idx0 = *idx3; FN=0 TFD INT init=24 WS=1 RS=2 */
    0x99190036, /* 002C    LCD: idx2 = idx2; idx2 once var0; idx2 += inc6 */
    0x60000005, /* 0030      DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
    0x0c4cf889, /* 0034      DRD2B1: *idx1 = EU3(); EU3(idx2,var9)  */
    0x000001f8, /* 0038    NOP */
    0x9950d210,
	0x2c4cf889,
    0
};

union
{
    unsigned long i;
    struct
    {
        unsigned sb:3;     // [02:00] increment #2
        unsigned sa:3;     // [05:03] increment #1
        unsigned tc:6;     // [11:06] variable to which idx is compared   
        unsigned drtc:1;   //    [12] dr ? *(tc) : (tc)
        unsigned tu:2;     // [14:13] term usage 00-idx_a, 01-idx_b, 10- lit init 11-no cond
        unsigned ib:6;     // [20:15] init_b 
        unsigned drib:1;   //    [21] dr ? *(init_a) : (init_a)
        unsigned p:1;      //    [22] indx plus offset
        unsigned ia:6;     // [28:23] init_a 
        unsigned dria:1;   //    [29] dr ? *(init_a) : (init_a)
        unsigned ext:1;    //    [30] = 2 or 3 for LCD
        unsigned op:1;     //    [31] = 2 or 3 for LCD
    } lcd;
    struct
    {
        unsigned ll:13;    // [12:00] literal init low
        unsigned tu:2;     // [14:13] term usage == 2
        unsigned lh:15;    // [29:15] literal init hi 
        unsigned bas:1;    //    [30] = 2 or 3 for LCD
        unsigned op:1;     //    [31] = 2 or 3 for LCD
    } lcdl;

    struct
    {
        unsigned fn:3;     // [02:00]
        unsigned src:6;    // [08:03]
        unsigned drs:1;    //    [09] deref src?
        unsigned dst:6;    // [15:10]
        unsigned drd:1;    //    [16] deref dst? scal?
        unsigned ws:2;     // [18:17] 0-32bit, 1-1 byte, 2-16 word, 3-dynamic/reserved??
        unsigned rs:2;     // [20:19] 0-32bit, 1-1 byte, 2-16 word, 3-dynamic/reserved??
        unsigned init:5;   // [25:21]
        unsigned intr:1;   //    [26]
        unsigned tfd:1;    //    [27]
        unsigned more:1;   //    [28]      
        unsigned type:1;   //    [29] 
        unsigned ext:1;    //    [30] 
        unsigned op:1;     //    [31] = 0 for DRD
    } drd1a;
    struct
    {
        unsigned eu3:4;    // [03:00] Execution Unit3 Function number
        unsigned eu2:4;    // [07:04] Execution Unit3 Function number
        unsigned eu1:4;    // [11:08] Execution Unit3 Function number
        unsigned eu0:4;    // [15:12] Execution Unit3 Function number
        unsigned drd:1;    //    [16] deref dst? scal?
        unsigned ws:2;     // [18:17] 0-32bit, 1-1 byte, 2-16 word, 3-dynamic/reserved??
        unsigned rs:2;     // [20:19] 0-32bit, 1-1 byte, 2-16 word, 3-dynamic/reserved??
        unsigned init:5;   // [25:21]
        unsigned int:1;    //    [26]
        unsigned tfd:1;    //    [27]
        unsigned more:1;   //    [28]      
        unsigned type:1;   //    [29] 
        unsigned ext:1;    //    [30] 
        unsigned op:1;     //    [31] = 0 for DRD
    } drd2a;
    struct
    {
        unsigned od1:6;    // [05:00] EU operand 1
        unsigned od0:6;    // [11:06] EU operand 0
        unsigned eu:2;     // [13:12] EU#, only #3 available on MPC5200
        unsigned mems:6;   // [19:14] memory write source
        unsigned drds:1;   //    [20]      
        unsigned rsv2:1;   //    [21]      
        unsigned memd:6;   // [27:22] memory write destination
        unsigned rsv1:1;   //    [28] reserved?
        unsigned type:1;   //    [29] 
        unsigned ext:1;    //    [30] 
        unsigned op:1;     //    [31] = 0 for DRD
    } drd2b1;
    struct
    {
        unsigned odb1:6;   // [05:00] EUb operand 1/3/5/7
        unsigned odb0:6;   // [11:06] EUb operand 0/2/4/6
        unsigned eub:2;    // [13:12] EUb#, only #3 available on MPC5200
        unsigned oda1:6;   // [19:14] EUa operand 1/3/5/7
        unsigned oda0:6;   // [25:20] EUa operand 0/2/4/6
        unsigned eua:2;    // [27:26] EUa#, only #3 available on MPC5200
        unsigned rsv1:1;   //    [28]      
        unsigned type:1;   //    [29] 
        unsigned ext:1;    //    [30] 
        unsigned op:1;     //    [31] = 0 for DRD
    } drd2b2;
} x;

// Condition codes (first 4 bits of the increments)
// >=   c
// >    4
// once 0
// !=   6
// <=   a
// <    2

char *ft[] = {
    "ld_acc", "unld_acc", "and", "or", "xor" "andn", "not",
    "add", "sub", "lsh", "rsh", "crc8", "crc16", "crc32", 
	"endian32", "endian16"
};

char s[8];
indvar (int i)
{
    switch ((i & 0x3f) >> 4)
    {
    case 0:
        sprintf (s, "var%d", i & 0x1f); // varN
        break;
    case 1:
        sprintf (s, "inc%d", i & 0x07); // incN
        break;
    case 2:    			                // extraN
    case 3:
        sprintf (s, "idx%d", i & 0x0f); // idxN
        break;
    }
}

#define L2 LLev*2
main ()
{
    int i, j, LLev = 0, drdt, ex = 0, ml;
    char in[12];

    for (i = 0; fw[i]; i++)
    {
        x.i = fw[i];
        if (x.i == 0x1f8)
            printf ("0x%08x, // NOP\n", x.i);
        else if (x.lcd.op)      	// LCD
        {
            if (LLev == 0)
                strcpy (in, "");
            else
                strcpy (in, "  ");

            if (x.lcd.ext)			// LCDEXT
            {
                indvar (x.lcd.tc);
                printf
                    ("0x%08x, // %sLCDEXT: idx%d=idx%d; idx%d >%s%s ; idx%d += inc%d\n",
                     x.i, in, L2, L2, L2, x.lcd.drtc ? "*" : " ", s, L2,
                     x.lcd.sb);
            } else if (x.lcd.tu == 2)	 // LCDLIT
            {
                printf ("0x%08x, // %sLCDLIT: idx%d = 0x%07x ??\n",
                        x.i, in, L2, (x.lcdl.lh << 13) | x.lcdl.ll);
            } else                	// LCD
            {
                printf ("0x%08x, // %sLCD: ", x.i, in);
                if (x.lcd.p)    // indexed p-plus
                {
                    indvar (x.lcd.ia);
                    printf ("idx%d = %s(%s + ", L2 + 1, x.lcd.dria ? "*" : " ", s);
                    indvar (x.lcd.ib);
                    printf ("%s%s); ; ", x.lcd.drib ? "*" : " ", s);
                } else
                {
                    indvar (x.lcd.ia);
                    printf ("idx%d=%s%s, ", L2, x.lcd.dria ? "*" : " ", s);
                    indvar (x.lcd.ib);
                    printf ("idx%d=%s%s, ", L2 + 1, x.lcd.drib ? "*" : " ", s);
                }
                if (x.lcd.tu < 2)
                {
                    indvar (x.lcd.tc);
                    printf ("idx%d <=%s%s, ", (x.lcd.tu == 0) ? L2 : L2 + 1,
                            x.lcd.drtc ? "*" : " ", s);
                }
                if (x.lcd.tu != 3)
                    printf ("idx%d += inc%01x, ", L2, x.lcd.sa);
                printf ("idx%d += inc%01x\n", L2 + 1, x.lcd.sb);
                ex = 0;
            }
        }
        else
        {
            // DRD
            if (LLev == 0)
                strcpy (in, "  ");
            else
                strcpy (in, "    ");
            drdt = (ex << 2) | (x.drd1a.ext << 1) | x.drd1a.type;
            switch (drdt)
            {
            case 0:            // DRD1A
                printf ("0x%08x, // %sDRD1A: ", x.i, in);
                indvar (x.drd1a.dst);
                printf ("%s%s =", x.drd1a.drd ? "*" : " ", s);
                indvar (x.drd1a.src);
                printf ("%s%s; ", x.drd1a.drs ? "*" : " ", s);
                printf ("FN=%d (%s) ", x.drd1a.fn, ft[x.drd1a.fn]);
                if (x.drd1a.more)
                    printf ("MORE ");
                if (x.drd1a.tfd)
                    printf ("TFD ");
                if (x.drd1a.intr)
                    printf ("INT ");
                printf ("init=%d ", x.drd1a.init);
                printf ("WS=%d RS=%d \n", x.drd1a.ws, x.drd1a.rs);
                break;
            case 3:            // DRD2A
                ex = x.drd2a.ext;
                printf ("0x%08x, // %sDRD2A: ", x.i, in);
                printf ("EU0=0 EU1=0 EU2=0 EU3=%d (%s) EXT init=%d ",
                        x.drd2a.eu3, ft[x.drd2a.eu3], x.drd2a.init);
                printf ("WS=%d RS=%d \n", x.drd2a.ws, x.drd2a.rs);
                break;
            case 4:            // DRD2B1
                printf ("0x%08x, // %sDRD2B1: ", x.i, in);
                indvar (x.drd2b1.memd);   // mems ??
                printf ("*%s=EU%d(); ", s, x.drd2b1.eu);
                indvar (x.drd2b1.od0); printf ("EU%d(%s, ", x.drd2b1.eu, s);
                indvar (x.drd2b1.od1); printf ("%s) \n", s);
                break;
            case 5:            // DRD2B2
            case 7:            // DRD2B2?
                printf ("0x%08x, // %sDRD2B2: ", x.i, in);
                indvar (x.drd2b2.oda0); printf ("EU%d(%s, ", x.drd2b2.eub, s);
                indvar (x.drd2b2.oda1); printf ("%s) , ", s);
                indvar (x.drd2b2.odb0); printf ("EU%d(%s, ", x.drd2b2.eua, s);
                indvar (x.drd2b2.odb1); printf ("%s) ??\n", s);
				break;
            case 1:
            case 2:
            case 6:
                printf ("fix_me\n");
                ex = x.drd1a.ext;
                break;
            }
            LLev |= 1;
        }
    }
}

[-- Attachment #3: sdHandAssemblyLcdDrd.pdf --]
[-- Type: application/pdf, Size: 9985 bytes --]

^ permalink raw reply

* [PATCH] misc lparcfg fixes
From: Will Schmidt @ 2006-03-30 21:05 UTC (permalink / raw)
  To: linuxppc-dev, paulus

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

Please apply.

This patch fixed several problems with the lparcfg code.  In case
someone gets a sense of deja-vu, part of this was submitted last Sep, I
thought the changes went in, but either got backed out, or just got
lost. 

First, change the local_buffer declaration to be unsigned char *.  We
had a bad-math problem in a 2.4 tree which was built with a
"-fsigned-char" parm.  I dont believe we ever build with that parm
now-a-days, but to be safe, I'd prefer the declaration be explicit.

Second, fix a bad math calculation for splpar_strlen.   

Third, on the rtas_call for get-system-parameter, pass in
RTAS_DATA_BUF_SIZE for the rtas_data_buf size, instead of letting random
data determine the size.   Until recently, we've had a sufficiently
large 'random data' value get passed in, so the function just happens to
have worked OK.   Now it's getting passed a '0', which causes the
rtas_call to return success, but no data shows up in the buffer.
(oops!).   This was found by the LTC test org.  

This is in a branch of code that only gets run on SPLPAR systems.
Tested on power5 Lpar.  

Signed-off-by: Will Schmidt <willschm@us.ibm.com>



[-- Attachment #2: 22746.diff --]
[-- Type: text/x-patch, Size: 1375 bytes --]

diff -Naur 2.6/arch/powerpc/kernel/lparcfg.c 2.6.mar30/arch/powerpc/kernel/lparcfg.c
--- 2.6/arch/powerpc/kernel/lparcfg.c	2006-03-20 02:15:57.000000000 -0800
+++ 2.6.mar30/arch/powerpc/kernel/lparcfg.c	2006-03-30 12:06:34.323023840 -0800
@@ -37,7 +37,7 @@
 #include <asm/prom.h>
 #include <asm/vdso_datapage.h>
 
-#define MODULE_VERS "1.6"
+#define MODULE_VERS "1.7"
 #define MODULE_NAME "lparcfg"
 
 /* #define LPARCFG_DEBUG */
@@ -242,7 +242,7 @@
 {
 	int call_status;
 
-	char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
+	unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
 	if (!local_buffer) {
 		printk(KERN_ERR "%s %s kmalloc failure at line %d \n",
 		       __FILE__, __FUNCTION__, __LINE__);
@@ -254,7 +254,8 @@
 	call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
 				NULL,
 				SPLPAR_CHARACTERISTICS_TOKEN,
-				__pa(rtas_data_buf));
+				__pa(rtas_data_buf),
+				RTAS_DATA_BUF_SIZE);
 	memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH);
 	spin_unlock(&rtas_data_buf_lock);
 
@@ -275,7 +276,7 @@
 #ifdef LPARCFG_DEBUG
 		printk(KERN_INFO "success calling get-system-parameter \n");
 #endif
-		splpar_strlen = local_buffer[0] * 16 + local_buffer[1];
+		splpar_strlen = local_buffer[0] * 256 + local_buffer[1];
 		local_buffer += 2;	/* step over strlen value */
 
 		memset(workbuffer, 0, SPLPAR_MAXLENGTH);

^ permalink raw reply

* Re: Kernel for MPC Lite 5200 will not compile
From: John Rigby @ 2006-03-30 21:51 UTC (permalink / raw)
  To: Dale Farnsworth; +Cc: Linuxppc-embedded
In-Reply-To: <20060330200509.10908.qmail@farnsworth.org>

Even if the current Freescale code were cleaned up the basic design is
ugly.  The C preprocessor hell it goes through along with the
indirection is a high price to pay for the generalitiy it buys in
terms of the task var/inc setting.

On the licensing side, it has been changed to an MIT license so it can
be included in the kernel but third parties can use it in there non
GPL OSs without problem.

For now lets just stay with your code and I will work on getting other
drivers to use it.

On 30 Mar 2006 20:05:09 -0000, Dale Farnsworth <dale@farnsworth.org> wrote:
> Jon Rigby <jcrigby@gmail.com> wrote:
> > After thinking about this more....I don't want to push getting the offi=
cial
> > Freescale code into the tree.  If Dale's code works as well as the Free=
scale
> > code then lets stay with it because it is a lot cleaner.
>
> Thanks.
>
> > The effort of porting other drivers will hopefully be easier now that
> > I have the experience of having done ATA.
>
> Would Freescale be amenable to working toward a revised, common, API?
> Unfortunately, I didn't find the Freescale Bestcomm API to be clean enoug=
h
> for acceptance into Linux, so changes would be needed.
>
> -Dale
>

^ permalink raw reply

* [PATCH]: e1000: prevent statistics from getting garbled during reset.
From: Linas Vepstas @ 2006-03-30 21:39 UTC (permalink / raw)
  To: john.ronciak, jesse.brandeburg, jeffrey.t.kirsher
  Cc: netdev, linux-pci, Jeff Garzik, linux-kernel, linuxppc-dev


Please review, sign-off/ack, and forward upstream.
--linas

[PATCH]: e1000: prevent statistics from getting garbled during reset.

If a PCI bus error/fault triggers a PCI bus reset, attempts to get the
ethernet packet count statistics from the hardware will fail, returning
garbage data upstream.  This patch skips statistics data collection
if the PCI device is not on the bus. 

This patch presumes that an earlier patch,
[PATCH] PCI Error Recovery: e1000 network device driver
has already been applied.

Signed-off-by: Linas Vepstas <linas@austin.ibm.com>

----
 drivers/net/e1000/e1000_main.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

Index: linux-2.6.16-git6/drivers/net/e1000/e1000_main.c
===================================================================
--- linux-2.6.16-git6.orig/drivers/net/e1000/e1000_main.c	2006-03-30 14:42:33.000000000 -0600
+++ linux-2.6.16-git6/drivers/net/e1000/e1000_main.c	2006-03-30 14:44:52.000000000 -0600
@@ -3069,13 +3069,17 @@ void
 e1000_update_stats(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
+	struct pci_dev *pdev = adapter->pdev;
 	unsigned long flags;
 	uint16_t phy_tmp;
 
 #define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
 
-	/* Prevent stats update while adapter is being reset */
-	if (adapter->link_speed == 0)
+	/* Prevent stats update while adapter is being reset, or if
+	 * the pci connection is down. */
+	if ((adapter->link_speed == 0) ||
+       ((pdev->error_state != 0) &&
+	    (pdev->error_state != pci_channel_io_normal)))
 		return;
 
 	spin_lock_irqsave(&adapter->stats_lock, flags);

^ permalink raw reply

* U-boot CPU post failure on 405gp
From: Martin Hicks @ 2006-03-30 21:11 UTC (permalink / raw)
  To: linuxppc-embedded


I'm using a PPC405gp based board, and using u-boot to boot Linux.  I
recently upgraded toolchains from gcc-3.2 (some timesys build) to a
gcc-3.4.5/glibc-2.3.6 toolchain built with crosstools-0.42

Reading specs from /home/mort/src/targa/powerpc-linux/gcc-3.4.5-glibc-2.3.6/powerpc-405-linux-gnu/bin/../lib/gcc/powerpc-405-linux-gnu/3.4.5/specs
Configured with: /home/mort/src/crosstool-0.42/build/powerpc-405-linux-gnu/gcc-3.4.5-glibc-2.3.6/gcc-3.4.5/configure --target=powerpc-405-linux-gnu --host=i686-host_pc-linux-gnu --prefix=/opt/targa/local/powerpc-linux/gcc-3.4.5-glibc-2.3.6/powerpc-405-linux-gnu --with-cpu=405 --enable-cxx-flags=-mcpu=405 --with-headers=/opt/targa/local/powerpc-linux/gcc-3.4.5-glibc-2.3.6/powerpc-405-linux-gnu/powerpc-405-linux-gnu/include --with-local-prefix=/opt/targa/local/powerpc-linux/gcc-3.4.5-glibc-2.3.6/powerpc-405-linux-gnu/powerpc-405-linux-gnu --disable-nls --enable-threads=posix --enable-symvers=gnu --enable-__cxa_atexit --enable-languages=c,c++ --enable-shared --enable-c99 --enable-long-long
Thread model: posix
gcc version 3.4.5


The problem I'm having is when running the CPU post test on u-boot
1.1.4.  Specifically, in the branch tests.  While doing the first branch
conditional test the computer incorrectly takes the "if (link)" branch
in u-boot/post/cpu/b.c::cpu_post_test_bc()

--- a/post/cpu/b.c
+++ b/post/cpu/b.c
@@ -84,10 +84,14 @@ static int cpu_post_test_bc (ulong cmd, 
     }
     if (ret == 0)
     {
-	if (link)
+        printf("link = %d\n", link);
+        if (link)
 	    ret = lr == (ulong) code + 24 ? 0 : -1;
 	else
 	    ret = lr == 0 ? 0 : -1;
+	if (ret)
+		printf("ret = %d, link = %lx, code = %p, lr = %lx\n",
+		       ret, link, code, lr);
     }
 
     return ret;

---

Running with this small change, I get:

POST cpu link = 0
ret = -1, link = 0, code = 03fa5ab8, lr = 0

It looks clear to me that link == 0, so the test worked fine.

However, if I take away the "static" from the cpu_post_test_bc()
declaration then everything works fine.

I've posted "objdump -dS" output for post/cpu/b.o with and without
cpu_post_test_bc() declared as static at:

http://www.bork.org/~mort/ppcstatic/

Any hints appreciated.  Let me know if any other info is required.
mh

-- 
Martin Hicks || mort@bork.org || PGP/GnuPG: 0x4C7F2BEE

^ permalink raw reply

* Re: 2.6.16 cannot boot on powerbook
From: Étienne Bersac @ 2006-03-30 21:38 UTC (permalink / raw)
  To: Michal Purzynski; +Cc: linuxppc-dev
In-Reply-To: <0a0de86818d24b8f1d6d58c6bcbd3f75@rsbac.org>

Hello,

If it works without video=3Dofonly, i strongly advice you to let the =20
kernel use radeonfb.

Is usplash using psychedelic colors ? If yes, offb is used else =20
radeonfb is in use. Or try using fbdev in xorg.conf to see those =20
flashy colours :) At your own risk.

What problem do you have ?

=C9tienne.=

^ permalink raw reply

* Resubmit munged patch -- [PATCH] Add ATA bestcomm dma support for MPC5200.
From: John Rigby @ 2006-03-30 21:34 UTC (permalink / raw)
  To: Linuxppc-embedded, Sylvain Munaut

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

Dale noticed that the previous patch had been munged my my mailer. 
Sorry about that.

[-- Attachment #2: 0001-Add-ATA-bestcomm-dma-support-for-MPC5200.txt --]
[-- Type: text/plain, Size: 33645 bytes --]

Subject: [PATCH] Add ATA bestcomm dma support for MPC5200.

This works on the Lite5200B platform with some caveats.
The board seems to have a layout issue so the ata signals have
a noise problem.  You need to use an UDMA cable even though
the connector on the board does not allow most UDMA cables to
be plugged in.  To get around this you can remove the key pin
on the board connector or poke a hole in the cable connector.
You also want to use the shortest cable you can get.  I ended up
cutting the cable just past the slave connector.

Even with the above changes some drives will not work.
With the right cable and the right drive you can do UDMA1.

I have not tested this on the old Lite5200 but it is my
understanding that the older silicon has issues that
make UDMA not work.  MDMA should work though.

Signed-off-by: John Rigby <jrigby@freescale.com>

---

 arch/ppc/syslib/bestcomm/Makefile        |    1 
 arch/ppc/syslib/bestcomm/ata.c           |  143 +++++++
 arch/ppc/syslib/bestcomm/ata.h           |   49 ++
 arch/ppc/syslib/bestcomm/bestcomm.c      |    4 
 arch/ppc/syslib/bestcomm/bestcomm.h      |   27 +
 arch/ppc/syslib/bestcomm/sdma_ata_task.c |   61 +++
 arch/ppc/syslib/mpc52xx_setup.c          |    7 
 drivers/ide/Kconfig                      |   11 +
 drivers/ide/ppc/mpc52xx_ide.c            |  640 +++++++++++++++++++++++++++++-
 9 files changed, 915 insertions(+), 28 deletions(-)
 create mode 100644 arch/ppc/syslib/bestcomm/ata.c
 create mode 100644 arch/ppc/syslib/bestcomm/ata.h
 create mode 100644 arch/ppc/syslib/bestcomm/sdma_ata_task.c

01a9cf3296c225320105d26201fe7e86596a2ad5
diff --git a/arch/ppc/syslib/bestcomm/Makefile b/arch/ppc/syslib/bestcomm/Makefile
index 02cc99a..f04c5ad 100644
--- a/arch/ppc/syslib/bestcomm/Makefile
+++ b/arch/ppc/syslib/bestcomm/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_PPC_BESTCOMM) 	+= bestcomm.o
 obj-$(CONFIG_FEC_MPC52xx)	+= sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o
+obj-$(CONFIG_BLK_DEV_MPC52xx_IDE_DMA)	+= sdma_ata_task.o ata.o
diff --git a/arch/ppc/syslib/bestcomm/ata.c b/arch/ppc/syslib/bestcomm/ata.c
new file mode 100644
index 0000000..6feae2e
--- /dev/null
+++ b/arch/ppc/syslib/bestcomm/ata.c
@@ -0,0 +1,143 @@
+/*
+ * arch/ppc/syslib/bestcomm/ata.c
+ *
+ * Driver for MPC52xx processor BestComm ATA controller
+ *
+ * Copyright (C) 2006 Freescale - John Rigby
+ *
+ * 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.
+ *
+ * Patterned after:
+ *    arch/ppc/syslib/bestcomm/fec.c
+ *
+ *    Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *    2003-2004 (c) MontaVista, Software, Inc.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/errno.h>				  
+#include <asm/io.h>
+
+#include <asm/mpc52xx.h>
+
+#include "bestcomm.h"
+#include "ata.h"
+
+/*
+ * Initialize the shared ATA rx/tx task.
+ * Returns task number of ATA task.
+ * Returns -1 on failure
+ */
+int sdma_ata_init(struct sdma *s, int maxbufsize)
+{
+	static int tasknum = -1;
+	static struct sdma_bd2 *bd2 = 0;
+	static u32 bd_pa;
+
+	struct sdma_ata_var *var;
+
+	if (tasknum < 0) {
+		tasknum = sdma_load_task(sdma_ata_task);
+		if (tasknum < 0)
+			return tasknum;
+	}
+
+	if (!bd2) 
+		bd2 = (struct sdma_bd2 *)sdma_sram_alloc(sizeof(*bd2) * s->num_bd,
+								SDMA_BD_ALIGN, &bd_pa);
+	if (!bd2)
+		return -ENOMEM;
+
+	sdma_disable_task(tasknum);
+
+	s->flags = SDMA_FLAGS_BD2;
+	s->tasknum = tasknum;
+	s->bd2 = bd2;
+	s->index = 0;
+	s->outdex = 0;
+	memset(bd2, 0, sizeof(*bd2) * s->num_bd);
+
+	var = (struct sdma_ata_var *)sdma_task_var(tasknum);
+	var->enable		= sdma_io_pa(&sdma.io->tcr[tasknum]);
+	var->bd_base		= bd_pa;
+	var->bd_last		= bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd2);
+	var->bd_start		= bd_pa;
+	var->buffer_size	= maxbufsize;
+
+	printk("here in %s calling sdma_dump ata var is %08x\n", __FUNCTION__, var);
+	sdma_dump();
+
+#if 0
+	/* some tasks may need this set but ata apparently isn't one of them */
+	sdma_set_size(tasknum, 4, 4) /* SrcSz, DstSz */
+#endif
+	sdma_set_task_pragma(tasknum, SDMA_ATA_PRAGMA);
+	sdma_set_task_auto_start(tasknum, tasknum);
+
+	/* clear pending interrupt bits */
+	out_be32(&sdma.io->IntPend, 1<<tasknum);
+
+	out_8(&sdma.io->ipr[SDMA_INITIATOR_ATA_RX], SDMA_IPR_ATA_RX);
+	out_8(&sdma.io->ipr[SDMA_INITIATOR_ATA_TX], SDMA_IPR_ATA_TX);
+
+	return tasknum;
+}
+
+
+/*
+ * Initialize ATA receive task.
+ */
+void sdma_ata_rx_init(struct sdma *s)
+{
+	struct sdma_ata_inc *inc;
+
+	inc = (struct sdma_ata_inc *)sdma_task_inc(s->tasknum);
+	inc->incr_bytes = -(s16)sizeof(u32);
+	inc->incr_src = 0;
+	inc->incr_dst = sizeof(u32);
+
+	sdma_set_initiator(s->tasknum, SDMA_INITIATOR_ATA_RX);
+}
+
+/*
+ * Initialize ATA transmit task.
+ */
+void sdma_ata_tx_init(struct sdma *s)
+{
+	struct sdma_ata_inc *inc;
+
+	inc = (struct sdma_ata_inc *)sdma_task_inc(s->tasknum);
+	inc->incr_bytes	= -(s16)sizeof(u32);
+	inc->incr_src = sizeof(u32);
+	inc->incr_dst = 0;
+
+	sdma_set_initiator(s->tasknum, SDMA_INITIATOR_ATA_TX);
+}
+
+/*
+ * Reset all the ATA task's bds
+ */
+void sdma_ata_reset(struct sdma *s)
+{
+	struct sdma_ata_var *var;
+
+	sdma_reset_buffers2(s);
+	/*
+	 * Always start at the beginning (the ATA task modifies bd_start on writes)
+	 */
+	s->outdex = s->index = 0;
+	var = (struct sdma_ata_var *)sdma_task_var(s->tasknum);
+	var->bd_start = var->bd_base;
+}
+
+EXPORT_SYMBOL(sdma_ata_init);
+EXPORT_SYMBOL(sdma_ata_rx_init);
+EXPORT_SYMBOL(sdma_ata_tx_init);
+EXPORT_SYMBOL(sdma_ata_reset);
diff --git a/arch/ppc/syslib/bestcomm/ata.h b/arch/ppc/syslib/bestcomm/ata.h
new file mode 100644
index 0000000..6f2e99d
--- /dev/null
+++ b/arch/ppc/syslib/bestcomm/ata.h
@@ -0,0 +1,49 @@
+/*
+ * arch/ppc/syslib/bestcomm/ata.h
+ *
+ * Driver for MPC52xx processor BestComm ATA controller
+ *
+ * Copyright (C) 2006 Freescale - John Rigby
+ *
+ * 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.
+ *
+ * Patterned after:
+ *    arch/ppc/syslib/bestcomm/fec.c
+ *
+ *    Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *    2003-2004 (c) MontaVista, Software, Inc.
+ */
+
+#ifndef __BESTCOMM_ATA_H__
+#define __BESTCOMM_ATA_H__
+
+
+/* ata task vars that need to be set before enabling the task */
+struct sdma_ata_var {
+	u32 enable;		/* (u16*) address of task's control register */
+	u32 bd_base;		/* (struct sdma_bd*) beginning of ring buffer */
+	u32 bd_last;		/* (struct sdma_bd*) end of ring buffer */
+	u32 bd_start;		/* (struct sdma_bd*) current bd */
+	u32 buffer_size;	/* size of receive buffer */
+};
+
+/* ata task incs that need to be set before enabling the task */
+struct sdma_ata_inc {
+	u16 pad0;
+	s16 incr_bytes;
+	u16 pad1;
+	s16 incr_dst;
+	u16 pad2;
+	s16 incr_src;
+};
+
+extern int sdma_ata_init(struct sdma *s, int maxbufsize);
+extern void sdma_ata_rx_init(struct sdma *s);
+extern void sdma_ata_tx_init(struct sdma *s);
+extern void sdma_ata_reset(struct sdma *s);
+
+extern u32 sdma_ata_task[];
+
+#endif  /* __BESTCOMM_ATA_H__ */
diff --git a/arch/ppc/syslib/bestcomm/bestcomm.c b/arch/ppc/syslib/bestcomm/bestcomm.c
index 76d5a9b..0f249d6 100644
--- a/arch/ppc/syslib/bestcomm/bestcomm.c
+++ b/arch/ppc/syslib/bestcomm/bestcomm.c
@@ -43,12 +43,12 @@ static spinlock_t sdma_lock = SPIN_LOCK_
 void sdma_dump(void)
 {
 	int i;
-	printk("** SDMA registers: pa = %08x, va = %08x\n", sdma.base_reg_addr, sdma.io);
+
+	printk("** SDMA registers: pa = %08x, va = %08x\n", (u32)sdma.base_reg_addr, (u32)sdma.io);
 	printk("**  taskBar = %08x\n", sdma.io->taskBar);
 	printk("**  currentPointer = %08x\n", sdma.io->currentPointer);
 	printk("**  endPointer = %08x\n", sdma.io->endPointer);
 	printk("**  variablePointer = %08x\n", sdma.io->variablePointer);
-
 	printk("**  IntVect1 = %08x\n", sdma.io->IntVect1);
 	printk("**  IntVect2 = %08x\n", sdma.io->IntVect2);
 	printk("**  PtdCntrl = %08x\n", sdma.io->PtdCntrl);
diff --git a/arch/ppc/syslib/bestcomm/bestcomm.h b/arch/ppc/syslib/bestcomm/bestcomm.h
index 18cb58f..75ff7d2 100644
--- a/arch/ppc/syslib/bestcomm/bestcomm.h
+++ b/arch/ppc/syslib/bestcomm/bestcomm.h
@@ -237,7 +237,7 @@ static inline int sdma_desc_initiator(u3
 static inline void sdma_set_desc_initiator(u32 *desc, int initiator)
 {
 	*desc = (*desc & ~(0x1f << SDMA_DRD_INITIATOR_SHIFT)) |
-			((initiator << SDMA_DRD_INITIATOR_SHIFT) & 0x1f);
+			((initiator & 0x1f) << SDMA_DRD_INITIATOR_SHIFT);
 }
 
 static inline void sdma_submit_buffer(struct sdma *s, void *cookie, void *data,
@@ -284,12 +284,23 @@ static inline void *sdma_retrieve_buffer
 	return cookie;
 }
 
+static inline void sdma_reset_buffers(struct sdma *s)
+{
+	while (!sdma_queue_empty(s)) {
+		s->bd[s->outdex].status = 0;
+		s->bd[s->outdex].data = 0;
+		sdma_retrieve_buffer(s, NULL);
+	}
+	s->index = s->outdex = 0;
+}
+
 static inline void sdma_submit_buffer2(struct sdma *s, void *cookie,
 					void *data1, void *data2, int length)
 {
 #ifdef CONFIG_BESTCOMM_DEBUG
 	BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
 #endif
+
 	s->cookie[s->index] = cookie;
 	s->bd2[s->index].data1 = data1;
 	s->bd2[s->index].data2 = data2;
@@ -312,6 +323,17 @@ static inline void *sdma_retrieve_buffer
 	return cookie;
 }
 
+static inline void sdma_reset_buffers2(struct sdma *s)
+{
+	while (!sdma_queue_empty(s)) {
+		s->bd2[s->outdex].status = 0;
+		s->bd2[s->outdex].data1 = 0;
+		s->bd2[s->outdex].data2 = 0;
+		sdma_retrieve_buffer2(s, NULL);
+	}
+	s->index = s->outdex = 0;
+}
+
 #define SDMA_TASK_MAGIC		0x4243544B	/* 'BCTK' */
 
 /* the size fields are given in number of 32-bit words */
@@ -351,7 +373,7 @@ static inline int sdma_desc_is_drd(u32 d
 				 (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO)	| \
 				 (0 << SDMA_PRAGMA_BIT_PACK)		| \
 				 (0 << SDMA_PRAGMA_BIT_INTEGER)		| \
-				 (1 << SDMA_PRAGMA_BIT_SPECREAD)	| \
+				 (0 << SDMA_PRAGMA_BIT_SPECREAD)	| \
 				 (1 << SDMA_PRAGMA_BIT_CW)		| \
 				 (1 << SDMA_PRAGMA_BIT_RL))
 
@@ -469,6 +491,7 @@ extern int sdma_load_task(u32 *task_imag
 extern void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle);
 extern void sdma_init_bd(struct sdma *s);
 extern void sdma_init_bd2(struct sdma *s);
+extern void sdma_set_initiator(int task, int initiator);
 
 #define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f)))
 
diff --git a/arch/ppc/syslib/bestcomm/sdma_ata_task.c b/arch/ppc/syslib/bestcomm/sdma_ata_task.c
new file mode 100644
index 0000000..5613545
--- /dev/null
+++ b/arch/ppc/syslib/bestcomm/sdma_ata_task.c
@@ -0,0 +1,61 @@
+/*
+ * sdma_ata_task.c
+ *
+ * Created based on bestcom/code_dma/image_rtos1/dma_image.hex
+ */
+
+#include <linux/types.h>
+
+/*
+ * The header consists of the following fields:
+ *	uint32_t	magic;
+ *	uint8_t		desc_size;
+ *	uint8_t		var_size;
+ *	uint8_t		inc_size;
+ *	uint8_t		first_var;
+ *	uint8_t		reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+*/
+
+uint32_t sdma_ata_task[] = {
+	/* header */
+	0x4243544b,
+	0x0e060709,
+	0x00000000,
+	0x00000000,
+
+	/* Task descriptors */
+	0x8198009b, /* LCD: idx0 = var3; idx0 <= var2; idx0 += inc3 */
+	0x13e00c08, /*   DRD1A: var3 = var1; FN=0 MORE init=31 WS=0 RS=0 */
+	0xb8000264, /*   LCD: idx1 = *idx0, idx2 = var0; idx1 < var9; idx1 += inc4, idx2 += inc4 */
+	0x10000f00, /*     DRD1A: var3 = idx0; FN=0 MORE init=0 WS=0 RS=0 */
+	0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
+	0x0c8cfc8a, /*     DRD2B1: *idx2 = EU3(); EU3(*idx2,var10)  */
+	0xd8988240, /*   LCDEXT: idx1 = idx1; idx1 > var9; idx1 += inc0 */
+	0xf845e011, /*   LCDEXT: idx2 = *(idx0 + var00000015); ; idx2 += inc2 */
+	0xb845e00a, /*   LCD: idx3 = *(idx0 + var00000019); ; idx3 += inc1 */
+	0x0bfecf90, /*     DRD1A: *idx3 = *idx2; FN=0 TFD init=31 WS=3 RS=3 */
+	0x9898802d, /*   LCD: idx1 = idx1; idx1 once var0; idx1 += inc5 */
+	0x64000005, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 INT EXT init=0 WS=0 RS=0 */
+	0x0c0cf849, /*     DRD2B1: *idx0 = EU3(); EU3(idx1,var9)  */
+	0x000001f8, /* NOP */
+
+
+	/* VAR[9]-VAR[14] */
+	0x40000000,
+	0x7fff7fff,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+
+	/* INC[0]-INC[6] */
+	0x40000000,
+	0xe0000000,
+	0xe0000000,
+	0xa000000c,
+	0x20000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/arch/ppc/syslib/mpc52xx_setup.c b/arch/ppc/syslib/mpc52xx_setup.c
index 508b241..3c9cd42 100644
--- a/arch/ppc/syslib/mpc52xx_setup.c
+++ b/arch/ppc/syslib/mpc52xx_setup.c
@@ -220,7 +220,6 @@ mpc52xx_calibrate_decr(void)
 	tb_to_us = mulhwu_scale_factor(xlbfreq / divisor, 1000000);
 }
 
-
 void __init
 mpc52xx_setup_cpu(void)
 {
@@ -247,8 +246,9 @@ mpc52xx_setup_cpu(void)
 		out_be16(&cdm->fd_counters, 0x5555);
 
 	/* Configure the XLB Arbiter priorities */
-	out_be32(&xlb->master_pri_enable, 0xff);
-	out_be32(&xlb->master_priority, 0x11111111);
+	/* Give PPC and BestComm the same priority on the XLB */
+	out_be32(&xlb->master_pri_enable, 0xf);
+	out_be32(&xlb->master_priority, 0x00007131);
 
 	/* Enable ram snooping for 1GB window */
 	out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_SNOOP);
@@ -265,7 +265,6 @@ unmap_regs:
 	if (xlb)  iounmap(xlb);
 }
 
-
 int mpc52xx_match_psc_function(int psc_idx, const char *func)
 {
 	struct mpc52xx_psc_func *cf = mpc52xx_psc_functions;
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index e391cee..6ecaee7 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -973,6 +973,17 @@ config BLK_DEV_MPC52xx_IDE
 	tristate "MPC52xx Builtin IDE support"
 	depends on PPC_MPC52xx && IDE=y
 
+config BLK_DEV_MPC52xx_IDE_MDMA
+	bool "MDMA support"
+	depends on BLK_DEV_MPC52xx_IDE
+
+config BLK_DEV_MPC52xx_IDE_UDMA
+	bool "UDMA support"
+	depends on BLK_DEV_MPC52xx_IDE
+
+config BLK_DEV_MPC52xx_IDE_DMA
+	def_bool BLK_DEV_MPC52xx_IDE_UDMA || BLK_DEV_MPC52xx_IDE_MDMA
+
 # no isa -> no vlb
 config IDE_CHIPSETS
 	bool "Other IDE chipset support"
diff --git a/drivers/ide/ppc/mpc52xx_ide.c b/drivers/ide/ppc/mpc52xx_ide.c
index 5970f7b..7ab1bcc 100644
--- a/drivers/ide/ppc/mpc52xx_ide.c
+++ b/drivers/ide/ppc/mpc52xx_ide.c
@@ -5,6 +5,7 @@
  *
  *
  * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2005,2006 Freescale - Bernard Kuhn, John Rigby
  * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
  *
  * This file is licensed under the terms of the GNU General Public License
@@ -24,8 +25,28 @@
 #include <asm/io.h>
 #include <asm/ppcboot.h>
 
+#include <syslib/bestcomm/bestcomm.h>
+#include <syslib/bestcomm/ata.h>
+
 #include "mpc52xx_ide.h"
 
+#define CONFIG_BLK_DEV_IDE_MPC52xx_LIMIT_TO_UDMA1
+#define CONFIG_BLK_DEV_IDE_MPC52xx_SHOWDETAILS 1
+
+#define MAX_DMA_BUFFERS 128
+#define MAX_DMA_BUFFER_SIZE 0x20000
+
+#undef DEBUG
+#define DEBUG
+
+#undef DPRINTK
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+typedef unsigned long ide_ioreg_t;
 
 
 /* Private structures used by the driver */
@@ -42,11 +63,6 @@ struct mpc52xx_ata_timings {
 	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 */
@@ -58,9 +74,166 @@ static int ataspec_t2i[5]   = {  0,   0,
 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 */
+/* Helper to compute timing parameters */
 #define CALC_CLK_VALUE_UP(c,v) (((v) + c - 1) / c)
 
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_MDMA
+
+/* ATAPI-4 MDMA specs (in clocks) */
+struct mdmaspec {
+	u32 t0M[3];
+	u32 td[3];
+	u32 th[3];
+	u32 tj[3];
+	u32 tkw[3];
+	u32 tm[3];
+	u32 tn[3];
+};
+
+static struct mdmaspec mdmaspec66 = {
+	{32,  10,  8},
+	{15,  6,   5},
+	{2,   1,   1},
+	{2,   1,   1},
+	{15,  4,   2},
+	{4,   2,   2},
+	{1,   1,   1}
+};
+
+static struct mdmaspec mdmaspec132 = {
+	{64,  20,  16},
+	{29,  11,  10},
+	{3,   2,   2},
+	{3,   1,   1},
+	{29,  7,   4},
+	{7,   4,   4},
+	{2,   1,   1}
+};
+
+#endif
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_UDMA
+
+/* ATAPI-4 UDMA specs (in clocks) */
+struct udmaspec {
+	u32 tcyc[6];
+	u32 t2cyc[6];
+	u32 tds[6];
+	u32 tdh[6];
+	u32 tdvs[6];
+	u32 tdvh[6];
+	u32 tfs_min[6];
+	u32 tli_max[6];
+	u32 tmli[6];
+	u32 taz[6];
+	u32 tzah[6];
+	u32 tenv_min[6];
+	u32 tsr[6];
+	u32 trfs[6];
+	u32 trp[6];
+	u32 tack[6];
+	u32 tss[6];
+};
+
+struct udmaspec udmaspec66 = {
+	{8, 5,  4,   3,   2,  2},
+	{16, 11,  8,   6,   4 , 2},
+	{1, 1,  1,   1,   1,  1},
+	{1, 1,  1,   1,   1,  1},
+	{5, 4,  3,   2,   1,  1},
+	{1, 1,  1,   1,   1,  1},
+	{16, 14,  12,  9,   8,  6},
+	{10, 10,  10,  7,   8,  5},
+	{2, 2,  2,   2,   2,  2},
+	{1, 1,  1,   1,   1,  1},
+	{2, 2,  2,   2,   2,  2},
+	{2, 2,  2,   2,   2,  2},
+	{3, 2,  2,   2,   2,  2},
+	{5, 5,  4,   4,   4,  4},
+	{11, 9,  7,   7,   7,  6},
+	{2, 2,  2,   2,   2,  2},
+	{4, 4,  4,   4,   4,  4}
+};
+
+struct udmaspec udmaspec132 = {
+	{15, 10,  6,   7,   2,  3},
+	{31, 21,  12,  12,  5,  6},
+	{2, 2,  1,   1,   0,  1},
+	{1, 1,  1,   1,   0,  1},
+	{10, 7,  5,   3,   1,  1},
+	{1, 1,  1,   1,   1,  1},
+	{30, 27,  23,  15,  16, 12},
+	{20, 20,  20,  13,  14, 10},
+	{3, 3,  3,   3,   2,  3},
+	{2, 2,  2,   2,   1,  2},
+	{3, 3,  3,   3,   2,  3},
+	{3, 3,  3,   3,   2,  3},
+	{7, 4,  3,   3,   2,  3},
+	{10, 10,  8,   8,   7,  7},
+	{22, 17,  14,  14, 13, 12},
+	{3, 3,  3,   3,   2,  3},
+	{7, 7,  7,   7,   6,  7},
+};
+
+
+#endif
+
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+
+struct mpc52xx_ide_priv {
+	unsigned int ipb_period;	/* in ps */
+	struct mpc52xx_ata __iomem *ata_regs;
+	struct mpc52xx_ata_timings  timings[2];
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+	struct sdma *sdma;
+	struct udmaspec *udmaspec;
+	struct mdmaspec *mdmaspec;
+	int mpc52xx_ata_dma_last_write;
+#endif
+};
+
+static u8
+mpc52xx_dma2pio (u8 xfer_rate)
+{
+	switch(xfer_rate) {
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			//return 3;
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+#else
+		case XFER_PIO_4:
+			return 4;
+		case XFER_PIO_3:
+			return 3;
+		case XFER_PIO_2:
+			return 2;
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
 
 /* ======================================================================== */
 /* IDE Driver & Aux functions                                               */
@@ -100,6 +273,99 @@ mpc52xx_ide_compute_pio_timing(
 	timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8);
 }
 
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_UDMA
+
+static void mpc52xx_ide_calc_udma_timings(ide_drive_t *drive, u8 speed)
+{
+	struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+
+	int which = drive->select.b.unit & 0x01;
+	u32 t2cyc, tcyc, tds, tdh, tdvs, tdvh, tfs, tli, tmli, taz, tenv, tsr, tss, trfs, trp, tack, tzah;
+
+	t2cyc = priv->udmaspec->t2cyc[speed];
+	tcyc = priv->udmaspec->tcyc[speed];
+	tds = priv->udmaspec->tds[speed];
+	tdh = priv->udmaspec->tdh[speed];
+	tdvs = priv->udmaspec->tdvs[speed];
+	tdvh = priv->udmaspec->tdvh[speed];
+	tfs = priv->udmaspec->tfs_min[speed];
+	tmli = priv->udmaspec->tmli[speed];
+	tenv = priv->udmaspec->tenv_min[speed];
+	tss = priv->udmaspec->tss[speed];
+	trp = priv->udmaspec->trp[speed];
+	tack = priv->udmaspec->tack[speed];
+	tzah = priv->udmaspec->tzah[speed];
+	taz = priv->udmaspec->taz[speed];
+	trfs = priv->udmaspec->trfs[speed];
+	tsr = priv->udmaspec->tsr[speed];
+	tli = priv->udmaspec->tli_max[speed];
+
+	DPRINTK ("UDMA t2cyc = %d\n", t2cyc);
+	DPRINTK ("UDMA tcyc  = %d\n", tcyc);
+	DPRINTK ("UDMA tds   = %d\n", tds);
+	DPRINTK ("UDMA tdh   = %d\n", tdh);
+	DPRINTK ("UDMA tdvs  = %d\n", tdvs);
+	DPRINTK ("UDMA tdvh  = %d\n", tdvh);
+	DPRINTK ("UDMA tfs   = %d\n", tfs);
+	DPRINTK ("UDMA tli   = %d\n", tli);
+	DPRINTK ("UDMA tmli  = %d\n", tmli);
+	DPRINTK ("UDMA taz   = %d\n", taz);
+	DPRINTK ("UDMA tenv  = %d\n", tenv);
+	DPRINTK ("UDMA tsr   = %d\n", tsr);
+	DPRINTK ("UDMA tss   = %d\n", tss);
+	DPRINTK ("UDMA trfs  = %d\n", trfs);
+	DPRINTK ("UDMA trp   = %d\n", trp);
+	DPRINTK ("UDMA tack  = %d\n", tack);
+	DPRINTK ("UDMA tzah  = %d\n", tzah);
+
+	priv->timings[which].udma1 = (t2cyc << 24) | (tcyc << 16) | (tds << 8) | (tdh);
+	priv->timings[which].udma2 = (tdvs << 24) | (tdvh << 16) | (tfs << 8) | (tli);
+	priv->timings[which].udma3 = (tmli << 24) | (taz << 16) | (tenv << 8) | (tsr);
+	priv->timings[which].udma4 = (tss << 24) | (trfs << 16) | (trp << 8) | (tack);
+	priv->timings[which].udma5 = (tzah << 24);
+
+	priv->timings[which].using_udma = 1;
+}
+
+#endif
+
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_UDMA
+
+static void mpc52xx_ide_calc_mdma_timings(ide_drive_t *drive, u8 speed)
+{
+	struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+	int which = drive->select.b.unit & 0x01;
+	u32 t0M, td, tkw, tm, th, tj, tn;
+
+	t0M = priv->mdmaspec->t0M[speed];
+	td = priv->mdmaspec->td[speed];
+	tkw = priv->mdmaspec->tkw[speed];
+	tm = priv->mdmaspec->tm[speed];
+	th = priv->mdmaspec->th[speed];
+	tj = priv->mdmaspec->tj[speed];
+	tn = priv->mdmaspec->tn[speed];
+
+	DPRINTK ("t0M = %d\n", t0M);
+	DPRINTK ("td  = %d\n", td);
+	DPRINTK ("tkw = %d\n", tkw);
+	DPRINTK ("tm  = %d\n", tm);
+	DPRINTK ("th  = %d\n", th);
+	DPRINTK ("tj  = %d\n", tj);
+	DPRINTK ("tn  = %d\n", tn);
+
+	priv->timings[which].mdma1 = (t0M << 24) | (td << 16) | (tkw << 8) | (tm);
+	priv->timings[which].mdma2 = (th << 24) | (tj << 16) | (tn << 8);
+
+	priv->timings[which].using_udma = 0;
+}
+
+#endif
+
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+
 
 static void
 mpc52xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
@@ -117,25 +383,51 @@ mpc52xx_ide_tuneproc(ide_drive_t *drive,
 	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);
+	/* Only call ide_config_drive_speed in speedproc */
 }
 
 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);
+#ifdef CONFIG_BLK_DEV_IDE_MPC52xx_LIMIT_TO_UDMA1
+	if (speed > XFER_UDMA_1)
+		speed = XFER_UDMA_1;
+#else
+	if (speed > XFER_UDMA_4)
+		speed = XFER_UDMA_4;
+#endif
 
-	return 1;
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_UDMA
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			printk("%s: Setting UDMA %d timings\n", drive->name, speed - XFER_UDMA_0);
+			mpc52xx_ide_calc_udma_timings(drive, speed - XFER_UDMA_0);
+			break;
+#endif
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_MDMA
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			printk("%s: Setting MDMA %d timings\n", drive->name, speed - XFER_MW_DMA_0);
+			mpc52xx_ide_calc_mdma_timings(drive, speed - XFER_MW_DMA_0);
+			break;
+#endif
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:
+			break;
+		default:
+			return -EINVAL;
+	}
+	mpc52xx_ide_tuneproc(drive, mpc52xx_dma2pio(speed));
+	return ide_config_drive_speed(drive, speed);
 }
 
 static void
@@ -151,6 +443,225 @@ mpc52xx_ide_selectproc(ide_drive_t *driv
 }
 
 
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+
+static int mpc52xx_ide_dma_check(ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, 2);
+
+	DPRINTK("dma_check: speed=%x\n", speed);
+	if (speed == 0)
+		return -1;
+	mpc52xx_ide_speedproc(drive, speed);
+
+	if (ide_dma_enable(drive))
+		drive->using_dma = 1;
+	else
+		drive->using_dma = 0;
+
+	return 0;
+}
+
+static int mpc52xx_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+{
+	struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+	struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+	struct scatterlist *sg;
+	ide_hwif_t *hwif = HWIF(drive);
+	int i, count = 0;
+
+	/* Build sglist */
+	hwif->sg_nents = i = ide_build_sglist(drive, rq);
+	if (!hwif->sg_nents)
+		return 0;
+
+	if (hwif->sg_dma_direction == PCI_DMA_FROMDEVICE) {
+	    sdma_ata_rx_init(priv->sdma);
+	} else {
+	    sdma_ata_tx_init(priv->sdma);
+	}
+
+
+	sg = hwif->sg_table;
+	while (i && sg_dma_len(sg)) {
+		u32 cur_addr;
+		u32 cur_len;
+
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		while (cur_len) {
+			unsigned int tc  = (cur_len <= MAX_DMA_BUFFER_SIZE) ? cur_len: MAX_DMA_BUFFER_SIZE;
+
+			if (hwif->sg_dma_direction == PCI_DMA_FROMDEVICE) {
+				invalidate_dcache_range((u32)phys_to_virt(cur_addr), (u32)phys_to_virt(cur_addr)+(u32)tc);
+				sdma_submit_buffer2(priv->sdma, phys_to_virt(cur_addr), (void *)&regs->fifo_data, (void *)cur_addr, tc);
+			} else {
+				flush_dcache_range((u32)phys_to_virt(cur_addr), (u32)phys_to_virt(cur_addr)+(u32)tc);
+				sdma_submit_buffer2(priv->sdma, phys_to_virt(cur_addr), (void *)cur_addr, (void *)&regs->fifo_data, tc);
+			}
+
+			//DPRINTK("SDMA setup @%08x, l: %x, nextbd: %d !\n", cur_addr, tc, next_bd);
+			cur_addr += tc;
+			cur_len -= tc;
+			count++;
+			if(count == MAX_DMA_BUFFERS) {
+				printk(KERN_WARNING "%s: DMA table too small\n",drive->name);
+				goto use_pio_instead;
+			};
+		}
+		sg++;
+		i--;
+	}
+
+	return 1;
+
+use_pio_instead:
+	sdma_ata_reset(priv->sdma);
+
+	pci_unmap_sg(hwif->pci_dev,
+			hwif->sg_table,
+			hwif->sg_nents,
+			hwif->sg_dma_direction);
+
+	return 0; /* revert to PIO for this request */
+}
+
+
+/* Teardown mappings after DMA has completed.  */
+static void mpc52xx_ide_destroy_dmatable (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = hwif->sg_nents;
+
+	if (nents) {
+		pci_unmap_sg(dev, sg, nents, hwif->sg_dma_direction);
+		hwif->sg_nents = 0;
+	}
+}
+
+
+static void mpc52xx_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+	struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+	struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+
+	mpc52xx_ide_wait_tip_bit_clear(regs);
+
+	/* issue cmd to drive */
+	ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL);
+}
+
+
+static int mpc52xx_ide_dma_setup(ide_drive_t *drive)
+{
+	struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+	struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+	ide_hwif_t *hwif = HWIF(drive);
+	struct request *rq = HWGROUP(drive)->rq;
+	int which = drive->select.b.unit & 0x01;
+	u8 dma_mode;
+
+	if (!mpc52xx_ide_build_dmatable(drive, rq)) {
+		ide_map_sg(drive, rq);
+		return 1;
+	};
+
+	if(hwif->sg_dma_direction == PCI_DMA_FROMDEVICE) { /* read */
+
+		dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ | MPC52xx_ATA_DMAMODE_FE;
+
+		/* Setup FIFO if direction changed */
+		if (priv->mpc52xx_ata_dma_last_write) {
+			priv->mpc52xx_ata_dma_last_write = 0;
+			mpc52xx_ide_wait_tip_bit_clear(regs);
+			out_8(&regs->dma_mode, MPC52xx_ATA_DMAMODE_FR);
+			/* Configure it with granularity to 7 like sample code */
+			out_8(&regs->fifo_control, 7);
+			out_be16(&regs->fifo_alarm, 128);
+		}
+	}
+	else {
+
+		dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE;
+
+		/* Setup FIFO if direction changed */
+		if (!priv->mpc52xx_ata_dma_last_write) {
+			priv->mpc52xx_ata_dma_last_write = 1;
+			mpc52xx_ide_wait_tip_bit_clear(regs);
+			/* Configure FIFO with granularity to 4 like sample code */
+			out_8(&regs->fifo_control, 4);
+			//out_be16(&regs->fifo_alarm, 256);
+			out_be16(&regs->fifo_alarm, 128);
+		}
+	};
+
+	if (priv->timings[which].using_udma)
+		dma_mode |= MPC52xx_ATA_DMAMODE_UDMA;
+
+	mpc52xx_ide_wait_tip_bit_clear(regs);
+	out_8(&regs->dma_mode, dma_mode);
+
+	drive->waiting_for_dma = 1;
+
+	return 0;
+};
+
+static void mpc52xx_ide_dma_start(ide_drive_t *drive)
+{
+	struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+	extern void xlb_clear(void);
+
+	xlb_clear();
+	sdma_set_task_auto_start(priv->sdma->tasknum, priv->sdma->tasknum);
+	sdma_enable(priv->sdma);
+}
+
+
+static int mpc52xx_ide_dma_end(ide_drive_t *drive)
+{
+	struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+
+	drive->waiting_for_dma = 0;
+
+	sdma_disable(priv->sdma);
+	sdma_clear_irq(priv->sdma);
+	sdma_ata_reset(priv->sdma);
+	mpc52xx_ide_destroy_dmatable(drive);
+
+	return 0;
+}
+
+
+static int mpc52xx_ide_dma_test_irq(ide_drive_t *drive)
+{
+	return (drive->waiting_for_dma);
+}
+
+
+static int mpc52xx_ide_dma_host_off(ide_drive_t *drive)
+{
+	return 0;
+}
+
+
+static int mpc52xx_ide_dma_host_on(ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int mpc52xx_ide_dma_lostirq(ide_drive_t *drive)
+{
+	printk(KERN_ERR "%s: lost interrupt\n", drive->name);
+	return 0;
+}
+
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+
+
 static int
 mpc52xx_ide_setup(
 	struct mpc52xx_ata __iomem *regs, struct mpc52xx_ide_priv *priv)
@@ -181,6 +692,21 @@ mpc52xx_ide_setup(
 	tslot = CALC_CLK_VALUE_UP(priv->ipb_period, 1000000);
 	out_be32(&regs->share_cnt, tslot << 16);
 
+#ifdef CONFIG_BLK_DEV_IDE_MPC52xx_SHOWDETAILS
+	printk("ipb=%dMHz, set clock period to %d ps\n",(int)(bd->bi_ipbfreq/1000000), 
+			priv->ipb_period);
+#endif
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+	if(bd->bi_ipbfreq/1000000 == 66) {
+		priv->mdmaspec = &mdmaspec66;
+		priv->udmaspec = &udmaspec66;
+	} else {
+		priv->mdmaspec = &mdmaspec132;
+		priv->udmaspec = &udmaspec132;
+	}
+#endif
+
 	/* Init imings to PIO0 (safest) */
 	memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
 
@@ -189,9 +715,35 @@ mpc52xx_ide_setup(
 
 	mpc52xx_ide_apply_timing(regs, &priv->timings[0]);
 
+#ifdef CONFIG_BLK_DEV_IDE_MPC52xx_SHOWDETAILS
+	printk("GPIO config: %08x\n", in_be32((u32 *)0xf0000b00));
+	printk("ATA invalid: %08x\n", in_be32((u32 *)0xf0003a2c));
+	printk("ATA hostcnf: %08x\n", in_be32((u32 *)0xf0003a00));
+	printk("ATA pio1   : %08x\n", in_be32((u32 *)0xf0003a08));
+	printk("ATA pio2   : %08x\n", in_be32((u32 *)0xf0003a0c));
+	printk("XLB Arb cnf: %08x\n", in_be32((u32 *)0xf0001f40));
+#endif
+
 	return 0;
 }
 
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+static int
+mpc52xx_ata_sdma_setup(struct mpc52xx_ide_priv *priv)
+{
+	int rv = 0;
+
+	priv->sdma = sdma_alloc(MAX_DMA_BUFFERS);
+	if (!priv->sdma) {
+		return -ENOMEM;
+	}
+
+	(void) sdma_ata_init(priv->sdma, MAX_DMA_BUFFER_SIZE);
+
+	return rv;
+}
+#endif
+
 static void
 mpc52xx_ide_setup_hwif_ports(hw_regs_t *hw, struct mpc52xx_ata __iomem *regs)
 {
@@ -218,7 +770,7 @@ mpc52xx_ide_probe(struct platform_device
 {
 	/* Vars */
 	ide_hwif_t *hwif;
-	struct mpc52xx_ide_priv *priv;
+	struct mpc52xx_ide_priv *priv = NULL;
 	struct mpc52xx_gpio __iomem *gpio_regs = NULL;
 	struct mpc52xx_ata __iomem *ata_regs = NULL;
 	int ata_irq;
@@ -284,6 +836,7 @@ mpc52xx_ide_probe(struct platform_device
 		goto error;
 	}
 
+	memset(priv, 0, sizeof *priv);
 	priv->ata_regs = ata_regs;
 
 	/* Setup the ATA controller */
@@ -292,6 +845,13 @@ mpc52xx_ide_probe(struct platform_device
 		printk(KERN_ERR "mpc52xx-ide: Controller setup failed !\n");
 		goto error;
 	}
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+	rv = mpc52xx_ata_sdma_setup(priv);
+	if (rv) {
+		printk(KERN_ERR "mpc52xx-ide: SDMA setup failed !\n");
+		goto error;
+	}
+#endif
 
 	/* Setup the hwif structure */
 	hwif->irq = ata_irq;
@@ -325,6 +885,38 @@ mpc52xx_ide_probe(struct platform_device
 	hwif->drives[1].autodma = hwif->autodma;
 	hwif->drives[1].no_io_32bit = 1;	/* Anyone tried ? */
 
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+
+	hwif->atapi_dma = 1;
+	hwif->autodma = 1;
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_MDMA
+	hwif->mwdma_mask = 0x07;
+#endif
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_UDMA
+	hwif->ultra_mask = 0x1F;
+#endif
+	hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
+	hwif->ide_dma_on = &__ide_dma_on;
+	hwif->ide_dma_check = &mpc52xx_ide_dma_check;
+	hwif->dma_setup = &mpc52xx_ide_dma_setup;
+	hwif->dma_exec_cmd = &mpc52xx_ide_dma_exec_cmd;
+	hwif->dma_start = &mpc52xx_ide_dma_start;
+	hwif->ide_dma_end = &mpc52xx_ide_dma_end;
+	hwif->ide_dma_test_irq = &mpc52xx_ide_dma_test_irq;
+	hwif->ide_dma_host_off = &mpc52xx_ide_dma_host_off;
+	hwif->ide_dma_host_on = &mpc52xx_ide_dma_host_on;
+	hwif->ide_dma_timeout = &__ide_dma_timeout;
+	hwif->ide_dma_lostirq = &mpc52xx_ide_dma_lostirq;
+
+#ifndef CONFIG_BLK_DEV_IDE_MPC52xx_LIMIT_TO_UDMA1
+	hwif->udma_four = 1;
+#endif
+	hwif->hwif_data = priv;
+
+	priv->mpc52xx_ata_dma_last_write = 1;
+
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+
 	hwif->hwif_data = priv;
 	platform_set_drvdata(dev, hwif);
 
@@ -346,6 +938,14 @@ error:
 
 	release_mem_region(res_mem->start, sizeof(struct mpc52xx_ata));
 
+	if (priv) {
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+		if (priv->sdma)	sdma_free(priv->sdma);
+#endif
+		kfree(priv);
+	}
+		
+
 	return rv;
 }
 
-- 
1.1.3

^ permalink raw reply related

* [PATCH] powerpc/pseries: fix device name printing, again.
From: Linas Vepstas @ 2006-03-30 21:27 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, linux-kernel


Paul, please apply and send upstram.

--linas

[PATCH] powerpc/pseries: fix device name printing, again.

The recent patch to print device names in EEH reset messages
was lacking ... this patch works better.

Signed-off-by: Linas Vepstas <linas@linas.org>

----
 arch/powerpc/platforms/pseries/eeh_driver.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)

Index: linux-2.6.16-git6/arch/powerpc/platforms/pseries/eeh_driver.c
===================================================================
--- linux-2.6.16-git6.orig/arch/powerpc/platforms/pseries/eeh_driver.c	2006-03-30 14:43:51.000000000 -0600
+++ linux-2.6.16-git6/arch/powerpc/platforms/pseries/eeh_driver.c	2006-03-30 14:47:31.000000000 -0600
@@ -292,9 +292,10 @@ struct pci_dn * handle_eeh_events (struc
 	frozen_pdn = PCI_DN(frozen_dn);
 	frozen_pdn->eeh_freeze_count++;
 
-	pci_str = pci_name (frozen_pdn->pcidev);
-	drv_str = pcid_name (frozen_pdn->pcidev);
-	if (!pci_str) {
+	if (frozen_pdn->pcidev) {
+		pci_str = pci_name (frozen_pdn->pcidev);
+		drv_str = pcid_name (frozen_pdn->pcidev);
+	} else {
 		pci_str = pci_name (event->dev);
 		drv_str = pcid_name (event->dev);
 	}

^ permalink raw reply

* [PATCH] powerpc: Extends HCALL interface for InfiniBand usage
From: Heiko J Schick @ 2006-03-30 20:47 UTC (permalink / raw)
  To: paulus, segher, linuxppc-dev

Hello,

this patch extends the HCALL interface for InfiniBand usage. I've
made the patch against the linux-2.6 git tree and Segher's patch:
[PATCH] Change H_StudlyCaps to H_SHOUTING_CAPS

We moved this into the common powerpc code based on comments we
got after posting the first eHCA InfiniBand device driver patch.

  arch/powerpc/platforms/pseries/hvCall.S |  100 ++++++++++++++++++++++++++++++++
  arch/powerpc/platforms/pseries/lpar.c   |    3
  include/asm-powerpc/hvcall.h            |  100 ++++++++++++++++++++++++++++++++
  3 files changed, 202 insertions(+), 1 deletion(-)

Signed-of-by: Heiko j Schick <schickhj@de.ibm.com>


diff -Nurpw linux-2.6-hcall/arch/powerpc/platforms/pseries/hvCall.S linux-2.6-hcallib/arch/powerpc/platforms/pseries/hvCall.S
--- linux-2.6-hcall/arch/powerpc/platforms/pseries/hvCall.S	2006-03-30 21:53:19.000000000 +0200
+++ linux-2.6-hcallib/arch/powerpc/platforms/pseries/hvCall.S	2006-03-30 22:19:43.462047744 +0200
@@ -127,3 +127,103 @@ _GLOBAL(plpar_hcall_4out)

  	mtcrf	0xff,r0
  	blr				/* return r3 = status */
+
+/* plpar_hcall_7arg_7ret(unsigned long opcode,		R3
+			 unsigned long arg1,		R4
+			 unsigned long arg2,		R5
+			 unsigned long arg3,		R6
+			 unsigned long arg4,		R7
+			 unsigned long arg5,		R8
+			 unsigned long arg6,		R9
+			 unsigned long arg7,		R10
+			 unsigned long *out1,		112(R1)
+			 unsigned long *out2,		110(R1)
+			 unsigned long *out3,		108(R1)
+			 unsigned long *out4,		106(R1)
+			 unsigned long *out5,		104(R1)
+			 unsigned long *out6,		102(R1)
+			 unsigned long *out7);		100(R1)
+*/
+_GLOBAL(plpar_hcall_7arg_7ret)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	HVSC				/* invoke the hypervisor */
+
+	lwz	r0,8(r1)
+
+	ld	r11,STK_PARM(r11)(r1)	/* Fetch r4 ret arg */
+	std	r4,0(r11)
+	ld	r11,STK_PARM(r12)(r1)	/* Fetch r5 ret arg */
+	std	r5,0(r11)
+	ld	r11,STK_PARM(r13)(r1)	/* Fetch r6 ret arg */
+	std	r6,0(r11)
+	ld	r11,STK_PARM(r14)(r1)	/* Fetch r7 ret arg */
+	std	r7,0(r11)
+	ld	r11,STK_PARM(r15)(r1)	/* Fetch r8 ret arg */
+	std	r8,0(r11)
+	ld	r11,STK_PARM(r16)(r1)	/* Fetch r9 ret arg */
+	std	r9,0(r11)
+	ld	r11,STK_PARM(r17)(r1)	/* Fetch r10 ret arg */
+	std	r10,0(r11)
+
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
+
+/* plpar_hcall_9arg_9ret(unsigned long opcode,		R3
+			 unsigned long arg1,		R4
+			 unsigned long arg2,		R5
+			 unsigned long arg3,		R6
+			 unsigned long arg4,		R7
+			 unsigned long arg5,		R8
+			 unsigned long arg6,		R9
+			 unsigned long arg7,		R10
+			 unsigned long arg8,		112(R1)
+			 unsigned long arg9,		110(R1)
+			 unsigned long *out1,		108(R1)
+			 unsigned long *out2,		106(R1)
+			 unsigned long *out3,		104(R1)
+			 unsigned long *out4,		102(R1)
+			 unsigned long *out5,		100(R1)
+			 unsigned long *out6,		 98(R1)
+			 unsigned long *out7);		 96(R1)
+			 unsigned long *out8,		 94(R1)
+		         unsigned long *out9,            92(R1)
+*/
+_GLOBAL(plpar_hcall_9arg_9ret)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	ld	r11,STK_PARM(r11)(r1)	 /* put arg8 in R11 */
+	ld	r12,STK_PARM(r12)(r1)    /* put arg9 in R12 */
+
+	HVSC				/* invoke the hypervisor */
+
+	ld	r0,STK_PARM(r13)(r1)	/* Fetch r4 ret arg */
+	stdx	r4,r0,r0
+	ld	r0,STK_PARM(r14)(r1)	/* Fetch r5 ret arg */
+	stdx	r5,r0,r0
+	ld	r0,STK_PARM(r15)(r1)	/* Fetch r6 ret arg */
+	stdx	r6,r0,r0
+	ld	r0,STK_PARM(r16)(r1)	/* Fetch r7 ret arg */
+	stdx	r7,r0,r0
+	ld	r0,STK_PARM(r17)(r1)	/* Fetch r8 ret arg */
+	stdx	r8,r0,r0
+	ld	r0,STK_PARM(r18)(r1)	/* Fetch r9 ret arg */
+	stdx	r9,r0,r0
+	ld	r0,STK_PARM(r19)(r1)	/* Fetch r10 ret arg */
+	stdx	r10,r0,r0
+	ld	r0,STK_PARM(r20)(r1)	/* Fetch r11 ret arg */
+	stdx	r11,r0,r0
+	ld	r0,STK_PARM(r21)(r1)	/* Fetch r12 ret arg */
+	stdx	r12,r0,r0
+
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
diff -Nurpw linux-2.6-hcall/arch/powerpc/platforms/pseries/lpar.c linux-2.6-hcallib/arch/powerpc/platforms/pseries/lpar.c
--- linux-2.6-hcall/arch/powerpc/platforms/pseries/lpar.c	2006-03-30 21:55:05.000000000 +0200
+++ linux-2.6-hcallib/arch/powerpc/platforms/pseries/lpar.c	2006-03-30 21:58:00.000000000 +0200
@@ -54,7 +54,8 @@ EXPORT_SYMBOL(plpar_hcall);
  EXPORT_SYMBOL(plpar_hcall_4out);
  EXPORT_SYMBOL(plpar_hcall_norets);
  EXPORT_SYMBOL(plpar_hcall_8arg_2ret);
-
+EXPORT_SYMBOL(plpar_hcall_7arg_7ret);
+EXPORT_SYMBOL(plpar_hcall_9arg_9ret);
  extern void pSeries_find_serial_port(void);


diff -Nurpw linux-2.6-hcall/include/asm-powerpc/hvcall.h linux-2.6-hcallib/include/asm-powerpc/hvcall.h
--- linux-2.6-hcall/include/asm-powerpc/hvcall.h	2006-03-30 21:55:05.000000000 +0200
+++ linux-2.6-hcallib/include/asm-powerpc/hvcall.h	2006-03-30 22:03:56.000000000 +0200
@@ -7,8 +7,12 @@
  #define H_SUCCESS	0
  #define H_BUSY		1	/* Hardware busy -- retry later */
  #define H_CLOSED	2	/* Resource closed */
+#define H_NOT_AVAILABLE 3
  #define H_CONSTRAINED	4	/* Resource request constrained to max allowed */
+#define H_PARTIAL       5
  #define H_IN_PROGRESS	14	/* Kind of like busy */
+#define H_PAGE_REGISTERED 15
+#define H_PARTIAL_STORE   16
  #define H_PENDING	17	/* returned from H_POLL_PENDING */
  #define H_CONTINUE	18	/* Returned from H_Join on success */
  #define H_LONG_BUSY_START_RANGE		9900  /* Start of long busy range */
@@ -41,6 +45,36 @@
  #define H_DEST_PARM	-14
  #define H_REMOTE_PARM	-15
  #define H_RESOURCE	-16
+#define H_ADAPTER_PARM  -17
+#define H_RH_PARM       -18
+#define H_RCQ_PARM      -19
+#define H_SCQ_PARM      -20
+#define H_EQ_PARM       -21
+#define H_RT_PARM       -22
+#define H_ST_PARM       -23
+#define H_SIGT_PARM     -24
+#define H_TOKEN_PARM    -25
+#define H_MLENGTH_PARM  -27
+#define H_MEM_PARM      -28
+#define H_MEM_ACCESS_PARM -29
+#define H_ATTR_PARM     -30
+#define H_PORT_PARM     -31
+#define H_MCG_PARM      -32
+#define H_VL_PARM       -33
+#define H_TSIZE_PARM    -34
+#define H_TRACE_PARM    -35
+
+#define H_MASK_PARM     -37
+#define H_MCG_FULL      -38
+#define H_ALIAS_EXIST   -39
+#define H_P_COUNTER     -40
+#define H_TABLE_FULL    -41
+#define H_ALT_TABLE     -42
+#define H_MR_CONDITION  -43
+#define H_NOT_ENOUGH_RESOURCES -44
+#define H_R_STATE       -45
+#define H_RESCINDEND    -46
+

  /* Long Busy is a condition that can be returned by the firmware
   * when a call cannot be completed now, but the identical call
@@ -73,6 +107,9 @@
  #define H_DABRX_KERNEL		(1UL<<(63-62))
  #define H_DABRX_USER		(1UL<<(63-63))

+/* Each control block has to be on a 4K bondary */
+#define H_CB_ALIGNMENT          4096
+
  /* pSeries hypervisor opcodes */
  #define H_REMOVE		0x04
  #define H_ENTER			0x08
@@ -124,6 +161,33 @@
  #define H_VTERM_PARTNER_INFO	0x150
  #define H_REGISTER_VTERM	0x154
  #define H_FREE_VTERM		0x158
+#define H_RESET_EVENTS          0x15C
+#define H_ALLOC_RESOURCE        0x160
+#define H_FREE_RESOURCE         0x164
+#define H_MODIFY_QP             0x168
+#define H_QUERY_QP              0x16C
+#define H_REREGISTER_PMR        0x170
+#define H_REGISTER_SMR          0x174
+#define H_QUERY_MR              0x178
+#define H_QUERY_MW              0x17C
+#define H_QUERY_HCA             0x180
+#define H_QUERY_PORT            0x184
+#define H_MODIFY_PORT           0x188
+#define H_DEFINE_AQP1           0x18C
+#define H_GET_TRACE_BUFFER      0x190
+#define H_DEFINE_AQP0           0x194
+#define H_RESIZE_MR             0x198
+#define H_ATTACH_MCQP           0x19C
+#define H_DETACH_MCQP           0x1A0
+#define H_CREATE_RPT            0x1A4
+#define H_REMOVE_RPT            0x1A8
+#define H_REGISTER_RPAGES       0x1AC
+#define H_DISABLE_AND_GETC      0x1B0
+#define H_ERROR_DATA            0x1B4
+#define H_GET_HCA_INFO          0x1B8
+#define H_GET_PERF_COUNT        0x1BC
+#define H_MANAGE_TRACE          0x1C0
+#define H_QUERY_INT_STATE       0x1E4
  #define H_POLL_PENDING		0x1D8
  #define H_JOIN			0x298
  #define H_ENABLE_CRQ		0x2B0
@@ -183,6 +247,42 @@ long plpar_hcall_4out(unsigned long opco
  		      unsigned long *out3,
  		      unsigned long *out4);

+long plpar_hcall_7arg_7ret(unsigned long opcode,
+			   unsigned long arg1,
+			   unsigned long arg2,
+			   unsigned long arg3,
+			   unsigned long arg4,
+			   unsigned long arg5,
+			   unsigned long arg6,
+			   unsigned long arg7,
+			   unsigned long *out1,
+			   unsigned long *out2,
+			   unsigned long *out3,
+			   unsigned long *out4,
+			   unsigned long *out5,
+			   unsigned long *out6,
+			   unsigned long *out7);
+
+long plpar_hcall_9arg_9ret(unsigned long opcode,
+			   unsigned long arg1,
+			   unsigned long arg2,
+			   unsigned long arg3,
+			   unsigned long arg4,
+			   unsigned long arg5,
+			   unsigned long arg6,
+			   unsigned long arg7,
+			   unsigned long arg8,
+			   unsigned long arg9,
+			   unsigned long *out1,
+			   unsigned long *out2,
+			   unsigned long *out3,
+			   unsigned long *out4,
+			   unsigned long *out5,
+			   unsigned long *out6,
+			   unsigned long *out7,
+			   unsigned long *out8,
+			   unsigned long *out9);
+
  #endif /* __ASSEMBLY__ */
  #endif /* __KERNEL__ */
  #endif /* _ASM_POWERPC_HVCALL_H */

^ permalink raw reply

* Re: [PATCH] Change H_StudlyCaps to H_SHOUTING_CAPS
From: Ryan Arnold @ 2006-03-30 15:36 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev
In-Reply-To: <20060330115817.ADB99211AE9@Schermpje.local>

On Thu, 2006-03-30 at 13:58 +0200, Segher Boessenkool wrote:
> [I hope I got my mailer script to work okay, don't kill me please.]
> 
> Also cleans up some nearby whitespace problems.
> 
> Signed-of-by: Segher Boessenkool <segher@kernel.crashing.org>

> -	else if (rc == H_Parameter)
> +		       "plpar-hcall (%s) failed; not authorized to this"
> +		       " function\n", tag);
> +	else if (rc == H_PARAMETER)
>  		printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n",
>  		       tag);

I believe the studly caps were used over shouting caps because the RPA
specification, from which these ret codes were taken, uses Studly Caps.
That probably isn't sufficient justification, just an historical
perspective.

-- 
Ryan S. Arnold <rsa@us.ibm.com>
IBM Linux Technology Center
Linux on Power Toolchain

^ permalink raw reply

* Re: Kernel for MPC Lite 5200 will not compile
From: Dale Farnsworth @ 2006-03-30 20:05 UTC (permalink / raw)
  To: jcrigby, Linuxppc-embedded
In-Reply-To: <4b73d43f0603300839k4465b2aao7e073f83052b97ff@mail.gmail.com>

Jon Rigby <jcrigby@gmail.com> wrote:
> After thinking about this more....I don't want to push getting the official
> Freescale code into the tree.  If Dale's code works as well as the Freescale
> code then lets stay with it because it is a lot cleaner.

Thanks.

> The effort of porting other drivers will hopefully be easier now that
> I have the experience of having done ATA.

Would Freescale be amenable to working toward a revised, common, API?
Unfortunately, I didn't find the Freescale Bestcomm API to be clean enough
for acceptance into Linux, so changes would be needed.

-Dale

^ permalink raw reply

* Re: Kernel for MPC Lite 5200 will not compile
From: Dale Farnsworth @ 2006-03-30 19:53 UTC (permalink / raw)
  To: jcrigby, Linuxppc-embedded
In-Reply-To: <4b73d43f0603300829q7d45a029qdb5d8006ccda7275@mail.gmail.com>

John Rigby <jcrigby@gmail.com> wrote:
> Sent this to Wolfgang last night.  Accidently omitted Syvain and the list.
> 
> The actual bestcomm "microcode" in Sylvain's tree is the same as the latest
> Freescale supported code.  The linux driver code that interfaces with it is
> code written by Dale Farnsworth and has Montavista copyright.  I don't know
> if it is based on old Freescale (Motorola) code or if it is Dale's creation
> (perhaps Dale can comment).

My bestcomm code is not based on the Freescale code.  I did have access to
the Freescale (Motorola) code when I wrote it, but I think you'll find that
there is *very little* similarity between the two code bases.

> I have just spent some time getting UDMA support into the ATA driver using
> the the bestcomm code in Sylvain's tree.  In the process I found some bugs
> in the code that may explain some problems people have seen with the FEC
> driver.  I'll try to get the patch out tomorrow.
> 
> The ATA driver is a port from a version that worked on an older kernel and
> used the supported Freescale Bestcomm code.  I did the port because it was
> my understanding that attempts to get the supported Freescale code into a
> public tree had met with resistance in the past.  (Second hand info, I'm
> actually fairly new to the 52xx world).
> 
> The pluses for the Freescale version is that several devices are supported
> that are not in Sylvain's tree.  The version in Sylvain's kernel has a
> generic api plus specific code for FEC.  My upcoming patch fixes some bugs,
> adds some missing functionality that I need for ATA and adds the specific
> ATA dma driver code.
> 
> The biggest minus for the Freescale version is that it is really opaque.
> Its implementation makes it hard to figure out what the code is actually
> doing.

Yes, this makes it difficult to maintain and is what has kept the
Freescale Bestcomm code from being accepted into the kernel.  I would
have preferred not to write an alternate version, but, at the time,
Motorola had a take-or-leave-it stance; they wouldn't consider accepting
patches to clean it up.  So then I planned to simply fork their version,
but found the code so convoluted that it was easier to start from scratch.

> If there is a chance of getting the Freescale Bestcomm code into Sylvain's
> tree (and on up the line to Linus) I would welcome that since I would not
> have to port other Bestcomm dependent drivers to the version in Sylvain's
> tree.  I would gladly port the current FEC code to the Freescale Bestcomm
> code to avoid the work of porting the other drivers.  Also we at Freescale
> would prefer to have one version of the Bestcomm code circulating.
> 
> So I guess my question for those with an opinion is what version of Bestcomm
> should be we use for 5200.

It would be better to have one version, and my bestcomm code could be
replaced in Linux by code derived from the current Freescale code.  The
challenges are political.  Neither Freescale nor the Linux community is
willing to relinquish control of their code to the other.  Potentially,
this can be addressed by having a Freescaler, who is responsive to the
Linux community, be a Linux maintainer for the bestcomm code.  There are
also licensing concerns though, since Freescale needs to also license
their code under non-GPL terms.

Until these challenges are resolved, I think we're stuck with two versions.

Thanks,
-Dale

^ permalink raw reply

* Re: [PATCH] powerpc: Extends HCALL interface for Infiniband usage
From: Michal Ostrowski @ 2006-03-30 19:13 UTC (permalink / raw)
  To: linuxppc-dev


For the sake of discussion...

A generic hcall wrapper through which any hcall may be made; an
alternative to having to wwrite-out each possible combination of
numbers of input and output arguments.

Needs the obvious fix to meek Heiko's requirements (9-in, 9-out).

Signed-off-by: Michal Ostrowski <mostrows@watson.ibm.com>


 arch/powerpc/platforms/pseries/hvCall.S |   45 ++++++++++++++++++++++++++++++++
 include/asm-powerpc/hvcall.h            |   10 +++++++
 2 files changed, 55 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S
index 176e8da..7bb29b5 100644
--- a/arch/powerpc/platforms/pseries/hvCall.S
+++ b/arch/powerpc/platforms/pseries/hvCall.S
@@ -129,3 +129,48 @@ _GLOBAL(plpar_hcall_4out)
 
 	mtcrf	0xff,r0
 	blr				/* return r3 = status */
+
+/* long plpar_hcall_generic(unsigned long opcode,	R3
+			    unsigned long in_args[8],	R4
+			    unsigned long out_args[8])	R5
+*/
+_GLOBAL(plpar_hcall_generic)
+	mfcr	r0
+	std	r0,-8(r1)
+	stdu	r1,-48(r1)
+
+	std	r4,16(r1)
+	std	r5,8(r1)
+
+	mr	r12, r4			/* Load HCALL args into r4...r11. */
+	ld	r4, 0(r12)
+	ld	r5, 8(r12)
+	ld	r6, 16(r12)
+	ld	r7, 24(r12)
+	ld	r8, 32(r12)
+	ld	r9, 40(r12)
+	ld	r10, 48(r12)
+	ld	r11, 56(r12)
+
+	HVSC				/* Invoke the hypervisor. */
+
+	ld	r12, 8(r1)		/* Check if return args need	*/
+	cmpi	0, r12, 0		/* to be saved.			*/
+	beq	1f
+
+	std	r4, 0(r12)
+	std	r5, 8(r12)
+	std	r6, 16(r12)
+	std	r7, 24(r12)
+	std	r8, 32(r12)
+	std	r9, 40(r12)
+	std	r10, 48(r12)
+	std	r11, 56(r12)
+1:
+	ld	r1,0(r1) 
+	ld	r0,-8(r1)
+
+	mtcrf	0xff,r0
+	blr				/* return r3 = status */
+
+
diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h
index 38ca9ad..3bf6425 100644
--- a/include/asm-powerpc/hvcall.h
+++ b/include/asm-powerpc/hvcall.h
@@ -175,6 +175,16 @@ long plpar_hcall_4out(unsigned long opco
 		      unsigned long *out3,
 		      unsigned long *out4);
 
+/* plpar_hcall_generic()
+ * 
+ * generic hcall pass-thru mechanism
+ *
+ */
+long plpar_hcall_generic(unsigned long opcode, 
+			 unsigned long in_args[8],	
+			 unsigned long out_args[8]);
+
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HVCALL_H */

^ permalink raw reply related

* Re: [PATCH 3/5] powerpc: Move create_(instruction|branch|function_call) into util.h
From: Linas Vepstas @ 2006-03-30 18:10 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <20060330061300.0B12567B6C@ozlabs.org>


Hi,
A minor quibble from the dept. of naming things:

On Thu, Mar 30, 2006 at 05:12:59PM +1100, Michael Ellerman wrote:
> ===================================================================
> --- /dev/null
> +++ to-merge/include/asm-powerpc/util.h
> @@ -0,0 +1,56 @@
> +
> +#ifndef _ASM_POWERPC_UTIL_H
> +#define _ASM_POWERPC_UTIL_H
> +
> +static inline void create_instruction(unsigned long addr, unsigned int instr)


Surely there is a more descriptive name for this new file than "util.h"?

How about "dynamic_insn.h" or "insn_patch.h" or "dyn_fixup.h" or
something like that? 

--linas

^ permalink raw reply

* Subject: [PATCH] Add ATA bestcomm dma support for MPC5200B.
From: John Rigby @ 2006-03-30 17:51 UTC (permalink / raw)
  To: Sylvain Munaut, Linuxppc-embedded

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

[PATCH] Add ATA bestcomm dma support for MPC5200B.

This works on the Lite5200B platform with some caveats.
The board seems to have a layout issue so the ata signals have
a noise problem.  You need to use an UDMA cable even though
the connector on the board does not allow most UDMA cables to
be plugged in.  To get around this you can remove the key pin
on the board connector or poke a hole in the cable connector.
You also want to use the shortest cable you can get.  I ended up
cutting the cable just past the slave connector.

Even with the above changes some drives will not work.
With the right cable and the right drive you can do UDMA1.

Signed-off-by: John Rigby <jrigby@freescale.com>

---

 arch/ppc/syslib/bestcomm/Makefile        |    1
 arch/ppc/syslib/bestcomm/ata.c           |  143 +++++++
 arch/ppc/syslib/bestcomm/ata.h           |   49 ++
 arch/ppc/syslib/bestcomm/bestcomm.c      |    4
 arch/ppc/syslib/bestcomm/bestcomm.h      |   27 +
 arch/ppc/syslib/bestcomm/sdma_ata_task.c |   61 +++
 arch/ppc/syslib/mpc52xx_setup.c          |    7
 drivers/ide/Kconfig                      |   11 +
 drivers/ide/ppc/mpc52xx_ide.c            |  640
+++++++++++++++++++++++++++++-
 9 files changed, 915 insertions(+), 28 deletions(-)
 create mode 100644 arch/ppc/syslib/bestcomm/ata.c
 create mode 100644 arch/ppc/syslib/bestcomm/ata.h
 create mode 100644 arch/ppc/syslib/bestcomm/sdma_ata_task.c

01a9cf3296c225320105d26201fe7e86596a2ad5
diff --git a/arch/ppc/syslib/bestcomm/Makefile
b/arch/ppc/syslib/bestcomm/Makefile
index 02cc99a..f04c5ad 100644
--- a/arch/ppc/syslib/bestcomm/Makefile
+++ b/arch/ppc/syslib/bestcomm/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_PPC_BESTCOMM)     += bestcomm.o
 obj-$(CONFIG_FEC_MPC52xx)    += sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o
+obj-$(CONFIG_BLK_DEV_MPC52xx_IDE_DMA)    += sdma_ata_task.o ata.o
diff --git a/arch/ppc/syslib/bestcomm/ata.c b/arch/ppc/syslib/bestcomm/ata.c
new file mode 100644
index 0000000..6feae2e
--- /dev/null
+++ b/arch/ppc/syslib/bestcomm/ata.c
@@ -0,0 +1,143 @@
+/*
+ * arch/ppc/syslib/bestcomm/ata.c
+ *
+ * Driver for MPC52xx processor BestComm ATA controller
+ *
+ * Copyright (C) 2006 Freescale - John Rigby
+ *
+ * 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.
+ *
+ * Patterned after:
+ *    arch/ppc/syslib/bestcomm/fec.c
+ *
+ *    Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *    2003-2004 (c) MontaVista, Software, Inc.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#include <asm/mpc52xx.h>
+
+#include "bestcomm.h"
+#include "ata.h"
+
+/*
+ * Initialize the shared ATA rx/tx task.
+ * Returns task number of ATA task.
+ * Returns -1 on failure
+ */
+int sdma_ata_init(struct sdma *s, int maxbufsize)
+{
+    static int tasknum = -1;
+    static struct sdma_bd2 *bd2 = 0;
+    static u32 bd_pa;
+
+    struct sdma_ata_var *var;
+
+    if (tasknum < 0) {
+        tasknum = sdma_load_task(sdma_ata_task);
+        if (tasknum < 0)
+            return tasknum;
+    }
+
+    if (!bd2)
+        bd2 = (struct sdma_bd2 *)sdma_sram_alloc(sizeof(*bd2) * s->num_bd,
+                                SDMA_BD_ALIGN, &bd_pa);
+    if (!bd2)
+        return -ENOMEM;
+
+    sdma_disable_task(tasknum);
+
+    s->flags = SDMA_FLAGS_BD2;
+    s->tasknum = tasknum;
+    s->bd2 = bd2;
+    s->index = 0;
+    s->outdex = 0;
+    memset(bd2, 0, sizeof(*bd2) * s->num_bd);
+
+    var = (struct sdma_ata_var *)sdma_task_var(tasknum);
+    var->enable        = sdma_io_pa(&sdma.io->tcr[tasknum]);
+    var->bd_base        = bd_pa;
+    var->bd_last        = bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd2);
+    var->bd_start        = bd_pa;
+    var->buffer_size    = maxbufsize;
+
+    printk("here in %s calling sdma_dump ata var is %08x\n", __FUNCTION__,
var);
+    sdma_dump();
+
+#if 0
+    /* some tasks may need this set but ata apparently isn't one of them */
+    sdma_set_size(tasknum, 4, 4) /* SrcSz, DstSz */
+#endif
+    sdma_set_task_pragma(tasknum, SDMA_ATA_PRAGMA);
+    sdma_set_task_auto_start(tasknum, tasknum);
+
+    /* clear pending interrupt bits */
+    out_be32(&sdma.io->IntPend, 1<<tasknum);
+
+    out_8(&sdma.io->ipr[SDMA_INITIATOR_ATA_RX], SDMA_IPR_ATA_RX);
+    out_8(&sdma.io->ipr[SDMA_INITIATOR_ATA_TX], SDMA_IPR_ATA_TX);
+
+    return tasknum;
+}
+
+
+/*
+ * Initialize ATA receive task.
+ */
+void sdma_ata_rx_init(struct sdma *s)
+{
+    struct sdma_ata_inc *inc;
+
+    inc = (struct sdma_ata_inc *)sdma_task_inc(s->tasknum);
+    inc->incr_bytes = -(s16)sizeof(u32);
+    inc->incr_src = 0;
+    inc->incr_dst = sizeof(u32);
+
+    sdma_set_initiator(s->tasknum, SDMA_INITIATOR_ATA_RX);
+}
+
+/*
+ * Initialize ATA transmit task.
+ */
+void sdma_ata_tx_init(struct sdma *s)
+{
+    struct sdma_ata_inc *inc;
+
+    inc = (struct sdma_ata_inc *)sdma_task_inc(s->tasknum);
+    inc->incr_bytes    = -(s16)sizeof(u32);
+    inc->incr_src = sizeof(u32);
+    inc->incr_dst = 0;
+
+    sdma_set_initiator(s->tasknum, SDMA_INITIATOR_ATA_TX);
+}
+
+/*
+ * Reset all the ATA task's bds
+ */
+void sdma_ata_reset(struct sdma *s)
+{
+    struct sdma_ata_var *var;
+
+    sdma_reset_buffers2(s);
+    /*
+     * Always start at the beginning (the ATA task modifies bd_start on
writes)
+     */
+    s->outdex = s->index = 0;
+    var = (struct sdma_ata_var *)sdma_task_var(s->tasknum);
+    var->bd_start = var->bd_base;
+}
+
+EXPORT_SYMBOL(sdma_ata_init);
+EXPORT_SYMBOL(sdma_ata_rx_init);
+EXPORT_SYMBOL(sdma_ata_tx_init);
+EXPORT_SYMBOL(sdma_ata_reset);
diff --git a/arch/ppc/syslib/bestcomm/ata.h b/arch/ppc/syslib/bestcomm/ata.h
new file mode 100644
index 0000000..6f2e99d
--- /dev/null
+++ b/arch/ppc/syslib/bestcomm/ata.h
@@ -0,0 +1,49 @@
+/*
+ * arch/ppc/syslib/bestcomm/ata.h
+ *
+ * Driver for MPC52xx processor BestComm ATA controller
+ *
+ * Copyright (C) 2006 Freescale - John Rigby
+ *
+ * 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.
+ *
+ * Patterned after:
+ *    arch/ppc/syslib/bestcomm/fec.c
+ *
+ *    Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *    2003-2004 (c) MontaVista, Software, Inc.
+ */
+
+#ifndef __BESTCOMM_ATA_H__
+#define __BESTCOMM_ATA_H__
+
+
+/* ata task vars that need to be set before enabling the task */
+struct sdma_ata_var {
+    u32 enable;        /* (u16*) address of task's control register */
+    u32 bd_base;        /* (struct sdma_bd*) beginning of ring buffer */
+    u32 bd_last;        /* (struct sdma_bd*) end of ring buffer */
+    u32 bd_start;        /* (struct sdma_bd*) current bd */
+    u32 buffer_size;    /* size of receive buffer */
+};
+
+/* ata task incs that need to be set before enabling the task */
+struct sdma_ata_inc {
+    u16 pad0;
+    s16 incr_bytes;
+    u16 pad1;
+    s16 incr_dst;
+    u16 pad2;
+    s16 incr_src;
+};
+
+extern int sdma_ata_init(struct sdma *s, int maxbufsize);
+extern void sdma_ata_rx_init(struct sdma *s);
+extern void sdma_ata_tx_init(struct sdma *s);
+extern void sdma_ata_reset(struct sdma *s);
+
+extern u32 sdma_ata_task[];
+
+#endif  /* __BESTCOMM_ATA_H__ */
diff --git a/arch/ppc/syslib/bestcomm/bestcomm.c
b/arch/ppc/syslib/bestcomm/bestcomm.c
index 76d5a9b..0f249d6 100644
--- a/arch/ppc/syslib/bestcomm/bestcomm.c
+++ b/arch/ppc/syslib/bestcomm/bestcomm.c
@@ -43,12 +43,12 @@ static spinlock_t sdma_lock = SPIN_LOCK_
 void sdma_dump(void)
 {
     int i;
-    printk("** SDMA registers: pa = %08x, va = %08x\n", sdma.base_reg_addr,
sdma.io);
+
+    printk("** SDMA registers: pa = %08x, va = %08x\n",
(u32)sdma.base_reg_addr, (u32)sdma.io);
     printk("**  taskBar = %08x\n", sdma.io->taskBar);
     printk("**  currentPointer = %08x\n", sdma.io->currentPointer);
     printk("**  endPointer = %08x\n", sdma.io->endPointer);
     printk("**  variablePointer = %08x\n", sdma.io->variablePointer);
-
     printk("**  IntVect1 = %08x\n", sdma.io->IntVect1);
     printk("**  IntVect2 = %08x\n", sdma.io->IntVect2);
     printk("**  PtdCntrl = %08x\n", sdma.io->PtdCntrl);
diff --git a/arch/ppc/syslib/bestcomm/bestcomm.h
b/arch/ppc/syslib/bestcomm/bestcomm.h
index 18cb58f..75ff7d2 100644
--- a/arch/ppc/syslib/bestcomm/bestcomm.h
+++ b/arch/ppc/syslib/bestcomm/bestcomm.h
@@ -237,7 +237,7 @@ static inline int sdma_desc_initiator(u3
 static inline void sdma_set_desc_initiator(u32 *desc, int initiator)
 {
     *desc = (*desc & ~(0x1f << SDMA_DRD_INITIATOR_SHIFT)) |
-            ((initiator << SDMA_DRD_INITIATOR_SHIFT) & 0x1f);
+            ((initiator & 0x1f) << SDMA_DRD_INITIATOR_SHIFT);
 }

 static inline void sdma_submit_buffer(struct sdma *s, void *cookie, void
*data,
@@ -284,12 +284,23 @@ static inline void *sdma_retrieve_buffer
     return cookie;
 }

+static inline void sdma_reset_buffers(struct sdma *s)
+{
+    while (!sdma_queue_empty(s)) {
+        s->bd[s->outdex].status = 0;
+        s->bd[s->outdex].data = 0;
+        sdma_retrieve_buffer(s, NULL);
+    }
+    s->index = s->outdex = 0;
+}
+
 static inline void sdma_submit_buffer2(struct sdma *s, void *cookie,
                     void *data1, void *data2, int length)
 {
 #ifdef CONFIG_BESTCOMM_DEBUG
     BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
 #endif
+
     s->cookie[s->index] = cookie;
     s->bd2[s->index].data1 = data1;
     s->bd2[s->index].data2 = data2;
@@ -312,6 +323,17 @@ static inline void *sdma_retrieve_buffer
     return cookie;
 }

+static inline void sdma_reset_buffers2(struct sdma *s)
+{
+    while (!sdma_queue_empty(s)) {
+        s->bd2[s->outdex].status = 0;
+        s->bd2[s->outdex].data1 = 0;
+        s->bd2[s->outdex].data2 = 0;
+        sdma_retrieve_buffer2(s, NULL);
+    }
+    s->index = s->outdex = 0;
+}
+
 #define SDMA_TASK_MAGIC        0x4243544B    /* 'BCTK' */

 /* the size fields are given in number of 32-bit words */
@@ -351,7 +373,7 @@ static inline int sdma_desc_is_drd(u32 d
                  (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO)    | \
                  (0 << SDMA_PRAGMA_BIT_PACK)        | \
                  (0 << SDMA_PRAGMA_BIT_INTEGER)        | \
-                 (1 << SDMA_PRAGMA_BIT_SPECREAD)    | \
+                 (0 << SDMA_PRAGMA_BIT_SPECREAD)    | \
                  (1 << SDMA_PRAGMA_BIT_CW)        | \
                  (1 << SDMA_PRAGMA_BIT_RL))

@@ -469,6 +491,7 @@ extern int sdma_load_task(u32 *task_imag
 extern void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle);
 extern void sdma_init_bd(struct sdma *s);
 extern void sdma_init_bd2(struct sdma *s);
+extern void sdma_set_initiator(int task, int initiator);

 #define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f)))

diff --git a/arch/ppc/syslib/bestcomm/sdma_ata_task.c
b/arch/ppc/syslib/bestcomm/sdma_ata_task.c
new file mode 100644
index 0000000..5613545
--- /dev/null
+++ b/arch/ppc/syslib/bestcomm/sdma_ata_task.c
@@ -0,0 +1,61 @@
+/*
+ * sdma_ata_task.c
+ *
+ * Created based on bestcom/code_dma/image_rtos1/dma_image.hex
+ */
+
+#include <linux/types.h>
+
+/*
+ * The header consists of the following fields:
+ *    uint32_t    magic;
+ *    uint8_t        desc_size;
+ *    uint8_t        var_size;
+ *    uint8_t        inc_size;
+ *    uint8_t        first_var;
+ *    uint8_t        reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+*/
+
+uint32_t sdma_ata_task[] = {
+    /* header */
+    0x4243544b,
+    0x0e060709,
+    0x00000000,
+    0x00000000,
+
+    /* Task descriptors */
+    0x8198009b, /* LCD: idx0 = var3; idx0 <= var2; idx0 += inc3 */
+    0x13e00c08, /*   DRD1A: var3 = var1; FN=0 MORE init=31 WS=0 RS=0 */
+    0xb8000264, /*   LCD: idx1 = *idx0, idx2 = var0; idx1 < var9; idx1 +=
inc4, idx2 += inc4 */
+    0x10000f00, /*     DRD1A: var3 = idx0; FN=0 MORE init=0 WS=0 RS=0 */
+    0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2
*/
+    0x0c8cfc8a, /*     DRD2B1: *idx2 = EU3(); EU3(*idx2,var10)  */
+    0xd8988240, /*   LCDEXT: idx1 = idx1; idx1 > var9; idx1 += inc0 */
+    0xf845e011, /*   LCDEXT: idx2 = *(idx0 + var00000015); ; idx2 += inc2
*/
+    0xb845e00a, /*   LCD: idx3 = *(idx0 + var00000019); ; idx3 += inc1 */
+    0x0bfecf90, /*     DRD1A: *idx3 = *idx2; FN=0 TFD init=31 WS=3 RS=3 */
+    0x9898802d, /*   LCD: idx1 = idx1; idx1 once var0; idx1 += inc5 */
+    0x64000005, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 INT EXT init=0 WS=0
RS=0 */
+    0x0c0cf849, /*     DRD2B1: *idx0 = EU3(); EU3(idx1,var9)  */
+    0x000001f8, /* NOP */
+
+
+    /* VAR[9]-VAR[14] */
+    0x40000000,
+    0x7fff7fff,
+    0x00000000,
+    0x00000000,
+    0x00000000,
+    0x00000000,
+
+    /* INC[0]-INC[6] */
+    0x40000000,
+    0xe0000000,
+    0xe0000000,
+    0xa000000c,
+    0x20000000,
+    0x00000000,
+    0x00000000,
+};
diff --git a/arch/ppc/syslib/mpc52xx_setup.c
b/arch/ppc/syslib/mpc52xx_setup.c
index 508b241..3c9cd42 100644
--- a/arch/ppc/syslib/mpc52xx_setup.c
+++ b/arch/ppc/syslib/mpc52xx_setup.c
@@ -220,7 +220,6 @@ mpc52xx_calibrate_decr(void)
     tb_to_us = mulhwu_scale_factor(xlbfreq / divisor, 1000000);
 }

-
 void __init
 mpc52xx_setup_cpu(void)
 {
@@ -247,8 +246,9 @@ mpc52xx_setup_cpu(void)
         out_be16(&cdm->fd_counters, 0x5555);

     /* Configure the XLB Arbiter priorities */
-    out_be32(&xlb->master_pri_enable, 0xff);
-    out_be32(&xlb->master_priority, 0x11111111);
+    /* Give PPC and BestComm the same priority on the XLB */
+    out_be32(&xlb->master_pri_enable, 0xf);
+    out_be32(&xlb->master_priority, 0x00007131);

     /* Enable ram snooping for 1GB window */
     out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_SNOOP);
@@ -265,7 +265,6 @@ unmap_regs:
     if (xlb)  iounmap(xlb);
 }

-
 int mpc52xx_match_psc_function(int psc_idx, const char *func)
 {
     struct mpc52xx_psc_func *cf = mpc52xx_psc_functions;
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index e391cee..6ecaee7 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -973,6 +973,17 @@ config BLK_DEV_MPC52xx_IDE
     tristate "MPC52xx Builtin IDE support"
     depends on PPC_MPC52xx && IDE=y

+config BLK_DEV_MPC52xx_IDE_MDMA
+    bool "MDMA support"
+    depends on BLK_DEV_MPC52xx_IDE
+
+config BLK_DEV_MPC52xx_IDE_UDMA
+    bool "UDMA support"
+    depends on BLK_DEV_MPC52xx_IDE
+
+config BLK_DEV_MPC52xx_IDE_DMA
+    def_bool BLK_DEV_MPC52xx_IDE_UDMA || BLK_DEV_MPC52xx_IDE_MDMA
+
 # no isa -> no vlb
 config IDE_CHIPSETS
     bool "Other IDE chipset support"
diff --git a/drivers/ide/ppc/mpc52xx_ide.c b/drivers/ide/ppc/mpc52xx_ide.c
index 5970f7b..7ab1bcc 100644
--- a/drivers/ide/ppc/mpc52xx_ide.c
+++ b/drivers/ide/ppc/mpc52xx_ide.c
@@ -5,6 +5,7 @@
  *
  *
  * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2005,2006 Freescale - Bernard Kuhn, John Rigby
  * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
  *
  * This file is licensed under the terms of the GNU General Public License
@@ -24,8 +25,28 @@
 #include <asm/io.h>
 #include <asm/ppcboot.h>

+#include <syslib/bestcomm/bestcomm.h>
+#include <syslib/bestcomm/ata.h>
+
 #include "mpc52xx_ide.h"

+#define CONFIG_BLK_DEV_IDE_MPC52xx_LIMIT_TO_UDMA1
+#define CONFIG_BLK_DEV_IDE_MPC52xx_SHOWDETAILS 1
+
+#define MAX_DMA_BUFFERS 128
+#define MAX_DMA_BUFFER_SIZE 0x20000
+
+#undef DEBUG
+#define DEBUG
+
+#undef DPRINTK
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+typedef unsigned long ide_ioreg_t;


 /* Private structures used by the driver */
@@ -42,11 +63,6 @@ struct mpc52xx_ata_timings {
     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 */
@@ -58,9 +74,166 @@ static int ataspec_t2i[5]   = {  0,   0,
 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 */
+/* Helper to compute timing parameters */
 #define CALC_CLK_VALUE_UP(c,v) (((v) + c - 1) / c)

+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_MDMA
+
+/* ATAPI-4 MDMA specs (in clocks) */
+struct mdmaspec {
+    u32 t0M[3];
+    u32 td[3];
+    u32 th[3];
+    u32 tj[3];
+    u32 tkw[3];
+    u32 tm[3];
+    u32 tn[3];
+};
+
+static struct mdmaspec mdmaspec66 = {
+    {32,  10,  8},
+    {15,  6,   5},
+    {2,   1,   1},
+    {2,   1,   1},
+    {15,  4,   2},
+    {4,   2,   2},
+    {1,   1,   1}
+};
+
+static struct mdmaspec mdmaspec132 = {
+    {64,  20,  16},
+    {29,  11,  10},
+    {3,   2,   2},
+    {3,   1,   1},
+    {29,  7,   4},
+    {7,   4,   4},
+    {2,   1,   1}
+};
+
+#endif
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_UDMA
+
+/* ATAPI-4 UDMA specs (in clocks) */
+struct udmaspec {
+    u32 tcyc[6];
+    u32 t2cyc[6];
+    u32 tds[6];
+    u32 tdh[6];
+    u32 tdvs[6];
+    u32 tdvh[6];
+    u32 tfs_min[6];
+    u32 tli_max[6];
+    u32 tmli[6];
+    u32 taz[6];
+    u32 tzah[6];
+    u32 tenv_min[6];
+    u32 tsr[6];
+    u32 trfs[6];
+    u32 trp[6];
+    u32 tack[6];
+    u32 tss[6];
+};
+
+struct udmaspec udmaspec66 = {
+    {8, 5,  4,   3,   2,  2},
+    {16, 11,  8,   6,   4 , 2},
+    {1, 1,  1,   1,   1,  1},
+    {1, 1,  1,   1,   1,  1},
+    {5, 4,  3,   2,   1,  1},
+    {1, 1,  1,   1,   1,  1},
+    {16, 14,  12,  9,   8,  6},
+    {10, 10,  10,  7,   8,  5},
+    {2, 2,  2,   2,   2,  2},
+    {1, 1,  1,   1,   1,  1},
+    {2, 2,  2,   2,   2,  2},
+    {2, 2,  2,   2,   2,  2},
+    {3, 2,  2,   2,   2,  2},
+    {5, 5,  4,   4,   4,  4},
+    {11, 9,  7,   7,   7,  6},
+    {2, 2,  2,   2,   2,  2},
+    {4, 4,  4,   4,   4,  4}
+};
+
+struct udmaspec udmaspec132 = {
+    {15, 10,  6,   7,   2,  3},
+    {31, 21,  12,  12,  5,  6},
+    {2, 2,  1,   1,   0,  1},
+    {1, 1,  1,   1,   0,  1},
+    {10, 7,  5,   3,   1,  1},
+    {1, 1,  1,   1,   1,  1},
+    {30, 27,  23,  15,  16, 12},
+    {20, 20,  20,  13,  14, 10},
+    {3, 3,  3,   3,   2,  3},
+    {2, 2,  2,   2,   1,  2},
+    {3, 3,  3,   3,   2,  3},
+    {3, 3,  3,   3,   2,  3},
+    {7, 4,  3,   3,   2,  3},
+    {10, 10,  8,   8,   7,  7},
+    {22, 17,  14,  14, 13, 12},
+    {3, 3,  3,   3,   2,  3},
+    {7, 7,  7,   7,   6,  7},
+};
+
+
+#endif
+
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+
+struct mpc52xx_ide_priv {
+    unsigned int ipb_period;    /* in ps */
+    struct mpc52xx_ata __iomem *ata_regs;
+    struct mpc52xx_ata_timings  timings[2];
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+    struct sdma *sdma;
+    struct udmaspec *udmaspec;
+    struct mdmaspec *mdmaspec;
+    int mpc52xx_ata_dma_last_write;
+#endif
+};
+
+static u8
+mpc52xx_dma2pio (u8 xfer_rate)
+{
+    switch(xfer_rate) {
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+        case XFER_UDMA_6:
+        case XFER_UDMA_5:
+        case XFER_UDMA_4:
+        case XFER_UDMA_3:
+        case XFER_UDMA_2:
+        case XFER_UDMA_1:
+        case XFER_UDMA_0:
+        case XFER_MW_DMA_2:
+        case XFER_PIO_4:
+            //return 3;
+            return 4;
+        case XFER_MW_DMA_1:
+        case XFER_PIO_3:
+            return 3;
+        case XFER_SW_DMA_2:
+        case XFER_PIO_2:
+            return 2;
+        case XFER_MW_DMA_0:
+        case XFER_SW_DMA_1:
+        case XFER_SW_DMA_0:
+#else
+        case XFER_PIO_4:
+            return 4;
+        case XFER_PIO_3:
+            return 3;
+        case XFER_PIO_2:
+            return 2;
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+        case XFER_PIO_1:
+        case XFER_PIO_0:
+        case XFER_PIO_SLOW:
+        default:
+            return 0;
+    }
+}

 /* ========================================================================
*/
 /* IDE Driver & Aux functions
*/
@@ -100,6 +273,99 @@ mpc52xx_ide_compute_pio_timing(
     timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8);
 }

+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_UDMA
+
+static void mpc52xx_ide_calc_udma_timings(ide_drive_t *drive, u8 speed)
+{
+    struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+
+    int which = drive->select.b.unit & 0x01;
+    u32 t2cyc, tcyc, tds, tdh, tdvs, tdvh, tfs, tli, tmli, taz, tenv, tsr,
tss, trfs, trp, tack, tzah;
+
+    t2cyc = priv->udmaspec->t2cyc[speed];
+    tcyc = priv->udmaspec->tcyc[speed];
+    tds = priv->udmaspec->tds[speed];
+    tdh = priv->udmaspec->tdh[speed];
+    tdvs = priv->udmaspec->tdvs[speed];
+    tdvh = priv->udmaspec->tdvh[speed];
+    tfs = priv->udmaspec->tfs_min[speed];
+    tmli = priv->udmaspec->tmli[speed];
+    tenv = priv->udmaspec->tenv_min[speed];
+    tss = priv->udmaspec->tss[speed];
+    trp = priv->udmaspec->trp[speed];
+    tack = priv->udmaspec->tack[speed];
+    tzah = priv->udmaspec->tzah[speed];
+    taz = priv->udmaspec->taz[speed];
+    trfs = priv->udmaspec->trfs[speed];
+    tsr = priv->udmaspec->tsr[speed];
+    tli = priv->udmaspec->tli_max[speed];
+
+    DPRINTK ("UDMA t2cyc = %d\n", t2cyc);
+    DPRINTK ("UDMA tcyc  = %d\n", tcyc);
+    DPRINTK ("UDMA tds   = %d\n", tds);
+    DPRINTK ("UDMA tdh   = %d\n", tdh);
+    DPRINTK ("UDMA tdvs  = %d\n", tdvs);
+    DPRINTK ("UDMA tdvh  = %d\n", tdvh);
+    DPRINTK ("UDMA tfs   = %d\n", tfs);
+    DPRINTK ("UDMA tli   = %d\n", tli);
+    DPRINTK ("UDMA tmli  = %d\n", tmli);
+    DPRINTK ("UDMA taz   = %d\n", taz);
+    DPRINTK ("UDMA tenv  = %d\n", tenv);
+    DPRINTK ("UDMA tsr   = %d\n", tsr);
+    DPRINTK ("UDMA tss   = %d\n", tss);
+    DPRINTK ("UDMA trfs  = %d\n", trfs);
+    DPRINTK ("UDMA trp   = %d\n", trp);
+    DPRINTK ("UDMA tack  = %d\n", tack);
+    DPRINTK ("UDMA tzah  = %d\n", tzah);
+
+    priv->timings[which].udma1 = (t2cyc << 24) | (tcyc << 16) | (tds << 8)
| (tdh);
+    priv->timings[which].udma2 = (tdvs << 24) | (tdvh << 16) | (tfs << 8) |
(tli);
+    priv->timings[which].udma3 = (tmli << 24) | (taz << 16) | (tenv << 8) |
(tsr);
+    priv->timings[which].udma4 = (tss << 24) | (trfs << 16) | (trp << 8) |
(tack);
+    priv->timings[which].udma5 = (tzah << 24);
+
+    priv->timings[which].using_udma = 1;
+}
+
+#endif
+
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_UDMA
+
+static void mpc52xx_ide_calc_mdma_timings(ide_drive_t *drive, u8 speed)
+{
+    struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+    int which = drive->select.b.unit & 0x01;
+    u32 t0M, td, tkw, tm, th, tj, tn;
+
+    t0M = priv->mdmaspec->t0M[speed];
+    td = priv->mdmaspec->td[speed];
+    tkw = priv->mdmaspec->tkw[speed];
+    tm = priv->mdmaspec->tm[speed];
+    th = priv->mdmaspec->th[speed];
+    tj = priv->mdmaspec->tj[speed];
+    tn = priv->mdmaspec->tn[speed];
+
+    DPRINTK ("t0M = %d\n", t0M);
+    DPRINTK ("td  = %d\n", td);
+    DPRINTK ("tkw = %d\n", tkw);
+    DPRINTK ("tm  = %d\n", tm);
+    DPRINTK ("th  = %d\n", th);
+    DPRINTK ("tj  = %d\n", tj);
+    DPRINTK ("tn  = %d\n", tn);
+
+    priv->timings[which].mdma1 = (t0M << 24) | (td << 16) | (tkw << 8) |
(tm);
+    priv->timings[which].mdma2 = (th << 24) | (tj << 16) | (tn << 8);
+
+    priv->timings[which].using_udma = 0;
+}
+
+#endif
+
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+

 static void
 mpc52xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
@@ -117,25 +383,51 @@ mpc52xx_ide_tuneproc(ide_drive_t *drive,
     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);
+    /* Only call ide_config_drive_speed in speedproc */
 }

 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);
+#ifdef CONFIG_BLK_DEV_IDE_MPC52xx_LIMIT_TO_UDMA1
+    if (speed > XFER_UDMA_1)
+        speed = XFER_UDMA_1;
+#else
+    if (speed > XFER_UDMA_4)
+        speed = XFER_UDMA_4;
+#endif

-    return 1;
+    switch(speed) {
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_UDMA
+        case XFER_UDMA_4:
+        case XFER_UDMA_3:
+        case XFER_UDMA_2:
+        case XFER_UDMA_1:
+        case XFER_UDMA_0:
+            printk("%s: Setting UDMA %d timings\n", drive->name, speed -
XFER_UDMA_0);
+            mpc52xx_ide_calc_udma_timings(drive, speed - XFER_UDMA_0);
+            break;
+#endif
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_MDMA
+        case XFER_MW_DMA_2:
+        case XFER_MW_DMA_1:
+        case XFER_MW_DMA_0:
+            printk("%s: Setting MDMA %d timings\n", drive->name, speed -
XFER_MW_DMA_0);
+            mpc52xx_ide_calc_mdma_timings(drive, speed - XFER_MW_DMA_0);
+            break;
+#endif
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+        case XFER_PIO_4:
+        case XFER_PIO_3:
+        case XFER_PIO_2:
+        case XFER_PIO_0:
+            break;
+        default:
+            return -EINVAL;
+    }
+    mpc52xx_ide_tuneproc(drive, mpc52xx_dma2pio(speed));
+    return ide_config_drive_speed(drive, speed);
 }

 static void
@@ -151,6 +443,225 @@ mpc52xx_ide_selectproc(ide_drive_t *driv
 }


+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+
+static int mpc52xx_ide_dma_check(ide_drive_t *drive)
+{
+    u8 speed = ide_dma_speed(drive, 2);
+
+    DPRINTK("dma_check: speed=%x\n", speed);
+    if (speed == 0)
+        return -1;
+    mpc52xx_ide_speedproc(drive, speed);
+
+    if (ide_dma_enable(drive))
+        drive->using_dma = 1;
+    else
+        drive->using_dma = 0;
+
+    return 0;
+}
+
+static int mpc52xx_ide_build_dmatable(ide_drive_t *drive, struct request
*rq)
+{
+    struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+    struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+    struct scatterlist *sg;
+    ide_hwif_t *hwif = HWIF(drive);
+    int i, count = 0;
+
+    /* Build sglist */
+    hwif->sg_nents = i = ide_build_sglist(drive, rq);
+    if (!hwif->sg_nents)
+        return 0;
+
+    if (hwif->sg_dma_direction == PCI_DMA_FROMDEVICE) {
+        sdma_ata_rx_init(priv->sdma);
+    } else {
+        sdma_ata_tx_init(priv->sdma);
+    }
+
+
+    sg = hwif->sg_table;
+    while (i && sg_dma_len(sg)) {
+        u32 cur_addr;
+        u32 cur_len;
+
+        cur_addr = sg_dma_address(sg);
+        cur_len = sg_dma_len(sg);
+
+        while (cur_len) {
+            unsigned int tc  = (cur_len <= MAX_DMA_BUFFER_SIZE) ? cur_len:
MAX_DMA_BUFFER_SIZE;
+
+            if (hwif->sg_dma_direction == PCI_DMA_FROMDEVICE) {
+                invalidate_dcache_range((u32)phys_to_virt(cur_addr),
(u32)phys_to_virt(cur_addr)+(u32)tc);
+                sdma_submit_buffer2(priv->sdma, phys_to_virt(cur_addr),
(void *)&regs->fifo_data, (void *)cur_addr, tc);
+            } else {
+                flush_dcache_range((u32)phys_to_virt(cur_addr),
(u32)phys_to_virt(cur_addr)+(u32)tc);
+                sdma_submit_buffer2(priv->sdma, phys_to_virt(cur_addr),
(void *)cur_addr, (void *)&regs->fifo_data, tc);
+            }
+
+            //DPRINTK("SDMA setup @%08x, l: %x, nextbd: %d !\n", cur_addr,
tc, next_bd);
+            cur_addr += tc;
+            cur_len -= tc;
+            count++;
+            if(count == MAX_DMA_BUFFERS) {
+                printk(KERN_WARNING "%s: DMA table too
small\n",drive->name);
+                goto use_pio_instead;
+            };
+        }
+        sg++;
+        i--;
+    }
+
+    return 1;
+
+use_pio_instead:
+    sdma_ata_reset(priv->sdma);
+
+    pci_unmap_sg(hwif->pci_dev,
+            hwif->sg_table,
+            hwif->sg_nents,
+            hwif->sg_dma_direction);
+
+    return 0; /* revert to PIO for this request */
+}
+
+
+/* Teardown mappings after DMA has completed.  */
+static void mpc52xx_ide_destroy_dmatable (ide_drive_t *drive)
+{
+    ide_hwif_t *hwif = drive->hwif;
+    struct pci_dev *dev = HWIF(drive)->pci_dev;
+    struct scatterlist *sg = hwif->sg_table;
+    int nents = hwif->sg_nents;
+
+    if (nents) {
+        pci_unmap_sg(dev, sg, nents, hwif->sg_dma_direction);
+        hwif->sg_nents = 0;
+    }
+}
+
+
+static void mpc52xx_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+    struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+    struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+
+    mpc52xx_ide_wait_tip_bit_clear(regs);
+
+    /* issue cmd to drive */
+    ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL);
+}
+
+
+static int mpc52xx_ide_dma_setup(ide_drive_t *drive)
+{
+    struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+    struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+    ide_hwif_t *hwif = HWIF(drive);
+    struct request *rq = HWGROUP(drive)->rq;
+    int which = drive->select.b.unit & 0x01;
+    u8 dma_mode;
+
+    if (!mpc52xx_ide_build_dmatable(drive, rq)) {
+        ide_map_sg(drive, rq);
+        return 1;
+    };
+
+    if(hwif->sg_dma_direction == PCI_DMA_FROMDEVICE) { /* read */
+
+        dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ |
MPC52xx_ATA_DMAMODE_FE;
+
+        /* Setup FIFO if direction changed */
+        if (priv->mpc52xx_ata_dma_last_write) {
+            priv->mpc52xx_ata_dma_last_write = 0;
+            mpc52xx_ide_wait_tip_bit_clear(regs);
+            out_8(&regs->dma_mode, MPC52xx_ATA_DMAMODE_FR);
+            /* Configure it with granularity to 7 like sample code */
+            out_8(&regs->fifo_control, 7);
+            out_be16(&regs->fifo_alarm, 128);
+        }
+    }
+    else {
+
+        dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE;
+
+        /* Setup FIFO if direction changed */
+        if (!priv->mpc52xx_ata_dma_last_write) {
+            priv->mpc52xx_ata_dma_last_write = 1;
+            mpc52xx_ide_wait_tip_bit_clear(regs);
+            /* Configure FIFO with granularity to 4 like sample code */
+            out_8(&regs->fifo_control, 4);
+            //out_be16(&regs->fifo_alarm, 256);
+            out_be16(&regs->fifo_alarm, 128);
+        }
+    };
+
+    if (priv->timings[which].using_udma)
+        dma_mode |= MPC52xx_ATA_DMAMODE_UDMA;
+
+    mpc52xx_ide_wait_tip_bit_clear(regs);
+    out_8(&regs->dma_mode, dma_mode);
+
+    drive->waiting_for_dma = 1;
+
+    return 0;
+};
+
+static void mpc52xx_ide_dma_start(ide_drive_t *drive)
+{
+    struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+    extern void xlb_clear(void);
+
+    xlb_clear();
+    sdma_set_task_auto_start(priv->sdma->tasknum, priv->sdma->tasknum);
+    sdma_enable(priv->sdma);
+}
+
+
+static int mpc52xx_ide_dma_end(ide_drive_t *drive)
+{
+    struct mpc52xx_ide_priv *priv = drive->hwif->hwif_data;
+
+    drive->waiting_for_dma = 0;
+
+    sdma_disable(priv->sdma);
+    sdma_clear_irq(priv->sdma);
+    sdma_ata_reset(priv->sdma);
+    mpc52xx_ide_destroy_dmatable(drive);
+
+    return 0;
+}
+
+
+static int mpc52xx_ide_dma_test_irq(ide_drive_t *drive)
+{
+    return (drive->waiting_for_dma);
+}
+
+
+static int mpc52xx_ide_dma_host_off(ide_drive_t *drive)
+{
+    return 0;
+}
+
+
+static int mpc52xx_ide_dma_host_on(ide_drive_t *drive)
+{
+    return 0;
+}
+
+static int mpc52xx_ide_dma_lostirq(ide_drive_t *drive)
+{
+    printk(KERN_ERR "%s: lost interrupt\n", drive->name);
+    return 0;
+}
+
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+
+
 static int
 mpc52xx_ide_setup(
     struct mpc52xx_ata __iomem *regs, struct mpc52xx_ide_priv *priv)
@@ -181,6 +692,21 @@ mpc52xx_ide_setup(
     tslot = CALC_CLK_VALUE_UP(priv->ipb_period, 1000000);
     out_be32(&regs->share_cnt, tslot << 16);

+#ifdef CONFIG_BLK_DEV_IDE_MPC52xx_SHOWDETAILS
+    printk("ipb=%dMHz, set clock period to %d
ps\n",(int)(bd->bi_ipbfreq/1000000),
+            priv->ipb_period);
+#endif
+
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+    if(bd->bi_ipbfreq/1000000 == 66) {
+        priv->mdmaspec = &mdmaspec66;
+        priv->udmaspec = &udmaspec66;
+    } else {
+        priv->mdmaspec = &mdmaspec132;
+        priv->udmaspec = &udmaspec132;
+    }
+#endif
+
     /* Init imings to PIO0 (safest) */
     memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));

@@ -189,9 +715,35 @@ mpc52xx_ide_setup(

     mpc52xx_ide_apply_timing(regs, &priv->timings[0]);

+#ifdef CONFIG_BLK_DEV_IDE_MPC52xx_SHOWDETAILS
+    printk("GPIO config: %08x\n", in_be32((u32 *)0xf0000b00));
+    printk("ATA invalid: %08x\n", in_be32((u32 *)0xf0003a2c));
+    printk("ATA hostcnf: %08x\n", in_be32((u32 *)0xf0003a00));
+    printk("ATA pio1   : %08x\n", in_be32((u32 *)0xf0003a08));
+    printk("ATA pio2   : %08x\n", in_be32((u32 *)0xf0003a0c));
+    printk("XLB Arb cnf: %08x\n", in_be32((u32 *)0xf0001f40));
+#endif
+
     return 0;
 }

+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+static int
+mpc52xx_ata_sdma_setup(struct mpc52xx_ide_priv *priv)
+{
+    int rv = 0;
+
+    priv->sdma = sdma_alloc(MAX_DMA_BUFFERS);
+    if (!priv->sdma) {
+        return -ENOMEM;
+    }
+
+    (void) sdma_ata_init(priv->sdma, MAX_DMA_BUFFER_SIZE);
+
+    return rv;
+}
+#endif
+
 static void
 mpc52xx_ide_setup_hwif_ports(hw_regs_t *hw, struct mpc52xx_ata __iomem
*regs)
 {
@@ -218,7 +770,7 @@ mpc52xx_ide_probe(struct platform_device
 {
     /* Vars */
     ide_hwif_t *hwif;
-    struct mpc52xx_ide_priv *priv;
+    struct mpc52xx_ide_priv *priv = NULL;
     struct mpc52xx_gpio __iomem *gpio_regs = NULL;
     struct mpc52xx_ata __iomem *ata_regs = NULL;
     int ata_irq;
@@ -284,6 +836,7 @@ mpc52xx_ide_probe(struct platform_device
         goto error;
     }

+    memset(priv, 0, sizeof *priv);
     priv->ata_regs = ata_regs;

     /* Setup the ATA controller */
@@ -292,6 +845,13 @@ mpc52xx_ide_probe(struct platform_device
         printk(KERN_ERR "mpc52xx-ide: Controller setup failed !\n");
         goto error;
     }
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+    rv = mpc52xx_ata_sdma_setup(priv);
+    if (rv) {
+        printk(KERN_ERR "mpc52xx-ide: SDMA setup failed !\n");
+        goto error;
+    }
+#endif

     /* Setup the hwif structure */
     hwif->irq = ata_irq;
@@ -325,6 +885,38 @@ mpc52xx_ide_probe(struct platform_device
     hwif->drives[1].autodma = hwif->autodma;
     hwif->drives[1].no_io_32bit = 1;    /* Anyone tried ? */

+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+
+    hwif->atapi_dma = 1;
+    hwif->autodma = 1;
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_MDMA
+    hwif->mwdma_mask = 0x07;
+#endif
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_UDMA
+    hwif->ultra_mask = 0x1F;
+#endif
+    hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
+    hwif->ide_dma_on = &__ide_dma_on;
+    hwif->ide_dma_check = &mpc52xx_ide_dma_check;
+    hwif->dma_setup = &mpc52xx_ide_dma_setup;
+    hwif->dma_exec_cmd = &mpc52xx_ide_dma_exec_cmd;
+    hwif->dma_start = &mpc52xx_ide_dma_start;
+    hwif->ide_dma_end = &mpc52xx_ide_dma_end;
+    hwif->ide_dma_test_irq = &mpc52xx_ide_dma_test_irq;
+    hwif->ide_dma_host_off = &mpc52xx_ide_dma_host_off;
+    hwif->ide_dma_host_on = &mpc52xx_ide_dma_host_on;
+    hwif->ide_dma_timeout = &__ide_dma_timeout;
+    hwif->ide_dma_lostirq = &mpc52xx_ide_dma_lostirq;
+
+#ifndef CONFIG_BLK_DEV_IDE_MPC52xx_LIMIT_TO_UDMA1
+    hwif->udma_four = 1;
+#endif
+    hwif->hwif_data = priv;
+
+    priv->mpc52xx_ata_dma_last_write = 1;
+
+#endif /* CONFIG_BLK_DEV_MPC52xx_IDE_DMA */
+
     hwif->hwif_data = priv;
     platform_set_drvdata(dev, hwif);

@@ -346,6 +938,14 @@ error:

     release_mem_region(res_mem->start, sizeof(struct mpc52xx_ata));

+    if (priv) {
+#ifdef CONFIG_BLK_DEV_MPC52xx_IDE_DMA
+        if (priv->sdma)    sdma_free(priv->sdma);
+#endif
+        kfree(priv);
+    }
+
+
     return rv;
 }

--
1.1.3

[-- Attachment #2: Type: text/html, Size: 59041 bytes --]

^ permalink raw reply related

* Re: Kernel for MPC Lite 5200 will not compile
From: John Rigby @ 2006-03-30 16:39 UTC (permalink / raw)
  To: Linuxppc-embedded
In-Reply-To: <4b73d43f0603300829q7d45a029qdb5d8006ccda7275@mail.gmail.com>

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

After thinking about this more....I don't want to push getting the official
Freescale code into the tree.  If Dale's code works as well as the Freescale
code then lets stay with it because it is a lot cleaner.  The effort of
porting other drivers will hopefully be easier now that I have the
experience of having done ATA.

On 3/30/06, John Rigby <jcrigby@gmail.com> wrote:
>
> Sent this to Wolfgang last night.  Accidently omitted Syvain and the list.
>
>
> The actual bestcomm "microcode" in Sylvain's tree is the same as the
> latest Freescale supported code.  The linux driver code that interfaces with
> it is code written by Dale Farnsworth and has Montavista copyright.  I don't
> know if it is based on old Freescale (Motorola) code or if it is Dale's
> creation (perhaps Dale can comment).
>
> I have just spent some time getting UDMA support into the ATA driver using
> the the bestcomm code in Sylvain's tree.  In the process I found some bugs
> in the code that may explain some problems people have seen with the FEC
> driver.  I'll try to get the patch out tomorrow.
>
> The ATA driver is a port from a version that worked on an older kernel and
> used the supported Freescale Bestcomm code.  I did the port because it was
> my understanding that attempts to get the supported Freescale code into a
> public tree had met with resistance in the past.  (Second hand info, I'm
> actually fairly new to the 52xx world).
>
> The pluses for the Freescale version is that several devices are supported
> that are not in Sylvain's tree.  The version in Sylvain's kernel has a
> generic api plus specific code for FEC.  My upcoming patch fixes some bugs,
> adds some missing functionality that I need for ATA and adds the specific
> ATA dma driver code.
>
> The biggest minus for the Freescale version is that it is really opaque.
> Its implementation makes it hard to figure out what the code is actually
> doing.
>
> If there is a chance of getting the Freescale Bestcomm code into Sylvain's
> tree (and on up the line to Linus) I would welcome that since I would not
> have to port other Bestcomm dependent drivers to the version in Sylvain's
> tree.  I would gladly port the current FEC code to the Freescale Bestcomm
> code to avoid the work of porting the other drivers.  Also we at Freescale
> would prefer to have one version of the Bestcomm code circulating.
>
> So I guess my question for those with an opinion is what version of
> Bestcomm should be we use for 5200.
>
> Thanks for your input
> John
>
> On 3/29/06, Wolfgang Denk <wd@denx.de> wrote:
>
> > In message < 442B11E8.7020107@246tNt.com> you wrote:
> > >
> > > It is ?
> >
> > I think so.
> >
> > > I don't know about the 2.6-denx, but the stock 2.6.15 should work just
> > fine.
> > > What's wrong with it ? (except it misses some drivers ... it should
> > compile
> > > and boot just fine)
> >
> > Isn't the current reengineered implementation of  the  BestComm  code
> > based  on  an very old Freescale version, which has known limitations
> > and problems?
> >
> > Or has there any action resulted  out  of  the  discussion  with  the
> > Freescale engineers, and I have missed it?
> >
> > Best regards,
> >
> > Wolfgang Denk
> >
> > --
> > Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
> > Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
> > In accord with UNIX philosophy, Perl gives you enough  rope  to  hang
> > yourself.              - L. Wall & R. L. Schwartz, _Programming Perl_
> > _______________________________________________
> > Linuxppc-embedded mailing list
> > Linuxppc-embedded@ozlabs.org
> > https://ozlabs.org/mailman/listinfo/linuxppc-embedded
> >
>
>

[-- Attachment #2: Type: text/html, Size: 5427 bytes --]

^ permalink raw reply

* Re: Kernel for MPC Lite 5200 will not compile
From: John Rigby @ 2006-03-30 16:29 UTC (permalink / raw)
  To: Linuxppc-embedded
In-Reply-To: <20060330003419.3FF71353A37@atlas.denx.de>

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

Sent this to Wolfgang last night.  Accidently omitted Syvain and the list.

The actual bestcomm "microcode" in Sylvain's tree is the same as the latest
Freescale supported code.  The linux driver code that interfaces with it is
code written by Dale Farnsworth and has Montavista copyright.  I don't know
if it is based on old Freescale (Motorola) code or if it is Dale's creation
(perhaps Dale can comment).

I have just spent some time getting UDMA support into the ATA driver using
the the bestcomm code in Sylvain's tree.  In the process I found some bugs
in the code that may explain some problems people have seen with the FEC
driver.  I'll try to get the patch out tomorrow.

The ATA driver is a port from a version that worked on an older kernel and
used the supported Freescale Bestcomm code.  I did the port because it was
my understanding that attempts to get the supported Freescale code into a
public tree had met with resistance in the past.  (Second hand info, I'm
actually fairly new to the 52xx world).

The pluses for the Freescale version is that several devices are supported
that are not in Sylvain's tree.  The version in Sylvain's kernel has a
generic api plus specific code for FEC.  My upcoming patch fixes some bugs,
adds some missing functionality that I need for ATA and adds the specific
ATA dma driver code.

The biggest minus for the Freescale version is that it is really opaque.
Its implementation makes it hard to figure out what the code is actually
doing.

If there is a chance of getting the Freescale Bestcomm code into Sylvain's
tree (and on up the line to Linus) I would welcome that since I would not
have to port other Bestcomm dependent drivers to the version in Sylvain's
tree.  I would gladly port the current FEC code to the Freescale Bestcomm
code to avoid the work of porting the other drivers.  Also we at Freescale
would prefer to have one version of the Bestcomm code circulating.

So I guess my question for those with an opinion is what version of Bestcomm
should be we use for 5200.

Thanks for your input
John

On 3/29/06, Wolfgang Denk <wd@denx.de> wrote:
>
> In message <442B11E8.7020107@246tNt.com> you wrote:
> >
> > It is ?
>
> I think so.
>
> > I don't know about the 2.6-denx, but the stock 2.6.15 should work just
> fine.
> > What's wrong with it ? (except it misses some drivers ... it should
> compile
> > and boot just fine)
>
> Isn't the current reengineered implementation of  the  BestComm  code
> based  on  an very old Freescale version, which has known limitations
> and problems?
>
> Or has there any action resulted  out  of  the  discussion  with  the
> Freescale engineers, and I have missed it?
>
> Best regards,
>
> Wolfgang Denk
>
> --
> Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
> In accord with UNIX philosophy, Perl gives you enough  rope  to  hang
> yourself.              - L. Wall & R. L. Schwartz, _Programming Perl_
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>

[-- Attachment #2: Type: text/html, Size: 4093 bytes --]

^ permalink raw reply

* Re: pci-x
From: Andy Fleming @ 2006-03-30 16:28 UTC (permalink / raw)
  To: Carlos Mitidieri; +Cc: linuxppc-embedded
In-Reply-To: <200603281651.53196.carlos.mitidieri@sysgo.com>


On Mar 28, 2006, at 08:51, Carlos Mitidieri wrote:

>
>> On Friday 24 March 2006 15:53, Kumar Gala wrote:
>>> That seems like a driver problem.  Does lspci show your devices  
>>> after
>>> you boot?  Also, what kernel ver are you using?
>>
>> No, the device behind the bridge is not recognized, although the  
>> bridge
>> itself is. I am using kernel 2.6.15.
>
> I am trying to use a PCI-X bridge (Intel 31154) on a mpc8540ads  
> running kernel
> 2.6.15.  A USB controller is behind the bridge.
>
> When the mpc8540ads is booted with the PCI-X switch disabled, the  
> device
> behind the bridge is detected (and actually works), and the following
> messages are printed:

Are you using a Rev A or higher board?  PCI-X doesn't work on earlier  
systems.

Also, make sure your board is configured to run PCI at 66 MHz.  PCI-X  
doesn't work at 33 MHz.


Andy Fleming

^ permalink raw reply

* Re: [PATCH] powerpc: Add FSL CPM2 device tree node documentation
From: Vitaly Bordug @ 2006-03-30 15:10 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <3A2715AD-F459-4AB3-B01B-13301BE2B908@kernel.crashing.org>

On Thu, 30 Mar 2006 09:43:38 -0600
Kumar Gala <galak@kernel.crashing.org> wrote:

> 
> On Mar 30, 2006, at 9:14 AM, Dan Malek wrote:
> 
> >
> > On Mar 30, 2006, at 9:37 AM, Kumar Gala wrote:
> >
> >> * What a give channel (SCC, FCC, UCC, SMC?) is used for serial,
> >> ethernet, ATM, etc.
> >
> > You need to view this from the other direction.  As I've always
> > said, we don't have an "SCC driver", we have a uart driver for
> > SCCs.  So, you configure from that perspective.  The uart driver
> > is configured to use certain SCCs.
> 
> Oh, I agree with you.  This becomes more obvious with QE where  
> everything is a UCC channel.
> 
> >> * How a channel is wired? [pin muxing]  (I really hate having drivers
> >> have board specific ifdefs for this)
> >
> > I've got a solution for IO pin multiplexing that I have to get pushed
> > in using the "feature_call" method like a pmac.  The other thing
> > to realize here is there is often hardware beyond just "pin muxing"
> > that is unique to a board and requires configuration.  Statically
> > describing what pins set/clear is a small, and already understood
> > part, of more complex set up that needs to be done with code
> > unique to a board.
> 
> still waiting :)
> 
> >> * which (if any) BRG a channel is using?
> >
> > These are already a dynamically allocated resource.  Drivers
> > don't care which one is assigned, you should be allocating
> > one and using the handle provided to the support functions.
> 
> Ok, good.
> 
> >> * ...? [I feel like I'm missing some but haven't worked on a CPM
> >> driver in a while :)]
> >
> > I can't think of any, and I use the CPM all of the time.  :-)
> >
> >> The other question is what changes between CPUs?
> >
> > Almost nothing, except the PRAM offset you mention below
> > and I've mentioned in past messages as memory bank differences.
> >
> >> * Number/Mix of channels
> >> * some PRAM offset (8272 FCC comes to mind)
> >> * channel differences for same channel type? (what's an example of
> >> this?)
> >> * ...?
> >
> > Don't be creating problems to solve because we seem to have
> > a solution for _something_.  Yes, this would be a cute piece of code
> > to write and interesting driver updates, but in the end all we have
> > is change for the sake of change, without adding any new features.
> 
> I'm hopefully not suggesting that or at least not something I see as  
> this extensive.
> 
> > The thing to remember is the few public Linux drivers we have
> > take little advantage of the CPM features.  We just configure a few
> > fixed standard modes (like serial and Ethernet).  The CPM is far
> > more powerful and flexible than this, so it seems silly to create some
> > complex method of describing our trivial fixed modes that has no
> > hope of actually being useful for "real" CPM usage.  Then, when
> > someone does write a more complex driver, we have all of this
> > "framework" that just gets in the way instead of being useful.
> 
> I know.
> 
> I guess what I'd suggest is something that makes letting the kernel  
> know about serial & enet usage on the CPM is the extent to take this  
> to start with.  If in time we have more drivers for more things  
> great, then extend it then.  I dont see any reason we can't leverage  
> the flat-dev-tree to have a single way to describe the serial & enet  
> configs for a board.
> 
Yes, that's definitely what it is intended to be...

> I see how you can see this as duplication of a solved problem.   
> However, we need some place to describe some basic config info that  
> we have in arch/ppc for arch/powerpc and flat-dev/.dts is that  
> mechanism.  While we are moving it out of the kernel proper, I think  
> the idea is that over time using the flat-dev tree will allow the  
> information we have to be described in one place and shared between  
> kernel & firmware.
> 

And the results we have now for 85xx family look very nice using this approach.
> (and if Vitaly finishes this off we can beat him up to add kgdb  
> support back to cpm_uart :)

Hrm, I've added that to kgdb already... I even have the KGDB stuff implemented in the platform-device-reworked cpm_uart driver :)

-- 
Sincerely, 
Vitaly

^ permalink raw reply

* Re: [PATCH] powerpc: Add FSL CPM2 device tree node documentation
From: Vitaly Bordug @ 2006-03-30 15:02 UTC (permalink / raw)
  To: Dan Malek; +Cc: linuxppc-dev
In-Reply-To: <9ede6f664a3419c5dda34c5e1911a7e6@embeddedalley.com>

On Thu, 30 Mar 2006 10:14:18 -0500
Dan Malek <dan@embeddedalley.com> wrote:

> 
> On Mar 30, 2006, at 9:37 AM, Kumar Gala wrote:
> 
> > * What a give channel (SCC, FCC, UCC, SMC?) is used for serial,
> > ethernet, ATM, etc.
> 
> You need to view this from the other direction.  As I've always
> said, we don't have an "SCC driver", we have a uart driver for
> SCCs.  So, you configure from that perspective.  The uart driver
> is configured to use certain SCCs.
> 
Well, I am going to move the board-specific code to the BSP place, and make the driver use the callback when it needs to configure the HW tp use SCC/SMC (that includes pin setup as well - the way it is in fs_enet). Actually, it can use any (or even all the SXCs) simultaneously, and that strict configuration can be obsoleted (I mean - nothing required in .config to mention which soc device has the uart, as gianfar does not require what TSEC to utilize) - people often misconfigure things, and to be right there should be ifdef hell in the driver which is _odd_.

> > * How a channel is wired? [pin muxing]  (I really hate having drivers
> > have board specific ifdefs for this)
> 
> I've got a solution for IO pin multiplexing that I have to get pushed
> in using the "feature_call" method like a pmac.  The other thing
> to realize here is there is often hardware beyond just "pin muxing"
> that is unique to a board and requires configuration.  Statically
> describing what pins set/clear is a small, and already understood
> part, of more complex set up that needs to be done with code
> unique to a board.

well, ... :D
> 
> > * which (if any) BRG a channel is using?
> 
> These are already a dynamically allocated resource.  Drivers
> don't care which one is assigned, you should be allocating
> one and using the handle provided to the support functions.
> 

Nobody is arguing. But we need offsets to deal with BRGs (at least repeat that behavior in powerpc), CMX, CP - and there are 2 options to have them  -  yet another foo_immap.h or that "static" nodes in the flattened device tree. 

We already have mature implementation of the first approach - and I just want to give the second one a try and to see if it will be more flexible/effective that what we have in ppc right now. 


> > * ...? [I feel like I'm missing some but haven't worked on a CPM
> > driver in a while :)]
> 
> I can't think of any, and I use the CPM all of the time.  :-)
That is great :)
> 
> > The other question is what changes between CPUs?
> 
> Almost nothing, except the PRAM offset you mention below
> and I've mentioned in past messages as memory bank differences.
> 
> > * Number/Mix of channels
> > * some PRAM offset (8272 FCC comes to mind)
> > * channel differences for same channel type? (what's an example of
> > this?)
> > * ...?
> 
> Don't be creating problems to solve because we seem to have
> a solution for _something_.  Yes, this would be a cute piece of code
> to write and interesting driver updates, but in the end all we have
> is change for the sake of change, without adding any new features.

Let me disagree. Each big change is "a change for change, for design" usually at start. Or, why don't we still use 2.4 - I'm pretty sure there was some period of "redesign" when the new architecture tries to re-implement features yet-existing in mature-stable branch... Or am I missing something?

> 
> The thing to remember is the few public Linux drivers we have
> take little advantage of the CPM features.  We just configure a few
> fixed standard modes (like serial and Ethernet).  The CPM is far
> more powerful and flexible than this, so it seems silly to create some
> complex method of describing our trivial fixed modes that has no
> hope of actually being useful for "real" CPM usage.  Then, when
> someone does write a more complex driver, we have all of this
> "framework" that just gets in the way instead of being useful.
> 
Currently we'll be stale on that small fixed functionality with the implementation we have in ppc. Yes, feature_call could help, but will not save the world, so drivers will have that ifdeffed code inside, direct immr dereference, etc.  Well, it's really hard to make use of CPM flexibility the way it is now.  I don't believe that devicetree approach will save the world either, but it is promising enough at least to try that way.


-- 
Sincerely, 
Vitaly

^ 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