NAME | SYNOPSIS | API RESTRICTIONS | FEATURES | DESCRIPTION | EXTENDED DESCRIPTION | ATTRIBUTES | SEE ALSO
#include <ddi/busmux/busmux.h>
The function or functions documented here may not be used safely in all application contexts with all APIs provided in the ChorusOS 5.0 product.
See API(5FEA) for details.
DDI
Provides an API for the development of standard protocol stacks (or standard pseudo-drivers) on a multicomputing system inter-connected over an I/O bus.
This basic communication layer is composed of three (logical) device classes:
Bus multiplexer device.
Receive channel device.
Transmit channel device.
Each of these device classes provides a separate device driver interface described below.
The bus multiplexer driver is a client of the local and all remote BusCom driver instances running on the site.
The main role of the bus multiplexer driver is to inform its clients about an inital configuration of the communication domain and all configuration changes (that is, site insertion/removal) that happen in the domain. In addition, the bus multiplexer driver allows a client to create (and to destroy) a communication channel with a remote site. Such a communication channel is represented by a receive channel device on the local site and a transmit channel device on the remote site.
The character string "busmux" (alias BUSMUX_CLASS) names the BusMux device class. A pointer to the BusMuxOps structure is exported by the driver via the svDeviceRegister microkernel call. A driver client invokes the svDeviceLookup and svDeviceEntry microkernel calls in order to obtain a pointer to the device service routines vector. Once the pointer is obtained, the driver client is able to invoke the driver service routines via indirect function calls.
A BusMux driver is multi client device driver. In other words, a BusMux device driver instance may be looked up multiple times in the device registry.
typedef BusComSite BusMuxSite; typedef BusComSize BusMuxSize; typedef uint32_f BusMuxProto; typedef uint32_f BusMuxChannel; typedef struct BusMuxOps { BusMuxVersion version; KnError (*open) (BusMuxId id, BusMuxProto proto, BusMuxHandler handler, void* cookie, BusMuxConnId* cid); KnError (*create) (BusMuxConnId cid, BusMuxChannel channel, BusMuxSite site, BusMuxSize fifosize); void (*destroy) (BusMuxConnId cid, BusMuxChannel channel); void (*close) (BusMuxConnId cid); } BusMuxOps;
The version field specifies the maximum BusMux DDI version number supported by the driver.
The version number is incremented each time one of the BusMux DDI structures is extended in order to include new service routines. In other words, a new symbol is added to the BusMuxVersion enum each time the API is extended in this way.
A driver client specifies a minimum DDI version number required by the client when calling svDeviceLookup(). The svDeviceLookup() routine does not allow a client to look up a driver instance if the DDI version number supported by the driver is less than the DDI version number required by the client.
A client that is aware of DDI extensions may still specify a minimum DDI version when looking for a device in the registry. Once a device is successfully found, the client may examine the version field in order to take advantage of extended DDI features which may be supported by the device driver.
The open() method is the first call a client must make to a BusMux device driver. The open() call is used to establish a connection to the driver. It enables the subsequent invocation of the create(), destroy() and close() routines.
The id input argument specifies a given BusMux device driver instance. It is provided by the device registry entry.
The proto input argument specifies a communication protocol implemented by the client. It is an integer value which should be arbitrarily assigned to all high level communication protocols (for example, Ethernet, ATM).
The handler input argument specifies a client notification handler. This handler will be invoked by the BusMux driver each time a site insertion or removal is detected in the communication domain.
The cookie input argument is passed back to the client as an argument of the notification handler.
typedef enum { BUSMUX_SITE_CONNECTED = 1, BUSMUX_SITE_DISCONNECTED = 2 } BusMuxEvent; typedef void (*BusMuxHandler) (void* cookie, BusMuxEvent event, BusMuxSite site);
Together with the cookie argument, the notification handler also has two extra arguments. The event input argument specifies whether a site insertion or removal is detected in the communication domain. The BUSMUX_SITE_CONNECTED value means that a site has been inserted. The BUSMUX_SITE_DISCONNECTED value means that a site is removed. The site input argument specifies the site which has been inserted or removed.
The notification handler is called in the DKI thread context. This allows a client to directly invoke the create() and destroy() routines inside the handler.
Upon successful completion, the BusMux driver returns K_OK and passes back to the client a connection identifier through the cid output argument. The connection identifier must be given to the BusMux driver in all subsequent invocation of the driver.
Note that the notification handler may be called by the BusMux driver before returning from open(). This typically happens for all remote sites already present in the communication domain at open time. In this case, the BusMux driver guarantees that the cid output argument is already updated when the notification handler is invoked.
The BusMux driver returns K_ENOMEM if the system is out of memory resources.
The BusMux driver returns K_EBUSY if another connection has been already established for a given protocol.
If an error code is returned by the BusMux driver, the cid output argument is not altered.
The open() method must be called in the DKI thread context.
The create() method is used to create a simplex (that is, unidirectional) communication channel with a remote site belonging to the communication domain.
The cid input argument specifies an open connection to the BusMux driver. It is given by open().
The channel input argument specifies the channel number being created.
The site input argument specifies a remote site to which the channel will be created.
The fifosize input argument specifies the memory size (in bytes) being allocated for the channel FIFO.
Upon successful completion, the BusMux driver returns K_OK and creates a receive channel device on the local site. At the same time, a transmit channel device is also created on the remote site. Note that the channel creation is asynchronous. In other words, the BusMux driver does not guarantee that both (transmit and receive) channels are created when returning from create. A channel client should use a new device notification mechanism provided by the device registry module. This means that, in order to be notified when a new channel is created, a client should attach a new device notification handler to the device registry. When such a handler is invoked by the registry, the client should scan the device registry in order to look up a newly created channel device.
The BusMux driver returns K_ENOMEM if the system is out of memory resources.
The BusMux driver returns K_EOVERLAP if the system is out of the shared memory resources. In other words, there is not enough free space in the shared memory region to locate the channel descriptor and channel FIFO of a given size.
The BusMux driver returns K_EBUSY if another connection with the same channel number already exists for a given protocol.
The create() method must be called in the DKI thread context.
The destroy() method is used to destroy a given simplex communication channel which has been previously created via the create() routine.
The cid input argument specifies an open connection to the BusMux driver. It is given by open().
The channel input argument specifies the channel number being destroyed.
Note that the function does nothing if a given channel does not exist.
Note that the channel destruction is asynchronous. In other words, the BusMux driver does not guarantee that both (transmit and receive) channels are destroyed when returning from destroy(). The destroy() routine just starts the destruction process sending a shutdown event on both channel devices. Such a shutdown event will be received by channel clients on both sites. A channel will only be destroyed when both channel clients release both channel devices on local and remote sites.
The destroy() method must be called in the DKI thread context.
The close() method is used to close connection to a BusMux driver. This call must be the last call made to the BusMux driver.
The cid input argument specifies an open connection to the BusMux driver. It is provided by open().
Note that the close routine will destroy all previously created channels. Note also that the channels will be destroyed asynchronously.
The close() method must be called in the DKI thread context.
The character string "busmux-rx" (alias BUSMUX_RX_CLASS) names the BusMux Rx channel device class. A pointer to the BusMuxRxOps structure is exported by the driver via the svDeviceRegister() microkernel call. A driver client invokes the svDeviceLookup() and svDeviceEntry() microkernel calls in order to obtain a pointer to the device service routines vector. Once the pointer is obtained, the driver client is able to invoke the driver service routines via indirect function calls.
A BusMux Rx channel driver is mono-client device driver. The device registry prevents multiple lookups being done on the same driver instance.
typedef struct BusMuxRxOps { BusMuxRxVersion version; KnError (*open) (BusMuxRxId id, BusMuxRxHandler handler, void* cookie); void (*mask) (BusMuxRxId id); void (*unmask) (BusMuxRxId id); Bool (*receive) (BusMuxRxId id, BusMuxFrame* frame); void (*free) (BusMuxRxId id); void (*close) (BusMuxRxId id); } BusMuxRxOps;
The version field specifies the maximum BusMux Rx channel DDI version number supported by the driver.
The version number is incremented each time one of the BusMux Rx channel DDI structures is extended in order to include new service routines. In other words, a new symbol is added to the BusMuxRxVersion enum each time the API is extended in this way.
A driver client specifies a minimum DDI version number required by the client when calling svDeviceLookup. The svDeviceLookup routine does not allow a client to look up a driver instance if the DDI version number supported by the driver is less than the DDI version number required by the client.
A client that is aware of DDI extensions may still specify a minimum DDI version when looking for a device in the registry. Once a device is successfully found, the client may examine the version field in order to take advantage of extended DDI features which may be supported by the device driver.
The open() method is the first call a client must make to a BusMux Rx channel device driver. The open() call is used to establish a connection to the driver. It enables the subsequent invocation of the mask(), unmask(), receive(), free() and close() routines.
The id input argument specifies a given BusMux Rx channel device driver instance. It is given by the device registry entry.
The handler input argument specifies a client Rx handler. This handler is normally invoked by the BusMux Rx channel driver if the following conditions are met:
Last invoked receive has returned FALSE, in other words, a client has detected that the channel FIFO is empty.
The channel FIFO is not currently empty.
The channel is unmasked.
The cookie input argument is passed back to the client as the argument of the Rx handler.
typedef void (*BusMuxRxHandler) (void* cookie);
Note that the Rx handler may be falsely invoked by the BusMux Rx channel driver. This is due to a weak synchronization between the Rx and Tx channel drivers. The channel drivers do not utilize an atomic read-modify-write cycle. Such a feature may be unavailable on some busses (PCI for example). The channel drivers also avoid handling a classical mutual exclusion spin lock based on two variables. Such a spin lock would introduce unnecessary dependencies between the Tx and Rx channel drivers. In particular, when one site is suddenly down holding such a lock. This results in an inexact flow control which may introduce (usually a small number) of spurious (unnecessary) interrupts.
When the Rx handler is called, the channel is in a masked state. In other words, the BusMux Rx channel driver protects from re-entry in the Rx handler code. The channel is unmasked once the Rx handler returns to the BusBux Rx channel driver.
Upon successful completion, the BusMux Rx channel driver returns K_OK. Otherwise, K_ENOMEM is returned to notify that the system is out of memory resources.
Note that the channel is in a masked state by default, that is, the Rx handler invocation is disabled. In order to enable the Rx handler invocation, the unmask() routine should be called.
The open() method may block. So, it must be called at base level only.
The mask() method disables the invocation of the Rx handler if it has been previously enabled by unmask().
The id input argument specifies a given BusMux Rx channel device driver instance. It is given by the device registry entry.
The mask() method must be called at base level only.
The unmask() method enables invocation of the Rx handler if it has been disabled either implicitly by open or explicitly by a previously invoked mask() routine.
The id input argument specifies a given BusMux Rx channel device driver instance. It is provided by the device registry entry.
Note that interrupts received during a masked period are not lost. Once the channel is unmasked, the Rx handler is invoked if conditions listed above are met.
The unmask() method must be called at base level only. The mask()/unmask() pairs must not be nested.
The receive() method is invoked by a client in order to obtain a pointer to the first frame of the channel FIFO.
The id input argument specifies a given BusMux Rx channel device driver instance. It is provided by the device registry entry.
If the channel FIFO is empty, the receive() routine returns FALSE. Otherwise, the receive() routine returns TRUE and passes the frame descriptor (back to the client) through the frame output argument.
A BusMux frame is specified by the BusMuxFrame structure. A frame may contain up to two fragments: head and tail. Each fragment is specified by the BusMuxChunk structure. The addr field of the BusMuxChunk structure specifies the start address of the frame fragment in the supervisor address space. The size field of the BusMuxChunk structure specifies the frame fragment size in bytes. If the tail size is zero, the frame is contiguous and the frame start address and size are specified by the head descriptor. Otherwise, the frame is fragmented.
typedef struct BusMuxChunk { uint8_f* addr; BusMuxSize size; } BusMuxChunk; typedef struct BusMuxFrame { BusMuxChunk head; BusMuxChunk tail; } BusMuxFrame;
The frame head start address is always aligned to a four byte boundary. If frame is not contiguous, the head size and the tail start address are also always aligned to a four byte boundary.
After a successful receive(), a client is able to access the frame contents located into the channel FIFO.
Note that it is allowed to sequentially call the receive() method multiple times. Once the receive() routine returns TRUE, the subsequent invocation of the receive() method will return the same frame descriptor.
The receive() method must be called either at base level or from the Rx handler.
The free() method is invoked by a client in order to free memory occupied by the first frame in the channel FIFO. The released memory becomes available for transmission.
The id input argument specifies a given BusMux Rx channel device driver instance. It is provided by the device registry entry.
If the channel FIFO is empty, the free() routine behavior is unpredictable.
The free() method must be called either at base level or from the Rx handler.
The close() method is used to close connection to a BusMux Rx channel driver. This call must be the last call made to the driver.
The id input argument specifies a given BusMux Rx channel device driver instance. It is provided by the device registry entry.
The close() method may block. Therefore, it must be called at base level only.
The character string "busmux-tx" (alias BUSMUX_TX_CLASS) names the BusMux Tx channel device class. A pointer to the BusMuxTxOps structure is exported by the driver via the svDeviceRegister() microkernel call. A driver client invokes the svDeviceLookup() and svDeviceEntry() microkernel calls in order to obtain a pointer to the device service routines vector. Once the pointer is obtained, the driver client is able to invoke the driver service routines via indirect function calls.
A BusMux Tx channel driver is a mono client device driver. The device registry prevents multiple lookups being done on the same driver instance.
typedef struct BusMuxTxOps { BusMuxTxVersion version; KnError (*open) (BusMuxTxId id, BusMuxSize threshold, BusMuxTxHandler handler, void* cookie); void (*mask) (BusMuxTxId id); void (*unmask) (BusMuxTxId id); Bool (*alloc) (BusMuxTxId id, BusMuxSize size, BusMuxFrame* frame); void (*transmit) (BusMuxTxId id); void (*close) (BusMuxTxId id); } BusMuxTxOps;
The version field specifies the maximum BusMux Tx channel DDI version number supported by the driver.
The version number is incremented each time one of the BusMux Tx channel DDI structures is extended in order to include new service routines. In other words, a new symbol is added to the BusMuxRxVersion enum each time the API is extended in this way.
A driver client specifies a minimum DDI version number required by the client when calling svDeviceLookup(). The svDeviceLookup() routine does not allow a client to look up a driver instance if the DDI version number supported by the driver is less than the DDI version number required by the client.
A client that is aware of DDI extensions may still specify a minimum DDI version when looking for a device in the registry. Once a device is successfully found, the client may examine the version field in order to take advantage of extended DDI features which may be supported by the device driver.
The open() method is the first call a client must make to a BusMux Tx channel device driver. The open() call is used to establish a connection to the driver. It enables the subsequent invocation of the mask(), unmask(), alloc(), transmit() and close() routines.
The id input argument specifies a given BusMux Tx channel device driver instance. It is given by the device registry entry.
The threshold input argument specifies a channel FIFO threshold. If threshold value is greater than the FIFO size, it is adjusted to the FIFO size. Note that if the channel FIFO threshold is set to zero, the Tx handler invocation is disabled.
The handler input argument specifies a client Tx handler. This handler is invoked by the BusMux Tx channel driver if the following conditions are met:
The last invoked alloc has returned FALSE, in other words, a client has detected that the channel FIFO is full.
The channel FIFO threshold is not zero.
The channel FIFO free size is equal to or grater than the channel FIFO threshold.
The channel is unmasked.
The cookie input argument is passed back to the client as the argument of the Tx handler.
typedef void (*BusMuxTxHandler) (void* cookie);
Note that the Tx handler may be falsely invoked by the BusMux Tx channel driver. This is due to a weak synchronization between the Rx and Tx channel drivers. The channel drivers do not utilize an atomic read-modify-write cycle. Such a feature may be unavailable on some busses (PCI for example). The channel drivers also avoid handling a classical mutual exclusion spin lock based on two variables. Such a spin lock would introduce unnecessary dependencies between the Tx and Rx channel drivers. In particular, when one site is suddenly down holding such a lock. This results in an inexact flow control which may introduce (usually a small number) of spurious (unnecessary) interrupts.
When the Tx handler is called, the channel is in a masked state. In other words, the BusMux Tx channel driver protects from re-entry in the Tx handler code. The channel is unmasked once the Tx handler returns to the BusBux Tx channel driver.
Upon successful completion, the BusMux Tx channel driver returns K_OK. Otherwise, K_ENOMEM is returned to notify that the system is out of memory resources.
Note that the channel is in a masked state by default, that is, the Tx handler invocation is disabled. In order to enable the Tx handler invocation, the unmask() routine should be called.
The open() method may block. Therefore, it must be called at base level only.
The mask() method disables invocation of the Tx handler if it has been previously enabled by unmask().
The id input argument specifies a given BusMux Tx channel device driver instance. It is given by the device registry entry.
The mask() method must be called at base level only.
The unmask() method enables invocation of the Tx handler if it has been disabled either implicitly by open or explicitly by a previously invoked mask() routine.
The id input argument specifies a given BusMux Rx channel device driver instance. It is given by the device registry entry.
Note that interrupts received during a masked period are not lost. Once the channel is unmasked, the Tx handler is invoked if conditions listed above are met.
The unmask() method must be called at base level only. The mask()/unmask() pairs must not be nested.
The alloc() method is invoked by a client in order to allocate space for a frame in the channel FIFO.
The id input argument specifies a given BusMux Tx channel device driver instance. It is given by the device registry entry.
The size input argument specifies the frame size. Note that, because a frame in the channel FIFO is prefixed by its size, there are extra four bytes (that is, sizeof(BusMuxSize)) which need to be allocated in the channel FIFO for each frame.
If the channel FIFO is full (that is, there is no room for frame of a given size), the alloc() routine returns FALSE. Otherwise, the alloc() routine returns TRUE and passes the frame descriptor (back to the client) through the frame output argument.
A BusMux frame is specified by the BusMuxFrame structure. A frame may contain up to two fragments: head and tail. Each fragment is specified by the BusMuxChunk structure. The addr field of the BusMuxChunk structure specifies the start address of the frame fragment in the supervisor address space. The size field of the BusMuxChunk structure specifies the frame fragment size in bytes. If the tail size is zero, the frame is contiguous and the frame start address and size are specified by the head descriptor. Otherwise, the frame is fragmented.
The frame head start address is always aligned to a four byte boundary. If frame is not contiguous, the head size and the tail start address are also always aligned to a four byte boundary.
After a successful alloc(), a client is able to copy frame contents to the channel FIFO. Note that it is possible to sequentially call the alloc() method multiple times. In this case, current alloc() overrides the previous one.
The alloc() method must be called either at base level or from the Tx handler.
The transmit() method is invoked by a client in order to start transmission of the previously allocated frame.
The id input argument specifies a given BusMux Tx channel device driver instance. It is given by the device registry entry.
If there is no frame allocated in the channel FIFO, the transmit() routine behavior is unpredictable. In other words, a transmit() routine invocation should always follow the successful invocation of alloc().
The transmit() method must be called either at base level or from the Tx handler.
The close() method is used to close connection to a BusMux Tx channel driver. This call must be the last call made to the driver.
The id input argument specifies a given BusMux Tx channel device driver instance. It is provided by the device registry entry.
The close() method may block. Therefore, it must be called at base level only.
A BusMux device node has a "site" (alias BUSMUX_PROP_SITE) property. The property value type is BusMuxSite. The property value specifies the local site identifier.
A BusMux Rx/Tx channel node has a "channel" (alias BUSMUX_PROP_CHANNEL) property. The property value is a BusMuxPropChannel structure which specifies the characteristics of a given communication channel.
typedef struct BusMuxPropChannel { BusMuxSite lsite; BusMuxSite rsite; BusMuxProto proto; BusMuxChannel channel BusMuxSize fifosize; Bool lbswap; Bool rbswap; } BusMuxPropChannel;
The lsite field specifies the local site identifier.
The rsite field specifies the remote site identifier.
The proto field specifies the channel protocol. It is provided at channel creation time.
The channel field specifies the channel identifier. It is provided at channel creation time.
The fifosize field specifies size (in bytes) of the channel FIFO. It is provided at the channel creation time.
The lbswap field specifies whether the shared memory byte order is inverted with respect to the local memory. Obviously, lbswap is always FALSE for an Rx channel because the channel descriptor and FIFO are located in the local memory on the receiver site. Note that if lbswap is TRUE, a general purpose bcopy() (or memcpy()) routine cannot typically be used to copy a transmitting frame to the channel FIFO. This is due to the fact that such a bcopy() routine is usually optimized to use word (4 bytes) or double word (8 bytes) load/store instructions if possible. So, this does not work if the byte order is inverted between the source and destination memory.
The rbswap field specifies whether the shared memory byte order is inverted with respect to the memory mapping on the remote site. Note that rbswap is always FALSE for an Rx channel. So, the byte swapping (if needed) is always performed on a transmitter site.
When the BusMux driver receives a shutdown event from the local or a remote BusCom driver instance, it forwards the event to BusMux and Rx/Tx channel clients using the following strategy.
If a shutdown event is received from the local BusCom device, it is signaled on the BusMux device and all Rx and Tx channels.
If a shutdown event is received from a remote BusCom device, it is signaled on all Rx and Tx channels associated with a given remote site. In addition, the BusMux notification handler is invoked in order to signal the remote site disconnection.
See attributes(5) for descriptions of the following attributes:
ATTRIBUTE TYPE | ATTRIBUTE VALUE |
---|---|
Interface Stability | Evolving |
NAME | SYNOPSIS | API RESTRICTIONS | FEATURES | DESCRIPTION | EXTENDED DESCRIPTION | ATTRIBUTES | SEE ALSO