summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/shmdr/shm_driver.h
blob: 45c4c76ad57da118a500c8abce0de7d0e08533de (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
/*  shm.h
 *
 *  This include file contains all the constants, structures,
 *  and global variables for this RTEMS based shared memory
 *  communications interface driver.
 *
 *  Processor board dependencies are in other files.
 *
 *  COPYRIGHT (c) 1989-1997.
 *  On-Line Applications Research Corporation (OAR).
 *  Copyright assigned to U.S. Government, 1994.
 *
 *  The license and distribution terms for this file may in
 *  the file LICENSE in this distribution or at
 *  http://www.OARcorp.com/rtems/license.html.
 *
 *  $Id$
 */

#ifndef __SHM_h
#define __SHM_h

#include <clockdrv.h>

#ifdef __cplusplus
extern "C" {
#endif

/*  The information contained in the Node Status, Locked Queue, and
 *  Envelope Control Blocks must be maintained in a NEUTRAL format.
 *  Currently the neutral format may be selected as big or little
 *  endian by simply defining either NEUTRAL_BIG or NEUTRAL_LITTLE.
 *
 *  It is CRITICAL to note that the neutral format can ONLY be
 *  changed by modifying this file and recompiling the ENTIRE
 *  SHM driver including ALL target specific support files.
 *
 *  The following table details the memory contents for the endian
 *  field of the Node Status Control Block in the various
 *  data format configurations (data is in hexadecimal):
 *
 *   NEUTRAL NATIVE BYTE 0  BYTE 1  BYTE 2  BYTE 3
 *   ======= ====== ======  ======  ======  ======
 *    BIG     BIG     00      00      00      01
 *    BIG    LITTLE   10      00      00      00
 *   LITTLE   BIG     01      00      00      00
 *   LITTLE  LITTLE   00      00      00      10
 *
 *
 *  NOTE: XXX
 *                PORTABILITY OF LOCKING INSTRUCTIONS
 *                ===================================
 *            The locking mechanism described below is not
 *            general enough.  Where the hardware supports
 *            it we should use "atomic swap" instructions
 *            so the values in the lock can be tailored to
 *            support a CPU with only weak atomic memory
 *            instructions.  There are combinations of
 *            CPUs with inflexible atomic memory instructions
 *            which appear to be incompatible.  For example,
 *            the SPARClite instruction uses a byte which is
 *            0xFF when locked.  The PA-RISC uses 1 to indicate
 *            locked and 0 when unlocked.  These CPUs appear to
 *            have incompatible lock instructions.  But
 *            they could be used in a heterogenous system
 *            with does not mix SPARCs and PA-RISCs.  For
 *            example, the i386 and SPARC or i386 and SPARC
 *            could work together.  The bottom line is that
 *            not every CPU will work together using this
 *            locking scheme.  There are supposed to be
 *            algorithms to do this without hardware assist
 *            and one of these should be incorporated into
 *            the shared memory driver.
 *
 *            The most flexible scheme using the instructions
 *            of the various CPUs for efficiency would be to use
 *            "atomic swaps" wherever possible.  Make the lock
 *            and unlock configurable much like BIG vs LITTLE
 *            endian use of shared memory is now.  The values
 *            of the lock could then reflect the "worst"
 *            CPU in a system.  This still results in mixes
 *            of CPUs which are incompatible.
 *
 *  The current locking mechanism is based upon the MC68020
 *  "tas" instruction which is atomic.  All ports to other CPUs
 *  comply with the restrictive placement of lock bit by this
 *  instruction.  The lock bit is the most significant bit in a
 *  big-endian rtems_unsigned32.  On other processors, the lock is
 *  typically implemented via an atomic swap or atomic modify
 *  bits type instruction.
 */

#define NEUTRAL_BIG

#ifdef NEUTRAL_BIG
#define SHM_BIG       0x00000001
#define SHM_LITTLE    0x10000000
#endif

#ifdef NEUTRAL_LITTLE
#define SHM_BIG       0x01000000
#define SHM_LITTLE    0x00000010
#endif

/*
 *  The following are the values used to fill in the lock field.  Some CPUs
 *  are able to write only a single value into field.  By making the
 *  lock and unlock values configurable, CPUs which support "atomic swap"
 *  instructions can generally be made to work in any heterogeneous
 *  configuration.  However, it is possible for two CPUs to be incompatible
 *  in regards to the lock field values.  This occurs when two CPUs
 *  which write only a single value to the field are used in a system
 *  but the two CPUs write different incompatible values.
 *
 *  NOTE:  The following is a first attempt at defining values which
 *         have a chance at working together.  The m68k should use
 *         chk2 instead of tas to be less restrictive.  Target endian
 *         problems (like the Force CPU386 which has (broken) big endian
 *         view of the VMEbus address space) are not addressed yet.
 */

#if defined(i960)
#define SHM_LOCK_VALUE    0x00000080
#define SHM_UNLOCK_VALUE  0
#elif defined(m68k)
#define SHM_LOCK_VALUE    0x80000000
#define SHM_UNLOCK_VALUE  0
#define SHM_LOCK_VALUE    0x80000000
#define SHM_UNLOCK_VALUE  0
#elif defined(i386)
#define SHM_LOCK_VALUE    0x80000000
#define SHM_UNLOCK_VALUE  0
#elif defined(mips64orion)
#define SHM_LOCK_VALUE    0x80000000
#define SHM_UNLOCK_VALUE  0
#elif defined(hppa1_1)
#define SHM_LOCK_VALUE    0
#define SHM_UNLOCK_VALUE  1
#elif defined(unix)
#define SHM_LOCK_VALUE    0
#define SHM_UNLOCK_VALUE  1
#elif defined(no_cpu)               /* for this values are irrelevant */
#define SHM_LOCK_VALUE    1
#define SHM_UNLOCK_VALUE  0
#else
#error "shm.h - no SHM_LOCK_VALUE defined for this CPU architecture"
#endif

#define Shm_Convert( value ) \
  ((Shm_Configuration->convert) ? \
    (*Shm_Configuration->convert)(value) : (value))

/* constants */

#define SHM_MASTER                  1     /* master initialization node */
#define SHM_FIRST_NODE              1

/* size constants */

#define KILOBYTE          (1024)
#define MEGABYTE          (1024*1024)

/* inter-node interrupt values */

#define NO_INTERRUPT            0     /* used for polled nodes */
#define BYTE                    1
#define WORD                    2
#define LONG                    4

/* operational mode constants -- used in SHM Configuration Table */
#define POLLED_MODE             0
#define INTR_MODE               1

/* error codes */

#define NO_ERROR                0
#define SHM_NO_FREE_PKTS        0xf0000

/* null pointers of different types */

#define NULL_ENV_CB             ((Shm_Envelope_control *) 0)
#define NULL_CONVERT            0

/*
 * size of stuff before preamble in envelope.
 * It must be a constant since we will use it to generate MAX_PACKET_SIZE
 */
 
#define SHM_ENVELOPE_PREFIX_OVERHEAD    (4 * sizeof(vol_u32))

/*
 *  The following is adjusted so envelopes are MAX_ENVELOPE_SIZE bytes long.
 *  It must be >= RTEMS_MINIMUM_PACKET_SIZE in mppkt.h.
 */
 
#ifndef MAX_ENVELOPE_SIZE
#define MAX_ENVELOPE_SIZE 0x180
#endif

#define MAX_PACKET_SIZE  (MAX_ENVELOPE_SIZE -               \
                          SHM_ENVELOPE_PREFIX_OVERHEAD +    \
                          sizeof(Shm_Envelope_preamble) +   \
                          sizeof(Shm_Envelope_postamble))


/* constants pertinent to Locked Queue routines */

#define LQ_UNLOCKED              SHM_UNLOCK_VALUE
#define LQ_LOCKED                SHM_LOCK_VALUE

/* constants related to the Free Envelope Pool */

#define FREE_ENV_POOL            0
#define FREE_ENV_CB              (&Shm_Locked_queues[ FREE_ENV_POOL ])

/*  The following are important when dealing with
 *  the shared memory communications interface area.
 *
 *  NOTE: The starting address and length of the shared memory
 *        is defined in a system dependent file.
 */

#define START_NS_CBS     ((void *)Shm_Configuration->base)
#define START_LQ_CBS     ((START_NS_CBS) + \
        ( (sizeof (Shm_Node_status_control)) * (Shm_Maximum_nodes + 1) ) )
#define START_ENVELOPES  ( ((void *) START_LQ_CBS) + \
        ( (sizeof (Shm_Locked_queue_Control)) * (Shm_Maximum_nodes + 1) ) )
#define END_SHMCI_AREA    ( (void *) START_ENVELOPES + \
        ( (sizeof (Shm_Envelope_control)) * Shm_Maximum_envelopes ) )
#define END_SHARED_MEM   (START_NS_CBS+Shm_Configuration->length)

/* macros */

#define Shm_Is_master_node()  \
  ( SHM_MASTER == Shm_Local_node )

#define Shm_Free_envelope( ecb ) \
  Shm_Locked_queue_Add( FREE_ENV_CB, (ecb) )
#define Shm_Allocate_envelope() \
  Shm_Locked_queue_Get(FREE_ENV_CB)

#define Shm_Initialize_receive_queue(node) \
  Shm_Locked_queue_Initialize( &Shm_Locked_queues[node], node )

#define Shm_Append_to_receive_queue(node, ecb) \
  Shm_Locked_queue_Add( &Shm_Locked_queues[node], (ecb) )

#define Shm_Envelope_control_to_packet_prefix_pointer(ecb)  \
   ((void *)(ecb)->packet)

#define Shm_Packet_prefix_to_envelope_control_pointer( pkt )   \
   ((Shm_Envelope_control *)((rtems_unsigned8 *)(pkt) - \
   (sizeof(Shm_Envelope_preamble) + SHM_ENVELOPE_PREFIX_OVERHEAD)))

#define Shm_Build_preamble(ecb, node) \
       (ecb)->Preamble.endian = Shm_Configuration->format

#define Shm_Build_postamble( ecb )

/* volatile types */

typedef volatile rtems_unsigned8  vol_u8;
typedef volatile rtems_unsigned32 vol_u32;

/* shm control information */

struct shm_info {
  vol_u32 not_currently_used_0;
  vol_u32 not_currently_used_1;
  vol_u32 not_currently_used_2;
  vol_u32 not_currently_used_3;
};

typedef struct {
  /*byte start_of_text;*/
  vol_u32 endian;
  vol_u32 not_currently_used_0;
  vol_u32 not_currently_used_1;
  vol_u32 not_currently_used_2;
} Shm_Envelope_preamble;

typedef struct {
} Shm_Envelope_postamble;

/* WARNING! If you change this structure, don't forget to change
 *          SHM_ENVELOPE_PREFIX_OVERHEAD and
 *          Shm_Packet_prefix_to_envelope_control_pointer() above.
 */

/*  This comment block describes the contents of each field
 *  of the Envelope Control Block:
 *
 *  next      - The index of the next envelope on this queue.
 *  queue     - The index of the queue this envelope is on.
 *  index     - The index of this envelope.
 *  Preamble  - Generic packet preamble.  One day this structure
 *              could be enhanced to contain routing information.
 *  packet    - RTEMS MPCI packet.  Untouched by SHM Driver
 *              other than copying and format conversion as
 *              documented in the RTEMS User's Guide.
 *  Postamble - Generic packet postamble.  One day this structure
 *              could be enhanced to contain checksum information.
 */

typedef struct {
  vol_u32           next;     /* next envelope on queue       */
  vol_u32           queue;    /* queue on which this resides  */
  vol_u32           index;    /* index into array of envelopes*/
  vol_u32           pad0;     /* insure the next one is aligned */
  Shm_Envelope_preamble    Preamble; /* header information           */
  vol_u8            packet[MAX_PACKET_SIZE]; /* RTEMS INFO    */
  Shm_Envelope_postamble   Postamble;/* trailer information          */
} Shm_Envelope_control;

/*  This comment block describes the contents of each field
 *  of the Locked Queue Control Block:
 *
 *  lock      - Lock used to insure mutually exclusive access.
 *  front     - Index of first envelope on queue.  This field
 *              is used to remove head of queue (receive).
 *  rear      - Index of last envelope on queue.  This field
 *              is used to add evelope to queue (send).
 *  owner     - The node number of the recipient (owning) node.
 *              RTEMS does not use the node number zero (0).
 *              The zero node is used by the SHM Driver for the
 *              Free Envelope Queue shared by all nodes.
 */

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;

/*  This comment block describes the contents of each field
 *  of the Node Status Control Block:
 *
 *  status    - Node status.  Current values are Pending Initialization,
 *              Initialization Complete, and Active Node.  Other values
 *              could be added to enhance fault tolerance.
 *  error     - Zero if the node has not failed.  Otherwise,
 *              this field contains a status indicating the
 *              failure reason.
 *  int_address, int_value, and int_length
 *            - These field are the Interrupt Information table
 *              for this node in neutral format.  This is how
 *              each node knows how to generate interrupts.
 */

typedef struct {
  vol_u32  status;         /* node status information     */
  vol_u32  error;          /* fatal error code            */
  vol_u32  int_address;    /* write here for interrupt    */
  vol_u32  int_value;      /* this value causes interrupt */
  vol_u32  int_length;     /* for this length (0,1,2,4)   */
  vol_u32  not_currently_used_0;
  vol_u32  not_currently_used_1;
  vol_u32  not_currently_used_2;
} Shm_Node_status_control;

/*  This comment block describes the contents of each field
 *  of the Interrupt Information Table.  This table describes
 *  how another node can generate an interrupt to this node.
 *  This information is target board dependent.  If the
 *  SHM Driver is in POLLED_MODE, then all fields should
 *  be initialized to NO_INTERRUPT.
 *
 *  address   - The address to which another node should
 *              write to cause an interrupt.
 *  value     - The value which must be written
 *  length    - The size of the value to write.  Valid
 *              values are BYTE, WORD, and LONG.
 *
 *  NOTE:  The Node Status Control Block contains this
 *         information in neutral format and not in a
 *         structure to avoid potential alignment problems.
 */

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;

/*  SHM Configuration Table
 *
 *  This comment block describes the contents of each field
 *  of the SHM Configuration Table.
 *
 *  base       - The base address of the shared memory.  This
 *               address may be specific to this node.
 *  length     - The length of the shared memory in bytes.
 *  format     - The natural format for rtems_unsigned32's in the
 *               shared memory.  Valid values are currently
 *               only SHM_LITTLE and SHM_BIG.
 *  convert    - The address of the routine which converts
 *               between neutral and local format.
 *  poll_intr  - The operational mode of the driver.  Some
 *               target boards may not provide hardware for
 *               an interprocessor interrupt.  If POLLED_MODE
 *               is selected, the SHM driver will install a
 *               wrapper around the Clock_isr() to poll for
 *               incoming packets.  Throughput is dependent
 *               on the time between clock interrupts.
 *               Valid values are POLLED_MODE and INTR_MODE.
 *  cause_intr - This is the address of the routine used to
 *               write to a particular address and cause an
 *               interrupt on another node.  This routine
 *               may need to be target dependent if something
 *               other than a normal write from C does not work.
 *  Intr       - This structure describes the operation required
 *               to cause an interrupt to this node.  The actual
 *               contents of this structure are described above.
 */

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)( rtems_unsigned32 );
  Shm_Interrupt_information   Intr;     /* cause intr information      */
};

typedef struct shm_config_info shm_config_table;

/* global variables */

#ifdef _SHM_INIT
#define SHM_EXTERN
#else
#define SHM_EXTERN extern
#endif

SHM_EXTERN shm_config_table             *Shm_Configuration;
SHM_EXTERN Shm_Interrupt_information    *Shm_Interrupt_table;
SHM_EXTERN Shm_Node_status_control      *Shm_Node_statuses;
SHM_EXTERN Shm_Locked_queue_Control     *Shm_Locked_queues;
SHM_EXTERN Shm_Envelope_control         *Shm_Envelopes;
SHM_EXTERN rtems_configuration_table    *Shm_RTEMS_Configuration;
SHM_EXTERN rtems_multiprocessing_table  *Shm_RTEMS_MP_Configuration;
SHM_EXTERN rtems_unsigned32              Shm_Receive_message_count;
SHM_EXTERN rtems_unsigned32              Shm_Null_message_count;
SHM_EXTERN rtems_unsigned32              Shm_Interrupt_count;
SHM_EXTERN rtems_unsigned32              Shm_Local_node;
SHM_EXTERN Shm_Locked_queue_Control      *Shm_Local_receive_queue;
SHM_EXTERN Shm_Node_status_control       *Shm_Local_node_status;
SHM_EXTERN rtems_unsigned32              Shm_isrstat;
                                                     /* reported by shmdr */

SHM_EXTERN rtems_unsigned32 Shm_Pending_initialization;
SHM_EXTERN rtems_unsigned32 Shm_Initialization_complete;
SHM_EXTERN rtems_unsigned32 Shm_Active_node;

SHM_EXTERN rtems_unsigned32 Shm_Maximum_nodes;
SHM_EXTERN rtems_unsigned32 Shm_Maximum_envelopes;

SHM_EXTERN rtems_unsigned32 Shm_Locked_queue_End_of_list;
SHM_EXTERN rtems_unsigned32 Shm_Locked_queue_Not_on_list;

/* functions */

/* locked queue routines */
void           Shm_Locked_queue_Add(
                  Shm_Locked_queue_Control *, Shm_Envelope_control * );
Shm_Envelope_control *Shm_Locked_queue_Get( Shm_Locked_queue_Control * );
void           Shm_Locked_queue_Initialize(
                  Shm_Locked_queue_Control *, rtems_unsigned32 );
            /* Shm_Initialize_lock is CPU dependent */
            /* Shm_Lock is CPU dependent */
            /* Shm_Unlock is CPU dependent */

/* portable routines */
void           Init_env_pool();
void           Shm_Print_statistics( void );
void           MPCI_Fatal( Internal_errors_Source, boolean, rtems_unsigned32 );
rtems_task     Shm_Cause_interrupt( rtems_unsigned32 );
void           Shm_Poll();
void           Shm_setclockvec();
void           Shm_Convert_packet( rtems_packet_prefix * );

/* CPU specific routines are inlined in shmcpu.h */

/* target specific routines */
void          *Shm_Convert_address( void * );
void           Shm_Get_configuration( rtems_unsigned32, shm_config_table ** );
void           Shm_isr();
void           Shm_setvec( void );

void           Shm_Initialize_lock( Shm_Locked_queue_Control * );
void           Shm_Lock( Shm_Locked_queue_Control * );
void           Shm_Unlock( Shm_Locked_queue_Control * );

/* MPCI entry points */
rtems_mpci_entry Shm_Get_packet(
  rtems_packet_prefix **
);

rtems_mpci_entry Shm_Initialization( void );

rtems_mpci_entry Shm_Receive_packet(
  rtems_packet_prefix **
);

rtems_mpci_entry Shm_Return_packet(
  rtems_packet_prefix *
);

rtems_mpci_entry Shm_Send_packet(
  rtems_unsigned32,
  rtems_packet_prefix *
);

extern rtems_mpci_table MPCI_table;

#ifdef _SHM_INIT

/* multiprocessor communications interface (MPCI) table */

rtems_mpci_table MPCI_table  = {
  100000,                     /* default timeout value in ticks */
  MAX_PACKET_SIZE,            /* maximum packet size */
  Shm_Initialization,         /* initialization procedure   */
  Shm_Get_packet,             /* get packet procedure       */
  Shm_Return_packet,          /* return packet procedure    */
  Shm_Send_packet,            /* packet send procedure      */
  Shm_Receive_packet          /* packet receive procedure   */
};

#endif

#ifdef __cplusplus
}
#endif

#endif
/* end of include file */