Subject: Re: PCI Memory mapping

From: Marc Leeman <[email-masked]>
Date: Wed, 24 Mar 2004 15:25:24 +0100

This is getting weird, I found a solution to the problem, well kind of.

Let's introduce the major players in this drama:

 /* communication struct between user and kernel space , in driver.h
  * kernel include */
 typedef struct SStreamPci {
         unsigned int pciaddress;
         unsigned int useraddress;
         unsigned char stream;
 }TSStreamPci;

 /* user space program */
 /* as long as not all data is transferred */
 while(userptr < (userbuffer + (TRANSFER_SIZE>>2))){
   /* currentstream is a struct that is passed to the kernel of
    * type TSStreamPci */
   currentstream.useraddress = (unsigned)userptr;

   /* copy our buffer to the kernel (PCI_TRANSFER_SIZE), 4k */
   ioctl(dsphandle,PPC2DSP_CONSISTENT_COPY_TO_KERNEL,&currentstream);

   /* Interrupt the DSP */
   WriteToDSP(PacketReady,0x1);
   ioctl(dsphandle,PPC2DSP_SET_HDCR,&interrupt);

   /* Wait until the DSP acknowledges transfer */
   while(ReadFromDSP(PacketReady)){}

   /* Read kernel buffer back */
   ioctl(dsphandle,PPC2DSP_CONSISTENT_COPY_FROM_KERNEL,&currentstream);

   /* increment pointer */
   userptr += (BLOCK_TRANSFER_SIZE >> 2);
 }

The strange thing is that this works only and only if I do a transfer
back from kernel space into the userbuffer AFTER the DSP has
acknowledged transferring the data. Note that this data is never used
again. Doing this copy_to_user before DSP acknowledgement still results
in the afore mentioned data corruption.

The associated ioctls are:
case PPC2DSP_CONSISTENT_COPY_TO_KERNEL:
  {
    TSStreamPci currentstream;
    if(copy_from_user(&currentstream,(TSStreamPci*) arg,sizeof(TSStreamPci))){
      return -EFAULT;
    }
    if(copy_from_user(driver_data.device[currentstream.stream]->kern_addr,(char*)currentstream.useraddress, PCI_TRANSFER_SIZE)){
      return -EFAULT;
    }
    break;
  }
case PPC2DSP_CONSISTENT_COPY_FROM_KERNEL:
  {
    TSStreamPci currentstream;
    if(copy_from_user(&currentstream,(TSStreamPci*) arg, sizeof(TSStreamPci))){
      return -EFAULT;
    }
    if(copy_to_user((char*)currentstream.useraddress,driver_data.device[currentstream.stream]->kern_addr, PCI_TRANSFER_SIZE)){
      return -EFAULT;
    }
    break;
  }

There is about a 10% bandwith reduction (due to PPC utilisation I would
assume) over the PCI, so I can live with that; but what bothers me is
not knowing _why_, ... Especially since I want my first module not to
contain too large beginners mistakes :)

  marc.

** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/