Page 1 of 1

ATA/ATAPI using DMA problem with the PRD Table

Posted: Sat May 15, 2010 9:56 am
by Freddy
Hi

I am trying to program an cd Driver who uses Dma to recieve datas from the CD. Therefore I tried to set up the prdt table with that code:

This is for the second ATA Channel

Code: Select all

  ..........
          unsigned long addrr_bar4 =  results[0].pci_device->bar4;
  ................
          else if((addrr_bar4 & 0x1) == 1)

         {

            //Save start port in an var  and add the offset (Secondary ATA bus)

            int port = (addrr_bar4 & 0xFFFFFFFC) + 8; 

            //Go to the port to which we have to send the ptr table address

            port+=7;

            //make sure it is an DWORD and store the address into the var address

            unsigned long address_of_ptr = (int)ptr_table &  0xFFFFFFFF;

            //Send the first byte of the address 

            outportb(port, address_of_ptr & 0xFF);

            port--;

            //Send the second byte of the address

            outportb(port, (address_of_ptr >> 8)& 0xFF);

            port--;

            outportb(port, (address_of_ptr >> 16)& 0xFF);

            port--;

            //Send the last byte

            outportb(port,(address_of_ptr >>24) & 0xFF); 
            //Set Command byte. To start and write        

            outportb((addrr_bar4 & 0xFFFFFFFC) + 8,  0x81 & 0xFF); 

          }

That code I used to set up the ptrd table

Code: Select all

void DMA::setup_ptr_table(uint8_t count, unsigned long memory_space)

{

        



     //set the value of the ptr table. Memory Space is the first DWORD. Count the next Word. Next word Reservt for MSB    

     //I was not sure if an unsigned char pointer can store an unsigned long var. So I wrote this. If he can only



     *(ptr_table+3) = (unsigned char)(memory_space & 0xFF);
     *(ptr_table+2) = (unsigned char)(memory_space >> 8);
     *(ptr_table+1) = (unsigned char) (memory_space >> 16);              

     *ptr_table     = (unsigned char) (memory_space >> 24);

     
     //Set the next DWORD. First 16 bit are 0 (reserver MSB). The next is the count. A count of 0 means 64 k 

     //I was not sure if an unsigned char pointer can store an unsigned long var. So I wrote this. If he can only

     *(ptr_table+5) = (unsigned char) (count & 0xff);
     *(ptr_table +4) = (unsigned char)(count >> 8);

     

     //Set MSB

     *(ptr_table+6) = 0x00;

     *(ptr_table+7) = 0x00;
     *(ptr_table+8) = '\0';  

    

}
The function which return false;

Code: Select all

bool DMA::check_fail(int ata_bus) 

{



     //Read the two words of the BAR4 register 

     unsigned long addrr_bar4 =  results[0].pci_device->bar4;

     unsigned char* status_address; 

     unsigned long base_port;

     if((addrr_bar4 & 0x1 ) == 0) {

       status_address = (unsigned char *)(addrr_bar4 & 0xFFFFFFF0); 

       if(ata_bus == 1) {

         if(status_address[2] & 0x2 == 2)

                return false;    

       }  

       else { 

         if(status_address[10] & 0x2 == 2) 

            return false;

       }  

     }    

     else {

       base_port =  (addrr_bar4 & 0xFFFFFFFC);

       if (ata_bus == 1)  

       	 base_port += 2;

       else 

         base_port += 10;

                

       unsigned char staus_register = inportb(base_port);

       if(staus_register & 0x2 == 2)

         return false;  

                   

     }

     return true;

}
Does anyone know why the transfer fail ??

Re: ATA/ATAPI using DMA problem with the PRD Table

Posted: Sat May 15, 2010 4:48 pm
by pcmattman
Are you using virtual memory at all? If so, you need to use a physical address when talking to the device, and a virtual address when manipulating the data. DMA doesn't go through the MMU - it hits the memory directly.

Re: ATA/ATAPI using DMA problem with the PRD Table

Posted: Sat May 15, 2010 6:04 pm
by bewing
Did you get the basic driver running in PIO mode before you tried using DMA? Is this on real hardware, or in an emulator?

Re: ATA/ATAPI using DMA problem with the PRD Table

Posted: Sun May 16, 2010 6:21 am
by Freddy
Thanks for the response
bewing wrote:Is this on real hardware, or in an emulator?
It is on an emulator:
QEMU PC emulator version 0.12.3 (qemu-kvm-0.12.3), Copyright (c) 2003-2008 Fabrice Bellard
bewing wrote:Did you get the basic driver running in PIO mode before you tried using DMA?
I will try today to get the Driver to work in PIO mode. I will post then the result.
pcmattman wrote:Are you using virtual memory at all?
No Virtuall Memory. Paging is disable

Re: ATA/ATAPI using DMA problem with the PRD Table

Posted: Sun May 16, 2010 8:01 am
by Freddy
Only to make sure that I have the table with the I/O Ports understand right and the progam only does not work because I wrote to the wrong ports :(:

Bar4: 4-Byte Aligned Base Address of Bar 4 register. (Bar 4 & 0xFFFFFFFC)

Primary IDE channel
Bar4 | is the command port
Bar 4 + 0x2 | is the Status Port
Bar 4 + 0x4 |Port to send the first Byte of the PRDT Address
Bar 4 + 0x5 | Port to send the second Byte of the PRDT Address
.......................................
Second IDE channel
Bar4 + 0x8 | is the Command I/o port
Bar4 + 0xA | is the I/O port form which I can read the Status
Bar 0xC | Port to send the first byte of the PRDT Address

.....

http://wiki.osdev.org/ATA/ATAPI_using_DMA

That is right or ?

Update: bar4 is: c001

Re: ATA/ATAPI using DMA problem with the PRD Table

Posted: Sun May 16, 2010 11:39 am
by Combuster
Freddy wrote:Update: bar4 is: c001
I sure hope you use the actual base address of 0xc000 (see PCI)

Re: ATA/ATAPI using DMA problem with the PRD Table

Posted: Sun May 16, 2010 12:43 pm
by Freddy
Combuster wrote:
Freddy wrote:Update: bar4 is: c001
I sure hope you use the actual base address of 0xc000 (see PCI)
Thanks for the response
At first I check with

Code: Select all

 if(addrr_bar4 & 0x1 == 1) 
if it is an Memory Space BAR Layout or I/O Space BAR Layout. If it is an I/O space layout I calculate addrr_bar4 & 0xFFFFFFFC to get the base port. Othercase I would calculate Bar & 0xFFFFFFF0 to get the base address .

But if bar4 has the value c001 it should be an I/O Space BAR Layout

Right ?

Re: ATA/ATAPI using DMA problem with the PRD Table

Posted: Mon May 17, 2010 6:31 am
by thepowersgang
yes it should be (also, that C code is wrong, the & operator has a lower precedence than == for some reason, so the correct code is (addrr_bar4 & 0x1) == 1

Re: ATA/ATAPI using DMA problem with the PRD Table

Posted: Mon May 17, 2010 10:09 am
by Owen
The reason is quite obvious when one looks at history: BCPL had no && operator, so bitwise and was abused as a logical and.

Of course, we are now stuck with the stupidity, as changing that would break code.

Re: ATA/ATAPI using DMA problem with the PRD Table

Posted: Mon May 17, 2010 11:53 am
by Freddy
thepowersgang wrote:yes it should be (also, that C code is wrong, the & operator has a lower precedence than == for some reason, so the correct code is (addrr_bar4 & 0x1) == 1
I uses it right for checking if it is Memory Mapt or an I/O port but for the function which check for an error in DMA I forgot the () . Thx did not know that :(.

There was some other errors in the code and I make it easier (I use union now). I did not get the cd Driver to work right now but no function which check if with DMA everything work right "return false" (I hope there are no errors in these functions) :D. So I think with DMA is now everything right. If I get other problems with DMA I will repost. THX to all

Re: ATA/ATAPI using DMA problem with the PRD Table

Posted: Wed May 19, 2010 2:12 pm
by Freddy
Hi
i did not get an IRQ after I send the atapi read command(0xA8). I think the reason for that is that the 0x3C PCI register has the value 0xffffff.. So no conection with the Interrupt Line. But also the Bit 0 of the Status register did not change to 0, which means last entry of prdt table is read.

Can someone pls check if my error methods are so far right so that I really know that with DMA is all right. And I have to search the error in Atapi :(
Bit 1 (value = 2) is set if any DMA memory transfer failed for any reason in this PRDT.

Code: Select all

..................
       base_port =  (addrr_bar4 & 0xFFFFFFFC);

       if (ata_bus == 1)  

       	 base_port += 2;

       else 

         base_port += 10;

                

       unsigned char staus_register = (inportb(base_port)  & 0x2);

       if(staus_register == 2)

         return false;  

Bit 0 (value = 1) is set when the bus goes into DMA mode. It is cleared when the last PRD in the table has been used up.

Code: Select all

 if((staus_register & 0x1) != 1)
Or does the transfer fail because it is not conected with the IRQ line and therefore also the first bit of the status registe will not be cleared?