What Is a Good Interface for a Linux Device Driver for a Co-Processing Peripheral

Embedded device drivers development notes

Have you tried looking at some implementations?

  • eCos has a HAL, which has some documentation to go along with it.
  • eLua also has a HAL that has grown around it to support the platforms it runs on (ARM, AVR32, etc..), check the architecture information and the "Platform Interface" and "Generic Modules" menus. If you strip out the Lua, eLua is essentially a HAL.

There are likely other examples as well, but I'd recommend looking at living examples of cross-platform and non-cross-platform hardware APIs. Also, if/when you go and start putting together interfaces, make sure to examine individual platform peripheral implementations before nailing down the API. You will find that certain interaction models are commonly supported across many platforms, and others are very platform specific. If your API assumes functionality will always be available, it will be difficult to port to platforms that either have lacking or non-existent support for the functionality you want. Sometimes you may be able to work around this in software with simple solutions, other times you may find it is either impossible or horribly complicated to make behavior consistent across platforms.

Linux device driver that print periodically an information

You should set up a timer with hrtimer_start() at the hello_init().
The struct hrtimer *timer contains a function pointer what will be called at the time you set. That callback function should contains the printk(). You have to renew the timer each time the callback called.
Don't forget to call the hrtimer_cancel() at the hello_exit().
You can use the ktime_set() function to calculate the expire time you want. Have a look here, there are some related and useful functions: High-resolution timers

How are memory regions on ARM Cortex A denoted as device or strongly ordered under Linux

There are a few parts to this.

On ARMv7, which includes the Zynq-7000, memory is denoted as a given type by the memory region attributes configured through the translation table descriptors. There are various ways to configure these and the mechanisms are described in section B3.8 of the ARM Architecture Reference Manual ARMv7-A. Also useful is the Zynq technical reference manual, which is less complete as regards the ARM, but easier to process.

Broadly, the bits of interest are the B (bufferable) bit, the C (cacheable) bit and the 3 TEX (type extension) bits. These may be set directly, or through a redirection when SCTLR.TRE bit is set (which effectively allows a custom remapping using the PRRR and NMRR registers - there may be more to it than that, but I can't immediately see what).

The translation table descriptors are set up in Linux in the memory-management unit (MMU) subsystem. This is obviously very architecture specific, and the relevant ARM bits are found in arch/arm/mm. It's interesting to look through mmu.c to see how different memory attributes are configured on different types.

What follows is a little more speculative, but I think is accurate.

The core UIO driver sets up its relevant memory protections on a physical device by calling pgprot_noncached(). Now, I think this is delegated to the architecture specific implementation, which in the case of ARMv7 is a macro defined in arch/arm/include/asm/pgtable.h, and resolves to setting the L_PTE_MT_UNCACHED flag.

The L_PTE_MT_UNCACHED constant is in turn set in arch/arm/include/asm/pgtable-2level.h. There is a nice bit of documentation in that file that describes what the various constants represent. The value for each type is remapped to the B, C and TEX bits, either through the TRE redirection or through a look-up table configured in arch/arm/mm/proc-macros.S. The TRE redirection registers (PRRR and NMRR) I think are configured in arch/arm/mm/proc-v7-2level.S. If you track those through, you get the same values as the look-up table (which references constants defined in arch/arm/include/asm/pgtable-2level-hwdef.h - note that those constants are for a small page table descriptor, distinct to the ones used in mmu.c)

Where does this leave us? The UIO driver configuring a piece of memory as pgprot_noncached() implies it is L_PTE_MT_UNCACHED, which in turn implies TEX = 000, B = 0 and C = 0. Looking those settings up in the reference manual, we see this corresponds to an unbuffered, strongly ordered, shareable memory region (denoted "Strongly-typed").

It's apparent, that to change the device (perhaps to allow buffered writes), we'd need to modify the driver configuration of memory to use e.g. pgprot_writecombine() which would set the memory type to be normal but with the cache off. There is also a pgprot_device() macro, which also sets up device memory type (bufferable) and cache off, but with some additional flags I haven't understood properly yet (I think they are for configuring a software "Linux" version of the page table entry for the case where the hardware doesn't support it, so aren't relevant when it does).



Related Topics



Leave a reply



Submit