You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 17 Next »

Concepts

The low-level interface to an RCE's protocol plug-ins uses abstractions called ports, frames, channels, local ports and drivers.

A port is the RCE end of a communications link similar in concept to a BSD socket. Ports are globally visible but not MT-safe; at any given time only one thread may be waiting for incoming data on a given port. Some ports are predefined, i.e., created by before any application code is called.

Ports deliver data as frames. The exact content of a frame depends on the transmission protocol being used but at the port recognizes a division into header and payload. One frame corresponds to one message on the I/O medium and is delivered in a single buffer. In other words all ports implement datagram rather than byte-stream protocols. It's up to higher-level software such as a TCP stack to provide any operations that cross frame boundaries. Each port contains a queue of frames which have arrived and not yet been consumed by the application.

A channel is a hardware I/O engine capable of DMA to and from system RAM, i.e., a protocol plug-in. Most channels will make use of one or more of the Multi-Gigabit Tranceiver modules available in firmware, though some may simply offer access to on-board resources such as DSPs. Each channel has its own "local port" space where each local port is identified by a 16-bit unsigned integer. Each local port represents a different source of incoming data such as a UDP port or a Petacache flash lane. Some local ports will be predefined in the sense of being made ready for use early during system initialization, others may be created later if the driver allows it. Predefined local ports may not be destroyed but any others may be.

With one exception there is a one-to-one correspondence between (channel, local port) and ports. Therefore for each predefined local port there will be a predefined port object. One data container in configuration flash will contain a table of the predefined ports available on the RCE plus related information enabling the RCE core software to find the required drivers, etc.

The exception to the rule of correspondence between port and local port is the predefined "default" port, which receives data that doesn't "belong" to any other port.

Any attempt to close or destroy a predefined port will be ignored.

A channel is not obliged to predefine any local ports, in which case the channel's presence won't be detected by looking in the table of predefined ports; the table of channels will have to be searched.

Each channel has exactly one device driver whose object code fits into a single container in the configuration flash. A device driver is just a module as defined by the RCE dynamic linker; its rce_appmain() function initializes the driver. Early in the system init. process the RCE core code loads the device driver modules into system RAM and links them all together with the default instance of the linker. It then calls the rce_appmain() of each driver (no order guaranteed). Technically this allows a driver to depend on other drivers but DON'T DO IT. A driver should depend only on the RCE core. Later on the same instance of the linker used for the drivers is used to link the main application module, making it possible for the application code to use the drivers as simple libraries if they export any functions or classes for other modules. A driver might export nothing directly but instead register a new device in the RTEMS in-memory filesystem.

Port and channel information in configuration flash

Data container zero in the configuration flash contains tables providing all the information needed to make ready the all channels and predefined ports. This includes references to device driver code but not the code itself; other containers will hold driver code. In addition the tables provide some extra information not actually needed for setup but required to print a summary of what the protocol plug-ins provide.

The tables are called Ports, Channels, Channel Classes, Bandwidths, Drivers and Strings. Except for Strings each table is an array of plain-old-data structs with the first field being a key or ID field normally equal to the array index. An ID equal to 0xffffffff signifies the end of the table in which case none of the other fields in the struct have any guaranteed values and should never be read. Thus you'll generate end-of-table sentinels automatically when you erase a flash block before writing tables into it, provided you leave at least one 32-bit word of unwritten space at the end of each table. If you write all the tables in one go then you must provide the end-of-table markers explicitly.

The Strings table is like an ELF string table; NUL-terminated ASCII strings laid end to end. Certain standard strings such as the short-names of channels are at the front of the table with only one instance of each string present. The other tables refer to a string by giving the offset of its first character in the Strings table.

General layout of the container contents

The first words of the container are the 32-bit offsets in the container to the starts of the tables in the following order:

Offset of Ports

Offset of Channels

Offset of Channel Classes

Offset of Bandwidths

Offset of Drivers

Offset of Strings

Each of the offsets should be divisible by four.

After that come the tables themselves. No particular order is required, though since String table entries have variable length it's most convenient to place it last.

To make alignment easier we use 32-bit fields wherever possible, even for 16-bit quantities such as local port numbers.

typedef uint32_t StringOff; // Offset within the Strings table.

The Ports table

struct Port {
    uint32_t  id;             // Unique port number.
    uint32_t  channelId;      // Ref. to Channels table.
    uint32_t  localPort;      // Port's number within the channel.
    StringOff description;    // A short description of the port.
};

The Channels table

struct Channel {
    uint32_t id;              // Unique channel number.
    unit32_t idWithinClass;   // Class-unique 0, 1, ... .
    unit32_t classId;         // Ref. to Channel Classes table.
    StringOff description;
};

The Channel Classes table

struct ChannelClass {
    uint32_t  id;
    uint32_t  driverId;
    unit32_t  bandwidthId;
    StringOff shortName;
    StringOff description;
};

The Drivers table

Struct Driver {
    uint32_t  id;
    uint32_t  containerName;
    StringOff description;
};

The Bandwidths table

struct Bandwidth {
    uint32_t  id;
    StringOff description;
};

On Virtex-4 RCEs the bandwidth ID is just the number of Multi-Gigabit Tranceivers used by the plug-in. The ID zero is reserved for non-network plug-ins.

Example configuration tables

Here's what the tables would look like for an Virtex-4 RCE that defines nothing but the standard facilities that all RCEs have regardless of application:

The Ports table:

ID

Channel ID

Local ID

Description

0

0

0

"LAN"

1

1

0

"Configuration flash"

The Channels table:

ID

Id in class

Class ID

Description

0

0

0

"LAN"

1

0

1

"Configuration flash"

The Channel Classes table:

ID

Driver ID

Bandwidth ID

Short name

Description

0

0

4

"eth"

"ethernet"

1

1

0

"config"

"Configuration flash"

The Drivers table:

ID

Container name

Description

0

<name1>

"Virtex-4 10 Gb/s ethernet"

1

<name2>

"Virtex-4 configuration flash"

The Bandwidths table:

ID

Description

0

"non-network"

1

"2.5 Gb/s"

2

"5.0 Gb/s"

3

"7.5 Gb/s"

4

"10.0 Gb/s"

API used by drivers

API provided by drivers

Frames

Sequence of operations at system startup

Basic PowerPC setup

RTEMS

C++ runtime environment

Dynamic linker

Predefined ports

Drivers

Local ports

Port objects

Init task

UDP and TCP

DHCP

Application task

  • No labels