Fw: IDE DMA on ppc405 with via VT82C686

John F Davis johndavi at us.ibm.com
Mon Feb 7 11:54:35 EST 2005


----- Forwarded by John F Davis/Raleigh/IBM on 02/06/2005 07:54 PM -----

John F Davis/Raleigh/IBM 
02/06/2005 03:41 PM

To
linuxppc-embedded-bounces at ozlabs.org
cc
andre at linux-ide.org, vojtech at suse.cz, maratbn at yahoo.com, 
jean-luc.coulon at fnac.net
Subject
IDE DMA on ppc405 with via VT82C686





Hello

I am still trying to get this IDE DMA code working.  I have modified 
(hacked) the ide_build_dmatable so that it flushes the buffer for each 
range of 
memory that is modified by the dma bus master.  I am certain I have 
flushed
the cache properly as shown below, but the problem persists.

Below are two traces.  The first one is from my 
log buffer utility which shows the operation of the modified 
ide_build_dmatable routine.
The second one is from the logic analyzer and it corresponds to the first
dma operation. 

Lastly, I have the entire ide_build_dmatable routine for reference as
well as the resulting ksymoops.  Note, this code appears to be rock solid
for running multiple consecutive hdparm tests.  ie. enable dma and then
issue "while true; do hdparm -t /dev/hda; done" in four logins to the 
target
with ssh.

However, I get the oops when I start playback of a video in Xine from
the disk.

I am at the point now, where my next task is to try this board with a 
different
IDE controller and see if its a problem with the IDE DMA code for this
non cache coherent processor or if its a problem in the VIA driver.

JD


Truncated portion of my log buffer.
----------------------------------------------------

IBM john f. davis utils
**************************************
ide_build_dmatable
ide_build_sglist
sg_table -> dma/prd table 16
bcount = f000 
table (cpu view) = b2009000 (bus view) = fefd000
        cpu view addr [b2009000] = 10c00e
        cpu view data [b2009004] = 100000
        bus view addr [fefd000] = ec01000
        bus view data [fefd004] = 1000
flush_dcache_range (aec01000, aec02000)
sg_table -> dma/prd table 15
bcount = 10000 
table (cpu view) = b2009008 (bus view) = fefd008
        cpu view addr [b2009008] = c00e
        cpu view data [b200900c] = 100000
        bus view addr [fefd008] = ec00000
        bus view data [fefd00c] = 1000
flush_dcache_range (aec00000, aec01000)
sg_table -> dma/prd table 14
bcount = 1000 
table (cpu view) = b2009010 (bus view) = fefd010
        cpu view addr [b2009010] = f0bf0e
        cpu view data [b2009014] = 100000
        bus view addr [fefd010] = ebff000
        bus view data [fefd014] = 1000
flush_dcache_range (aebff000, aec00000)
...
...




Truncated portion of Logic Analyzer Trace
----------------------------------------------------

Listing(Listing<1>) - 22 May 2003 (23:45)

State Number        ADDR           FUTUREPLUS SYSTEMS c 1996 
Decimal             Hex            PCI BUS TRANSACTIONS REV 1.2 
________________    ___________    ____________________________________ 

...
...  
44                  0000FFD4       I/O WRITE ADR=0000FFD4 
45                  0FEFD000          D32=0FEFD000 
46                  0FEFD000       IDLE 
47                  0000FFD4       IDLE 
 
...
...
...  
71                  0FEFD000       MEM READ ADR=0FEFD000 
72                  0BF9D000          STOP-NO DATA XFERED-RETRY 
 
73                  0FEFD000       MEM READ ADR=0FEFD000 
74                  0EC01000          D32=0EC01000 
75                  00001000          D32=00001000 
76                  00001000       IDLE 
77                  00001000       IDLE 
 
78                  000000A1       I/O WRITE ADR=000000A1 
79                  3F3F3F3F          D32=xxxx3Fxx          STOP# 
80                  3F3F3F3F       IDLE 
81                  000000A1       IDLE 
 
82                  00000021       I/O WRITE ADR=00000021 
83                  F9F9F9F9          D32=xxxxF9xx          STOP# 
84                  F9F9F9F9       IDLE 
85                  00000021       IDLE 
 
86                  0EC01000       MEM WRITE ADR=0EC01000 
87                  1000B8FA          D32=1000B8FA 
88                  00BCD08E          D32=00BCD08E 
89                  0000B8B0          D32=0000B8B0 
90                  C08ED88E          D32=C08ED88E 
91                  7C00BEFB          D32=7C00BEFB 
92                  B90600BF          D32=B90600BF 


Modified ide_build_dma_table routine
----------------------------------------------------


/* JFD NOTES
 * This is called second after the dma_read is started.
 */ 
int ide_build_dmatable (ide_drive_t *drive, struct request *rq, int ddir)
{
        ide_hwif_t *hwif        = HWIF(drive);
        unsigned int *table     = hwif->dmatable_cpu;  /* JFD Blach table 
gets the non cached memory */
        volatile unsigned int *tableJFD;
        unsigned int is_trm290  = (hwif->chipset == ide_trm290) ? 1 : 0;
        unsigned int count = 0;
        unsigned int countJFD;
        int i,m;
        struct scatterlist *sg;
        unsigned int *prd_entry;
        unsigned int flush_start_addr;
        unsigned int flush_length;
 

//      jd_print_it("ide_build_dmatable\n");

        if (rq->cmd == IDE_DRIVE_TASKFILE) {
                printk("calling ide_raw_build_sglist\n");
                hwif->sg_nents = i = ide_raw_build_sglist(hwif, rq);
        } else {
                /* JFD we call this routine each time */
                // printk("calling ide_build_sglist\n");
                hwif->sg_nents = i = ide_build_sglist(hwif, rq, ddir);
        }


        if (!i)
                return 0;

        sg = hwif->sg_table;
        while (i && sg_dma_len(sg)) {
                u32 cur_addr;
                u32 cur_len;

                cur_addr = sg_dma_address(sg);  /* jfd blach these are 
real addresses */
                cur_len = sg_dma_len(sg);
//              jd_print_it("sg_table -> dma/PRD table %i\n", i);

                /*
                 * Fill in the dma table, without crossing any 64kB 
boundaries.
                 * Most hardware requires 16-bit alignment of all blocks,
                 * but the trm290 requires 32-bit alignment.
                 */

                while (cur_len) {
                        tableJFD=table;
                        if (count++ >= PRD_ENTRIES) {
                                printk("%s: DMA table too small\n", 
drive->name);
                                goto use_pio_instead;
                        } else {
                                u32 xcount, bcount = 0x10000 - (cur_addr & 
0xffff);

                                jd_print_it("bcount = %x \n",bcount);
                                if (bcount > cur_len)
                                        bcount = cur_len;

                                // JFD writes the address to the PRD table
                                *table++ = cpu_to_le32(cur_addr);
                                xcount = bcount & 0xffff;
                                countJFD=xcount;
                                if (is_trm290)
                                        xcount = ((xcount >> 2) - 1) << 
16;
                                if (xcount == 0x0000) {
        /* 
         * Most chipsets correctly interpret a length of 0x0000 as 64KB,
         * but at least one (e.g. CS5530) misinterprets it as zero (!).
         * So here we break the 64KB entry into two 32KB entries instead.
         */
                                        if (count++ >= PRD_ENTRIES) {
                                                printk("%s: DMA table too 
small\n", drive->name);
                                                goto use_pio_instead;
                                        }
 
                                        // JFD Write the truncated length 
to the PRD table
                                        *table++ = cpu_to_le32(0x8000);
                                        // JFD Write the address for the 
next truncated length to the PRD table
                                        *table++ = cpu_to_le32(cur_addr + 
0x8000);
                                        xcount = 0x8000;

// cut out the logging for real test
#if 0

                                        jd_print_it("table-trunc (cpu 
view) = %x (bus view) = %x\n",tableJFD, virt_to_bus(tableJFD));
                                        jd_print_it("\tCPU View ADDR [%x] 
= %x\n",tableJFD, *tableJFD);
                                        jd_print_it("\tCPU View DATA [%x] 
= %x\n",tableJFD+1, *(tableJFD+1));

                                        jd_print_it("\tBUS View ADDR [%x] 
= %x\n",virt_to_bus(tableJFD), le32_to_cpu(*tableJFD));
                                        jd_print_it("\tBUS View DATA [%x] 
= %x\n",virt_to_bus(tableJFD+1), le32_to_cpu(*(tableJFD+1)));

#endif
                                        flush_start_addr = 
bus_to_virt((unsigned int *)le32_to_cpu(*tableJFD));
                                        flush_length = 
le32_to_cpu(*(tableJFD+1));

//                                      jd_print_it("flush_dcache_range 
(%x, %x)\n", flush_start_addr, flush_start_addr + flush_length);
                                        flush_dcache_range 
(flush_start_addr, flush_start_addr + flush_length );
  
                                        // have to increment  our pointer 
to the next PRD address loc as well.
                                        tableJFD++;
                                        tableJFD++;
                                }


                                // JFD Write the length (could be trucated 
per above) to the PRD table
                                *table++ = cpu_to_le32(xcount);
                                cur_addr += bcount;
                                cur_len -= bcount;
                        }

// cut out the logging for real test.
#if 0
                                        jd_print_it("table (cpu view) = %x 
(bus view) = %x\n",tableJFD, virt_to_bus(tableJFD));
                                        jd_print_it("\tCPU View ADDR [%x] 
= %x\n",tableJFD, *tableJFD);
                                        jd_print_it("\tCPU View DATA [%x] 
= %x\n",tableJFD+1, *(tableJFD+1));

                                        jd_print_it("\tBUS View ADDR [%x] 
= %x\n",virt_to_bus(tableJFD), le32_to_cpu(*tableJFD));
                                        jd_print_it("\tBUS View DATA [%x] 
= %x\n",virt_to_bus(tableJFD+1), le32_to_cpu(*(tableJFD+1)));

#endif
                                        flush_start_addr = 
bus_to_virt((unsigned int *)le32_to_cpu(*tableJFD));
                                        flush_length = 
le32_to_cpu(*(tableJFD+1));

//                                      jd_print_it("flush_dcache_range 
(%x, %x)\n", flush_start_addr, flush_start_addr + flush_length);
                                        flush_dcache_range 
(flush_start_addr, flush_start_addr + flush_length );


 
#if 0
                        // Lets try to read that address into a variable 
to see if it "flushes that cache entry"
                        for (m=0; m< 0x1000;m++) {
                                ulFoo = *(unsigned int*) 
bus_to_virt(le32_to_cpu(*tableJFD++));
                        }
#endif

                }




                sg++;
                i--;
        }

        if (count) {
                if (!is_trm290)
                        *--table |= cpu_to_le32(0x80000000);
                return count;
        }
        printk("%s: empty DMA table?\n", drive->name);
use_pio_instead:
        pci_unmap_sg(hwif->pci_dev,
                     hwif->sg_table,
                     hwif->sg_nents,
                     hwif->sg_dma_direction);
        hwif->sg_dma_active = 0;
        return 0; /* revert to PIO for this request */
}




Ksymoops dump
----------------------------------------------------

003AF9C A002F770 A002EC18 A003B14C A003B288 A003B5E8 A003C1E4 
AA003AF9C A002F770 A002EC18 A003B14C A003B288 A003B5E8 A003C1E4 
007CA8C A0027690 A0028044 A0028518 A0028A5C A003840C A000279C 
0A007CA8C A0027690 A0028044 A0028518 A0028A5C A003840C A000279C 
FECCB68 0F833B80 0F59D02C 0F59D298 0F59C830 0FF5B278 0FEC7914 
00FECCB68 0F833B80 0F59D02C 0F59D298 0F59C830 0FF5B278 0FEC7914 
FC0B408 
0FC0B408 
Warning (Oops_read): Code line not seen, dumping what data is available


>>NIP; a002fc68 <kmem_find_general_cachep+da4/2bb4>   <=====

>>GPR1; ac803cf0 <_end+c55ffc8/125f6420>
>>GPR2; ac802000 <_end+c55e2d8/125f6420>
>>GPR3; a02eb1c8 <_end+474a0/125f6420>
>>GPR4; ac0b4000 <_end+be102d8/125f6420>
>>GPR9; ac12c020 <_end+be882f8/125f6420>
>>GPR11; a02eb1d0 <_end+474a8/125f6420>
>>GPR18; a00288ec <do_generic_file_read+74c/814>
>>GPR19; ad3fc834 <_end+d158b0c/125f6420>
>>GPR20; ac803ed8 <_end+c5601b0/125f6420>
>>GPR21; a007c768 <journal_blocks_per_page+4390/8868>
>>GPR25; a04ff860 <_end+25bb38/125f6420>
>>GPR29; a02eb1c8 <_end+474a0/125f6420>
>>GPR30; ac0b4f60 <_end+be11238/125f6420>
>>GPR31; a02eb1c8 <_end+474a0/125f6420>

Trace; a003af9c <bread+10/138>
Trace; a002f770 <kmem_find_general_cachep+8ac/2bb4>
Trace; a002ec18 <kmem_cache_alloc+10/20>
Trace; a003b14c <get_unused_buffer_head+68/c8>
Trace; a003b288 <set_bh_page+dc/350>
Trace; a003b5e8 <create_empty_buffers+24/960>
Trace; a003c1e4 <block_read_full_page+2c0/2ec>
Trace; a007ca8c <journal_blocks_per_page+46b4/8868>
Trace; a0027690 <filemap_fdatawait+424/4ec>
Trace; a0028044 <grab_cache_page_nowait+230/38c>
Trace; a0028518 <do_generic_file_read+378/814>
Trace; a0028a5c <generic_file_read+a8/9e4>
Trace; a003840c <default_llseek+340/e28>
Trace; a000279c <set_context+3b4/5e0>
Trace; 0feccb68 Before first symbol
Trace; 0f833b80 Before first symbol
Trace; 0f59d02c Before first symbol
Trace; 0f59d298 Before first symbol
Trace; 0f59c830 Before first symbol
Trace; 0ff5b278 Before first symbol
Trace; 0fec7914 Before first symbol
Trace; 0fc0b408 Before first symbol


5 warnings and 2 errors issued.  Results may not be reliable.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://ozlabs.org/pipermail/linuxppc-embedded/attachments/20050206/aa341454/attachment.htm 


More information about the Linuxppc-embedded mailing list