Help / Advice On Creating a Kernel Module

Yello,

I'm running a BF561 and what I'm basically trying to do is allow a Linux program on CoreA to read buffers that are being written to by a bare metal encoder running on CoreB. The buffers and varibles I need to be able to access have fixed memory locations in L3 and L2 Cache, the larger buffers and variables will be read on the Linux side, some of the others will need to be able to change bytes.

Now my main question is where or not it's possible to get the kernel process to pass to the Linux process a pointer so the linux process can read the buffer directly rather then have to copy the data. I know that the kernel module can directly address memory but I don't know how to then pass that to the Linux process. So can someone point me in the right direction, thanks

If it helps the bare metal process is a AD's H.264 encoder, and I need to be able to read the output NAL table and Stream buffer from linux, so they can be transmitted on to an end PC. I'm basically writting a mini ICC.

Kind Regards,

Nathan Skidmore

  • 0
    •  Analog Employees 
    on Jan 17, 2012 7:52 PM

    You can use ICC/MCAPI available in 2011R1 release to transfer buffer pointer and length between Linux application and bare metal code.

    The Linux application usually allocates this uncached buffers via ICC ioctl() /L2 SRAM system call and queues these buffer pointers to bare metal code’s free buffer list via ICC/MCAPI. After bare metal code remove one buffer pointer from free list and finishes filling it, it notifies Linux application via ICC/MCAPI and continue with next free buffer. After Linux application finishes receiving this buffer, it queues this buffer pointer back to bare metal code via ICC/MCAPI. This loop continue until Linux application notifies the bare metal code to stop running.

    Please refer to the ICC/MCAPI example code under uClinux-dist/user/blkfin-apps/icc_utils/example/ .

    From: Skid analog@sgaur.hosted.jivesoftware.com

    Sent: Wednesday, January 18, 2012 12:25 AM

    To: Zhang, Sonic

    Subject: New message: "Help / Advice On Creating a Kernel Module"

    Analog Devices EngineerZone<http://ez.analog.com/index.jspa>

    Help / Advice On Creating a Kernel Module

    created by Skid<http://ez.analog.com/people/Skid> in Linux Distribution for Blackfin - View the full discussion<http://ez.analog.com/message/40507#40507

  • The ICC doesn't work with VirualDSP++ compiled programs because it  was compiled with the GNU toolchain, at least not without being edited  to crowbar it in, also the Analog Device H.264 encoder that's running on  CoreB can't be compiled in the GNU toolchain. So out of the box the two  are not compatible, also the ICC is over complicated for what we are  trying to achieve.

    Please answer the ORIGINAL question, not fixate on a  detail that I only added to explain what I was aiming for, its like you  ignore the large majority of my original post.

    All I want to be able to do is use a device drive /  kernel module to pass a pointer to a linux program that points to the  right area of memory for the buffer, I just need a small code slice to  confirm that it is posible or that my best guess is correct. The way I  was assuming it could be done was by using ioctl to return a pointer to a  variable in the kernel module that already points to the right area of  memory area, something to the effect of the code below, but having never  written a kernel module before, and none of the documentation talking  about directly addressing memory I need my assumptions confirmed.

    Kernel Module:

    static unsigned char *streambuffer = (unsigned char*)0x02200000;

    int encoder_icc_ioctl (struct inode *inode, struct file* filp, unsigned int cmd, unsigned long arg)
    {
         switch (cmd)
         {
             case (SOME_COMMAND):
             {

                return &streambuffer;
             }
         }
    }

    Linux Program:

    unsigned char **streambufferpointer = ioctl(...);

    Kind Regards,

    Nathan Skidmore

  • 0
    •  Analog Employees 
    on Jan 18, 2012 10:23 PM

    ICC/MCAPI support for VDSP is underway. ICC/MCAPI is still the recommended solution for VDSP code.

    Before it is available, you best choice is to store buffer at fixed address known to both VDSP code and Linux application and reserve these memory region after the Linux memory region when Linux kernel boots up. Then, you can do anything in your Linux application with these reserved memory. But, you are on your own in this way.

    From: Skid analog@sgaur.hosted.jivesoftware.com

    Sent: Wednesday, January 18, 2012 5:07 PM

    To: Zhang, Sonic

    Subject: New message: "Help / Advice On Creating a Kernel Module"

    Analog Devices EngineerZone<http://ez.analog.com/index.jspa>

    Help / Advice On Creating a Kernel Module

    reply from Skid<http://ez.analog.com/people/Skid> in Linux Distribution for Blackfin - View the full discussion<http://ez.analog.com/message/40561#40561

  • Nevermind, finally got to the point where I needed this to work and have spent all day with it and worked it out ^^

    Kernel Module:

    static unsigned char *gStreamBuf[NUM_INSTANCES][NUM_STREAM_BUFFERS];    // Points to the stream buffer in SDRAM

    ...

    static int __init encoder_icc_init (void)
    {
        // Points gStreamBuf to the stream buffers in L3 cache
        gStreamBuf[0][0] = (unsigned char *)0x02800000;

    ...

    }

    long encoder_icc_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
    {
        switch (cmd)
        {

    ...

            case (1):
            {
                eInstanceFlags[1].active = ~eInstanceFlags[1].active;
                printk ("Encoder ICC Module: Buffer Address %x\n", (unsigned int) &gStreamBuf[0][0]);
                printk ("Encoder ICC Module: Buffer Pointer %x\n", (unsigned int) gStreamBuf[0][0]);

                ret = put_user ((unsigned int)gStreamBuf[0][0], (unsigned int*) arg);
                if (ret)
                {
                    return -EFAULT;
                }
                else
                {
                    return 0;
                }
            }
            break;

    ...

        }
    }

    Linux Program:

    unsigned char *gStreamBuf;

    int main() {

    ...

    ret = ioctl(fd, 1, (unsigned int) &gStreamBuf);

    ...

    }

    I've skipped out all the code for creating and opening the device driver / kernel module so thats just the code to do what I was aiming for.