From 72a62ad88f82fe1ffee50024db4dd0f3fa5806f7 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 3 Nov 2016 16:58:08 +1100 Subject: Rename all manuals with an _ to have a -. It helps released naming of files. --- bsp-howto/shared_memory_support.rst | 242 ++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 bsp-howto/shared_memory_support.rst (limited to 'bsp-howto/shared_memory_support.rst') diff --git a/bsp-howto/shared_memory_support.rst b/bsp-howto/shared_memory_support.rst new file mode 100644 index 0000000..f73588d --- /dev/null +++ b/bsp-howto/shared_memory_support.rst @@ -0,0 +1,242 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2009. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Shared Memory Support Driver +############################ + +The Shared Memory Support Driver is responsible for providing glue routines and +configuration information required by the Shared Memory Multiprocessor +Communications Interface (MPCI). The Shared Memory Support Driver tailors the +portable Shared Memory Driver to a particular target platform. + +This driver is only required in shared memory multiprocessing systems that use +the RTEMS mulitprocessing support. For more information on RTEMS +multiprocessing capabilities and the MPCI, refer to the *Multiprocessing +Manager* chapter of the *RTEMS Application C User's Guide*. + +Shared Memory Configuration Table +================================= + +The Shared Memory Configuration Table is defined in the following structure: + +.. code-block:: c + + typedef volatile uint32_t vol_u32; + + typedef struct { + vol_u32 *address; /* write here for interrupt */ + vol_u32 value; /* this value causes interrupt */ + vol_u32 length; /* for this length (0,1,2,4) */ + } Shm_Interrupt_information; + + struct shm_config_info { + vol_u32 *base; /* base address of SHM */ + vol_u32 length; /* length (in bytes) of SHM */ + vol_u32 format; /* SHM is big or little endian */ + vol_u32 (*convert)(); /* neutral conversion routine */ + vol_u32 poll_intr; /* POLLED or INTR driven mode */ + void (*cause_intr)( uint32_t ); + Shm_Interrupt_information Intr; /* cause intr information */ + }; + + typedef struct shm_config_info shm_config_table; + +where the fields are defined as follows: + +``base`` + is the base address of the shared memory buffer used to pass messages + between the nodes in the system. + +``length`` + is the length (in bytes) of the shared memory buffer used to pass messages + between the nodes in the system. + +``format`` + is either ``SHM_BIG`` or ``SHM_LITTLE`` to indicate that the neutral format + of the shared memory area is big or little endian. The format of the + memory should be chosen to match most of the inter-node traffic. + +``convert`` + is the address of a routine which converts from native format to neutral + format. Ideally, the neutral format is the same as the native format so + this routine is quite simple. + +``poll_intr``, ``cause_intr`` + is either ``INTR_MODE`` or ``POLLED_MODE`` to indicate how the node will be + informed of incoming messages. + +``Intr`` + is the information required to cause an interrupt on a node. This + structure contains the following fields: + + ``address`` + is the address to write at to cause an interrupt on that node. For a + polled node, this should be NULL. + + ``value`` + is the value to write to cause an interrupt. + + ``length`` + is the length of the entity to write on the node to cause an interrupt. + This can be 0 to indicate polled operation, 1 to write a byte, 2 to + write a sixteen-bit entity, and 4 to write a thirty-two bit entity. + +Primitives +========== + +Convert Address +--------------- + +The ``Shm_Convert_address`` is responsible for converting an address of an +entity in the shared memory area into the address that should be used from this +node. Most targets will simply return the address passed to this routine. +However, some target boards will have a special window onto the shared memory. +For example, some VMEbus boards have special address windows to access +addresses that are normally reserved in the CPU's address space. + +.. code-block:: c + + void *Shm_Convert_address( void *address ) + { + return the local address version of this bus address + } + +Get Configuration +----------------- + +The ``Shm_Get_configuration`` routine is responsible for filling in the Shared +Memory Configuration Table passed to it. + +.. code-block:: c + + void Shm_Get_configuration( + uint32_t localnode, + shm_config_table **shmcfg + ) + { + fill in the Shared Memory Configuration Table + } + +Locking Primitives +------------------ + +This is a collection of routines that are invoked by the portable part of the +Shared Memory Driver to manage locks in the shared memory buffer area. +Accesses to the shared memory must be atomic. Two nodes in a multiprocessor +system must not be manipulating the shared data structures simultaneously. The +locking primitives are used to insure this. + +To avoid deadlock, local processor interrupts should be disabled the entire +time the locked queue is locked. + +The locking primitives operate on the lock ``field`` of the +``Shm_Locked_queue_Control`` data structure. This structure is defined as +follows: + +.. code-block:: c + + typedef struct { + vol_u32 lock; /* lock field for this queue */ + vol_u32 front; /* first envelope on queue */ + vol_u32 rear; /* last envelope on queue */ + vol_u32 owner; /* receiving (i.e. owning) node */ + } Shm_Locked_queue_Control; + +where each field is defined as follows: + +``lock`` + is the lock field. Every node in the system must agree on how this field + will be used. Many processor families provide an atomic "test and set" + instruction that is used to manage this field. + +``front`` + is the index of the first message on this locked queue. + +``rear`` + is the index of the last message on this locked queue. + +``owner`` + is the node number of the node that currently has this structure locked. + +Initializing a Shared Lock +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Shm_Initialize_lock`` routine is responsible for initializing the lock +field. This routines usually is implemented as follows: + +.. code-block:: c + + void Shm_Initialize_lock( + Shm_Locked_queue_Control *lq_cb + ) + { + lq_cb->lock = LQ_UNLOCKED; + } + +Acquiring a Shared Lock +~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Shm_Lock`` routine is responsible for acquiring the lock field. +Interrupts should be disabled while that lock is acquired. If the lock is +currently unavailble, then the locking routine should delay a few microseconds +to allow the other node to release the lock. Doing this reduces bus contention +for the lock. This routines usually is implemented as follows: + +.. code-block:: c + + void Shm_Lock( + Shm_Locked_queue_Control *lq_cb + ) + { + disable processor interrupts + set Shm_isrstat to previous interrupt disable level + + while ( TRUE ) { + atomically attempt to acquire the lock + if the lock was acquired + return + delay some small period of time + } + } + +Releasing a Shared Lock +~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Shm_Unlock`` routine is responsible for releasing the lock field and +reenabling processor interrupts. This routines usually is implemented as +follows: + +.. code-block:: c + + void Shm_Unlock( + Shm_Locked_queue_Control *lq_cb + ) + { + set the lock to the unlocked value + reenable processor interrupts to their level prior + to the lock being acquired. This value was saved + in the global variable Shm_isrstat + } + +Installing the MPCI ISR +======================= + +The ``Shm_setvec`` is invoked by the portable portion of the shared memory to +install the interrupt service routine that is invoked when an incoming message +is announced. Some target boards support an interprocessor interrupt or +mailbox scheme and this is where the ISR for that interrupt would be installed. + +On an interrupt driven node, this routine would be implemented +as follows: + +.. code-block:: c + + void Shm_setvec( void ) + { + install the interprocessor communications ISR + } + +On a polled node, this routine would be empty. -- cgit v1.2.3