Main Page | Index

Axis Software User Manual


SRAM

The Axis hardware has one Megabyte of battery backed SRAM. The SRAM is connected to a local bus on the far side of a PCI bridge. Given this and the presence of the processors demand paging hardware means that it is impossible to access this SRAM without intervention by the device driver. The driver has to map the PCI address space into physical memory and then create page table entries to allow access to the physical addresses assigned to the PCI region that provides a window into the SRAM.

To understand the SRAM its important to understand the basics of the memory management facilities offered by the X86 processor family. The addresses generated by applications programs do not match physical memory addresses rather the upper 20 address bits are used to index into tables that effectively indirect any memory accesses. Each process has its own unique set of these paging tables as does the kernel. To access SRAM the driver needs to map the SRAM PCI address space into the processors physical address space and than create page table entries to allow it access to the SRAM.

The device driver does allow some flexibility in how the SRAM is used. The device driver provides application programs with three different mechanisms to access SRAM.

An application can open the SRAM and treat it as a fixed size file. The application uses the open close lseek read and write calls and the written data is written by the device driver to the SRAM on the applications behalf. The driver can also remap the SRAM into a processes local memory space using the mmap and munmap calls. Finally the driver can register itself with the Linux MTD subsystem and thus provide a block interface to the memory. This allows some or all of the SRAM to be used as a RAM disk.

To complicate matters further, the SRAM can be partitioned into multiple smaller blocks and each block can then be handled as an individual device. Each due to hardware restrictions each partition must be a multiple of 64K long, individual partitions have read and write enables and the driver exposes control of these enables.

As most SRAM configurations are fairly static, no attempt has been made to allow support for dynamic partitioning rather, the desired partition structure is compiled into the driver. Any changes to the SRAM configuration involve adding or removing entries in the axis_sram_config.c file and rebuilding the driver.

The axis_sram_config array of structures defined in the axis_sram_config.c file controls how the driver partitions SRAM. Each partition has a length and a set of flags. If the CREATE_MTD_DEVICE flag is set then that partition is passed to the MTD subsystem and can be used as a RAM disk (note currently if more than one MTD device is created by the driver then the MTD system causes a kernel panic on driver unload).

The other flags control the access control rules the driver applies to that partition. DEFAULT_READ_ENABLE_ON sets the partitions read enable to on all the time. DEFAULT_WRITE_ENABLE_ON sets the partitions write enable to on all the time.

If the AUTO_PROTECTION flag is set then the driver will enable the SRAM access just for the duration of valid read / write requests. If no access flags are set then the application must take control of the memory access lines itself. The driver provides an interface to allow application programs to control these enable lines via the /proc file system. Using application controlled enable lines is not recommended with MTD devices.

Querying the Current SRAM Configuration

For each SRAM partition the Axis driver creates an set of entries in the /proc/axis_00/sram directory. The entry associated with the first SRAM partition is a directory called Axis_SRAM_0 the second partition has a directory Axis_SRAM_1 and so on.

Each directory has two read only entries: config and mtd-config and two read / write entries : read_enable and write_enable.

The config entry reports the memories physical address, its virtual address (kernel address) and its length. The mtd-config just reports if the SRAM partition is used by the MTD device (if it is further information is available in /proc/mtd). Reading read_enable or write_enable displays their current state. Writing a one or a zero to these files allows an application to modify the read/write enables.

Using SRAM as a File

To access SRAM partitions a device node needs to be created for that partition:

#mknod -m666 /dev/axis_0/sram_0 c 231 0
Creates a device for partition 0
#mknod -m666 /dev/axis_0/sram_1 c 231 1
Creates a device for partition 1

The if the read and write enables are active then resulting device can then be used like a file.

To zero the partition:

#cat /dev/zero > /dev/axis_0/sram_0
cat: write error: No space left on device

Will overwrite the current content with zeros. The error message about running out of space is normal as the SRAM partition has a finite size.

The SRAM can be accesses from a C program as if its a file, read and write work as expected and lseek can be used to move around the file.

Example - Writing to RAM

#include <stdio.h>

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <popt.h>
char * sram_device_name="/dev/axis_0/sram_1" ;
int main(int argc,char ** argv)
{
	int handle ;
	int x;
	unsigned char buffer[100];
	handle = open(sram_device_name,O_RDWR);
	if (!handle)
		{
		fprintf(stderr,"Failed to open %s\n",sram_device_name);
		exit(-1);
		}
	for (x=0;x<sizeof(buffer);x++)
		{
		buffer[x]=x ;
		}
	write(handle,buffer,sizeof(buffer));
	close(handle);
}

Example - Reading from RAM

#include <stdio.h>

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <popt.h>
char * sram_device_name="/dev/axis_0/sram_1" ;
int main(int argc,char ** argv)
{
	int handle ;
	int x;
	unsigned char buffer[100];
	handle = open(sram_device_name,O_RDWR);
	if (!handle)
		{
		fprintf(stderr,"Failed to open %s\n",sram_device_name);
		exit(-1);
		}
	read(handle,buffer,sizeof(buffer));
	for (x=0;x<sizeof(buffer);x++)
		{
		printf("%x ", buffer[x]) ;
		}
	printf("\n");
	close(handle);
}

The Axis driver includes IOCTL calls to control each partitions read and write enables

#include <stdio.h>

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <popt.h>
#include "../PLX_Driver/axis.h"
int main(int argc,char ** argv)
{
	char * sram_device_name ;
	int handle ;
	if (argc < 2 || argc > 3)
		{
		fprintf(stderr,"usage ram_enable device enable|disable\n");
		exit(-1);
		}
	sram_device_name = argv[1] ;
	handle = open(sram_device_name,O_RDWR);
	if (!handle)
		{
		fprintf(stderr,"Failed to open %s\n",sram_device_name);
		exit(-1);
		}
	if (strcasecmp(argv[2],"disable")==0)
		{
		ioctl(handle,AXIS_SRAM_PROTECTION,0);
		}
	if (strcasecmp(argv[2],"enable")==0)
		{


ioctl(handle,AXIS_SRAM_PROTECTION,AXIS_SRAM_WRITE_ENABLE|AXIS_SRAM_READ_ENABLE);
		}
	close(handle);
}

Mapping SRAM into a Processes Local Memory

The driver also allows an application to map part or all of an SRAM partition into its own local memory space. Once this has been done the application can access the SRAM in the same way it would normal memory.

To create a mapping the mmap operation is used. The mmap operation allows a block of SRAM whose size is a multiple of the processor page size (4K) to be mapped into the applications memory map. The operation returns a pointer to the requested memory block,that the application can use like any other pointer. Once the application has finished with the block if it calls the munmap call then the address ceases to be valid and any attempt to access the memory will result in a segmentation fault. Any attempts to write addresses either before or after the mapped block will normally result in segmentation faults (any read that falls in the next page after the requested block will return random data other reads after the mmap will cause a segmentation fault).

Example

#include <stdio.h>

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc,char** argv)
{
	int handle ;
	const int size = 4096 ;
	int x;
	char * memory ;
	handle = open(argv[1],O_RDWR);
	if (argc < 2 || argc > 3)
		{
		fprintf(stderr,"usage ram_mmap device write|read \n");
		exit(-1);
		}
	if (!handle)
		{
		fprintf(stderr,"Failed to open %s\n",argv[1]);
		exit(-1);
		}
	memory = mmap(0,size,PROT_READ|PROT_WRITE,MAP_FILE|MAP_SHARED,handle,0);
	if (!memory)
		{
		fprintf(stderr,"mmap failed\n");
		close(handle);
		exit(1) ;
		}
	if (strcasecmp(argv[2],"read")==0)
		{
		for(x=0;x<size;x++)
			{
			putchar(memory[x]);
			}
		printf("\n");
		}
	if (strcasecmp(argv[2],"write")==0)
		{
		for(x=0;x<size;x++)
			{
			memory[x]=x;
			}
		printf("\n");
		}
	//printf("val =%c\n",memory[size+1]); read just past end of mapping
	returns random data

	//printf("val =%c\n",memory[size+4096+1]); read in second page after
	the end of the mapping causes a segmentation fault
	//memory[size+1]= 0; Write past end of valid mapping causes a segmentation
	fault
	munmap(memory,size);
	//memory[0]= 0;    Mapping is now invalid so this causes a segmentation
	fault
	close(handle);
}

The calls mmap and munmap are both standard POSIX calls. Further details can be found in most good Linux/Unix programming texts and on most systems they share a manual page man mmap.

Using SRAM as a RAM Disk

SRAM partitions can also be used as ram disks. To do this the Axis driver passes the memory to the Linux MTD subsystem, this will create a block device out of the SRAM. Once an MTD block device has been created it behaves like a virtual floppy disk drive.

If an Axis SRAM partition has the MTD flag set then the Axis driver will register the SRAM partition with the MTD system. The MTD driver maintains a list of registered MTD devices. Any Axis SRAM partition passed to the MTD system will join this list. The MTD system registers itself as block device with major number 31. The minor number is used to identify the registered MTD systems indexed by their position on the list.

Assuming the Axis partition is the first on the MTD list then create a device node to allow access to the first MTD block device (note the zero indexing).

mknod -m666 /dev/mtdblock0 b 31 0

Once the Axis driver is loaded then the SRAM partition can be accessed as a block device via this entry.
Block devices are like raw disks and need formatting and mounting prior to use.

The next stage is to format the MTD block device using the mkfs that matches your choice of format.

The example uses a ext2 format:

#mke2fs /dev/mtdblock0
Filesystem label=
OS type:Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
128 inodes, 1024 blocks
51 blocks (4.98%) reserved for the super user
First data block=1
1 block group
8192 blocks per group, 8192 fragments per group
128 inodes per group

Writing inode tables: done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 33 mounts or 180 days, whichever
comes first.

Use tune2fs -c or -i to override.

Having created a ram disk it needs mounting before use. This example uses /mnt/sram.
Other choices are possible:

#mount -text2 /dev/mtdblock0 /mnt/sram

After this any disk activity to /mnt/sram is written to SRAM. Both mkfs and mount have manual pages and should be covered in any book on Linux/Unix system administration.


© HEBER LTD. 2005. This document and the information contained therein is the intellectual property of Heber Ltd. and must not be disclosed to a third party without consent. Copies may be made only if they are in full and unmodified. The information contained in this documentation is believed to be accurate and reliable. However, Heber Ltd. assumes no responsibility for its use, and reserves the right to revise the documentation without notice.
Document No: 80-17794, Issue 4r1    Release Date: 01.12.05     Email: support@heber.co.uk    www.heber.co.uk