DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
TOC PREV NEXT INDEX

Bus Bridge Metalanguage

5

5.1 Overview

This chapter details the channel operations and their parameters for the Bus Bridge Metalanguage, which allow a driver for a direct-attached hardware device to communicate with the driver for its parent bus bridge. The device may be a leaf device or another bridge. For purposes of discussion we always refer to the child (furthest from the processor) as the device and the parent as the bridge, and we'll refer to the device driver and the bridge driver.

Each subsection defines the channel operation calls, control block type declarations, the rationale for the operation's existence, constraints and guidelines for the use of each operation, and error conditions that can occur. (The common errors described earlier are not repeated.)

The Bus Bridge Metalanguage operations are grouped into four roles. For each role there's a corresponding channel ops vector, which is registered via an associated udi_ops_init_t structure. The Bus Bridge Metalanguage bridge role supports binding/unbinding and interrupt registration operations invoked on a parent bridge object by a child device driver. The Bus Bridge Metalanguage device role supports binding/unbinding and interrupt registration operations invoked on a child device object by a parent bridge driver. The Bus Bridge Metalanguage interrupt dispatcher role supports interrupt acknowledgment operations invoked on a parent bridge object by a child device driver. The Bus Bridge Metalanguage interrupt handler role supports interrupt event operations invoked on a child device object by a parent bridge driver.

In the Bus Bridge Metalanguage, since each control block type is designed to be used across a group of related operations, a separate control block group is defined per individual type of control block. See udi_cb_init_t for additional information.

Only the udi_intr_event_rdy Bus Bridge Metalanguage operation is abortable with udi_channel_op_abort. None of the Bridge Metalanguage operations are recoverable.

5.1.1 Versioning

All functions and structures defined in this chapter are part of the "udi_bridge" interface, currently at version "0x101". A driver that conforms to and uses the Bus Bridge Metalanguage of the UDI Physical I/O Specification, Version 1.01, must include the following declaration in its udiprops.txt file (see Chapter 30, "Static Driver Properties", of the UDI Core Specification):

requires udi_bridge 0x101
 

Compile-time versioning and header files for the Bus Bridge Metalanguage are covered by the general requirements for the UDI Physical I/O Specification defined in Section 1.2, "General Requirements".

A portable implementation of the Bus Bridge Metalanguage must include a corresponding "provides" declaration in its udiprops.txt file, must conform to the same compile-time versioning and header requirements as for drivers, and must conform to the requirements specified in the Metalanguage-to-Environment (MEI) interface defined in Chapter 27, "Introduction to MEI", of the UDI Core Specification and Chapter 28, "Metalanguage-to-Environment Interface", of the UDI Core Specification.

5.2 Binding/Unbinding Operations

These operations are used during the binding and unbinding of a device driver to a bridge driver.

NAME udi_bus_device_ops_t

Device driver entry point ops vector

SYNOPSIS

#include <udi.h>

typedef const struct {

	udi_channel_event_ind_op_t *channel_event_ind_op;

	udi_bus_bind_ack_op_t *bus_bind_ack_op;

	udi_bus_unbind_ack_op_t *bus_unbind_ack_op;

	udi_intr_attach_ack_op_t *intr_attach_ack_op;

	udi_intr_detach_ack_op_t *intr_detach_ack_op;

} udi_bus_device_ops_t;
 
/* Bus Device Ops Vector Number */
 
#define  UDI_BUS_DEVICE_OPS_NUM				1
 

DESCRIPTION A driver using the Physical I/O services will specify the udi_bus_device_ops_t as part of its udi_init_info in order to register its entry points for managing bus bindings and handling interrupts (as opposed to dispatching interrupts).

REFERENCES udi_init_info, udi_ops_init_t, udi_bus_bridge_ops_t

EXAMPLE The driver's initialization structure definitions might include the following:

#define MY_DEVICE_OPS 10 /* Ops for my child role */

#define MY_BRIDGE_OPS 11 /* Ops for my bridge role */

#define MY_BUS_META   1 /* Meta index for Bus Bridge Metalanguage */

static

   udi_bus_device_ops_t ddd_bus_device_ops = {

	ddd_bus_device_channel_event_ind,

	ddd_bus_bind_ack,

	ddd_bus_unbind_ack,

	ddd_intr_attach_ack,

	ddd_intr_detach_ack

};

...

static udi_ops_init_t ddd_ops_init_list[] = {

	{	MY_DEVICE_OPS,

		MY_BUS_META,

		UDI_BUS_DEVICE_OPS_NUM,

		0, /* chan_context_size */

		(udi_ops_vector_t *)&ddd_bus_device_ops },

	{ 0 }

};
 

NAME udi_bus_bridge_ops_t

Bridge driver entry point ops vector

SYNOPSIS

#include <udi.h>

typedef const struct {

	udi_channel_event_ind_op_t *channel_event_ind_op;

	udi_bus_bind_req_op_t *bus_bind_req_op;

	udi_bus_unbind_req_op_t *bus_unbind_req_op;

	udi_intr_attach_req_op_t *intr_attach_req_op;

	udi_intr_detach_req_op_t *intr_detach_req_op;

} udi_bus_bridge_ops_t;
 
/* Bus Bridge Ops Vector Number */
 
#define  UDI_BUS_BRIDGE_OPS_NUM				2
 

DESCRIPTION A driver using the Physical I/O services and which acts as an "interrupt dispatcher" (as opposed to an "interrupt handler") will specify the udi_bus_bridge_ops_t structure as part of its udi_init_info to register its entry points for managing bus bindings and interrupts attachments/detachments.

REFERENCES udi_init_info, udi_ops_init_t, udi_bus_device_ops_t

EXAMPLE The driver's initialization structure definitions might include the following:

#define MY_DEVICE_OPS 10 /* Ops for my device role */

#define MY_BRIDGE_OPS 11 /* Ops for my bridge role */

#define MY_BUS_META   1 /* Meta index for Bus Bridge Metalanguage */

static

   udi_bus_bridge_ops_t ddd_bus_bridge_ops = {

	ddd_bus_bridge_channel_event_ind,

	ddd_bus_bind_req,

	ddd_bus_unbind_req,

	ddd_intr_attach_req,

	ddd_intr_detach_req

};

...

static udi_ops_init_t ddd_ops_init_list[] = {

	{	MY_DEVICE_OPS,

		MY_BUS_META,

		UDI_BUS_DEVICE_OPS_NUM,

		0, /* chan_context_size */

		(udi_ops_vector_t *)&ddd_bus_device_ops },

	{	MY_BRIDGE_OPS,

		MY_BUS_META,

		UDI_BUS_BRIDGE_OPS_NUM,

		0, /* chan_context_size */

		(udi_ops_vector_t *)&ddd_bus_bridge_ops },

	...

};
 

NAME udi_bus_bind_cb_t

Control block for bus bridge binding operations

SYNOPSIS

#include <udi.h>

typedef struct {

	udi_cb_t gcb;

} udi_bus_bind_cb_t;
 
/* Bus Bind Control Block Group Number */
 
#define  UDI_BUS_BIND_CB_NUM				1
 

MEMBERS gcb is a generic control block header, which includes a pointer to the scratch space associated with this control block. The driver may use the scratch space while it owns the control block, but the values are not guaranteed to persist across channel operations.

DESCRIPTION The bus bind control block is used between the bus device driver and the bus bridge driver to complete binding and unbinding over the bind channel.

This control block must be declared by specifying the control block index value UDI_BUS_BIND_CB_NUM in a udi_cb_init_t in the driver's udi_init_info.

The bus device driver obtains the udi_bus_bind_cb_t structure to use with the udi_bus_bind_req or udi_bus_unbind_req operation by calling udi_cb_alloc with a cb_idx that has been defined for the UDI_BUS_BIND_CB_NUM control block.

REFERENCES udi_bus_bind_cb_t, udi_cb_alloc, udi_bus_bind_req, udi_bus_bind_ack, udi_bus_unbind_req, udi_bus_unbind_ack

NAME udi_bus_bind_req

Request a binding to a bridge driver

SYNOPSIS

#include <udi.h>

void udi_bus_bind_req (

	udi_bus_bind_cb_t *cb );
 

ARGUMENTS cb is a pointer to a bus bind control block.

TARGET CHANNEL The target channel for this operation is the bind channel connecting a device driver with its parent bus bridge driver.

DESCRIPTION A device driver uses this operation to bind to its parent bus bridge driver.

The device driver must prepare for the udi_bus_bind_req operation by allocating a bus bind control block (calling udi_cb_alloc with a cb_idx corresponding to the UDI_BUS_BIND_CB_NUM control block type).

Next, the device driver sends the bus bind control block to the bridge driver with a udi_bus_bind_req operation.

REFERENCES udi_bus_bind_cb_t, udi_bus_bind_ack, udi_bus_unbind_req

NAME udi_bus_bind_ack

Acknowledge a bus bridge binding

SYNOPSIS

#include <udi.h>

void udi_bus_bind_ack (

	udi_bus_bind_cb_t *cb,

	udi_dma_constraints_t dma_constraints,

	udi_ubit8_t preferred_endianness,

	udi_status_t status );
 
/* Values for preferred_endianness */
 
#define  UDI_DMA_BIG_ENDIAN				(1U<<5)
 
#define  UDI_DMA_LITTLE_ENDIAN				(1U<<6)
 
#define  UDI_DMA_ANY_ENDIAN				(1U<<0)
 

ARGUMENTS cb is a pointer to a bus bind control block.

dma_constraints specifies the DMA constraints requirements of the bus bridge. The child driver must apply its own specific constraints attributes to this constraints object (using udi_dma_constraints_attr_set) before using it for its own DMA mappings.

preferred_endianness indicates the device endianness which works most effectively with the bridges in this path. It may be set to one of the following values:

UDI_DMA_LITTLE_ENDIAN
UDI_DMA_BIG_ENDIAN
UDI_DMA_ANY_ENDIAN

status indicates whether or not the binding was successful.

TARGET CHANNEL The target channel for this operation is the bind channel connecting a bus bridge driver with one of its child device drivers.

DESCRIPTION The udi_bus_bind_ack operation is used by a bridge driver to acknowledge binding with a child device driver (or failure to do so, as indicated by status), as requested by a udi_bus_bind_req operation. When a bind is acknowledged with this operation, the bridge driver must be prepared for DMA, PIO, or interrupt registration operations to be performed to the associated device and for the device to begin generating interrupts.

Some devices are bi-endian; that is, they can be placed in either a little-endian mode or a big-endian mode. preferred_endianness provides a hint to drivers for such devices, as to which endianness is likely to be most efficient. If this is set to UDI_DMA_ANY_ENDIAN, at least one interposed bridge is bi-endian, so either endianness can be supported without significant additional cost (i.e. without software byte swapping).

Drivers for fixed-endianness devices can ignore preferred_endianness.

STATUS VALUES UDI_STAT_CANNOT_BIND

warnings The control block must be the same control block as passed to the driver in the corresponding udi_bus_bind_req operation.

REFERENCES udi_bus_bind_cb_t, udi_bus_bind_req, udi_channel_close

NAME udi_bus_unbind_req

Request a bridge driver unbinding (child to bridge)

SYNOPSIS

#include <udi.h>

void udi_bus_unbind_req (

	udi_bus_bind_cb_t *cb );
 

ARGUMENTS cb is a pointer to a bus bind control block.

TARGET CHANNEL The target channel for this operation is the bind channel connecting a device driver with its parent bus bridge driver.

DESCRIPTION A device driver uses this operation to unbind from its parent bus bridge driver.

The device driver must prepare for the udi_bus_unbind_req operation by allocating a bus bind control block (calling udi_cb_alloc with a cb_idx that indicates a udi_bus_bind_cb_t).

Next, the device driver sends the bus unbind control block to the bridge driver with a udi_bus_unbind_req operation.

REFERENCES udi_bus_bind_cb_t, udi_bus_unbind_ack

NAME udi_bus_unbind_ack

Acknowledge a bus bridge unbinding

SYNOPSIS

#include <udi.h>

void udi_bus_unbind_ack (

	udi_bus_bind_cb_t *cb );
 

ARGUMENTS cb is a pointer to a bus bind control block.

TARGET CHANNEL The target channel for this operation is the bind channel connecting a device driver with its parent bus bridge driver.

DESCRIPTION The udi_bus_unbind_ack operation is used by a bridge driver to acknowledge an unbinding with a child device driver as requested by a udi_bus_unbind_req operation.

There is no status parameter associated with this operation; the bridge driver is expected to always be able to handle the unbind request and respond appropriately. If, for example, the bridge driver were to receive an unbind from a child without having first received a bind (or two unbinds in a row from the child), the bridge driver may log this condition but must always respond with this acknowledgment.

warnings The control block must be the same control block as passed to the driver in the corresponding udi_bus_unbind_req operation.

REFERENCES udi_bus_bind_cb_t, udi_bus_unbind_req, udi_channel_close

5.3 Interrupt Registration Operations

These operations are used to register and de-register interrupt handlers for interrupt sources routed through the bus bridge.

NAME udi_intr_attach_cb_t

Control block for interrupt registration operations

SYNOPSIS

#include <udi.h>

typedef struct {

	udi_cb_t gcb;

	udi_index_t interrupt_idx;

	udi_ubit8_t min_event_pend;

	udi_pio_handle_t preprocessing_handle;

} udi_intr_attach_cb_t;
 
/* Bridge Attach Control Block Group Number */
 
#define  UDI_BUS_INTR_ATTACH_CB_NUM				2
 

MEMBERS gcb is a generic control block header, which includes a pointer to the scratch space associated with this control block. The driver may use the scratch space while it owns the control block, but the values are not guaranteed to persist across channel operations.

interrupt_idx is used to select one of possibly several interrupt sources from the interrupt handler's device that are managed by a particular interrupt dispatcher. Zero indicates the first interrupt source for the device, one indicates the second source, etc. The dispatcher driver will have previously associated the handler's device properties with its channel context during the initial binding sequence.

The definition of interrupt_idx is bus and device dependent, and must be determined by the driver via the bus_type instance attribute (see Chapter 15, "Instance Attribute Management" in the UDI Core Specification) in conjunction with the corresponding UDI bus bindings (see "Section 3: Bus Bindings"). For example, if bus_type is "pci" then the settings would be based on the definitions in the UDI PCI Bus Binding Specification.

min_event_pend is the minimum number of interrupt event control blocks that must be supplied to the dispatcher by the handler (via udi_intr_event_rdy operations) before the dispatcher will invoke the preprocessing_handle trans list at start label 0 to enable interrupts from the device. Once invoked at label 0, all subsequent PIO preprocessing will be invoked at label 1 until only a single interrupt event control block remains, at which point label 2 will be used to invoke PIO preprocessing. If no interrupt event control blocks remain, label 3 will be used whenever an interrupt causes the PIO preprocessing to be invoked. Interrupt processing will not exit the "label 3" state until at least min_event_pend control blocks are supplied, at which time label 0 will be invoked and the cycle will repeat. If the number of control blocks available falls below min_event_pend, no action will be taken (PIO processing will continue to be invoked at label 1) until only one control block remains; if the number of control blocks moves back above min_event_pend without ever reaching the lower limit of 1 control block, no specific action will be taken and PIO processing will continue to be invoked at label 1 as normal.

The value for min_event_pend must be at least 2.

max_event_pend is the maximum number of interrupt events the device and driver can have pending at one time. This is a hint to the dispatcher, so it can determine how many event control blocks to allocate for maximum concurrency.

preprocessing_handle is an optional PIO handle to be used to preprocess interrupts. If not null, the interrupt dispatcher will execute the associated PIO transaction list before delivering the interrupt to the interrupt handler. If null, the handler must run in an interrupt region.

DESCRIPTION The interrupt attach control block is used between the interrupt handler and the interrupt dispatcher to attach interrupt handler channels (i.e., register an interrupt handler for a particular interrupt source).

This control block must be declared by specifying the control block index value UDI_BUS_INTR_ATTACH_CB_NUM in a udi_cb_init_t in the driver's udi_init_info.

The bus device driver obtains the udi_intr_attach_cb_t structure to use with the udi_intr_attach_req by calling udi_cb_alloc with a cb_idx that has been associated with UDI_BUS_INTR_ATTACH_CB_NUM.

REFERENCES udi_intr_attach_req, udi_intr_attach_ack, udi_init_info, udi_cb_init_t, udi_cb_alloc

NAME udi_intr_attach_req

Request an interrupt attachment

SYNOPSIS

#include <udi.h>

void udi_intr_attach_req (

	udi_intr_attach_cb_t *intr_attach_cb );
 

ARGUMENTS intr_attach_cb is a pointer to an interrupt attach control block.

TARGET CHANNEL The target channel for this operation is the bound bus bridge channel connecting a device driver with its parent bus bridge driver, established during the initial binding between the child device and its bus bridge.

DESCRIPTION An interrupt handler driver uses this operation to request an interrupt dispatcher driver to begin accepting interrupts for the handler driver's device and delivering them to the handler. If a device has multiple interrupt sources, the interrupt handler indicates which one to attach by using interrupt_idx in the control block.

The handler driver must prepare for the udi_intr_attach_req operation by allocating an interrupt attach control block, filling in the relevant members of the control block, and spawning its end of a new interrupt event channel.

The new channel will be used to send interrupt event operations from the interrupt dispatcher to the handler. The handler driver spawns its end by calling udi_channel_spawn, passing in its end of the bus bridge channel and setting spawn index equal to the interrupt_idx for this attachment. Using interrupt_idx for the spawn index ensures that it is unique with respect to any other spawn operations in progress on the same bus bridge channel, allowing the environment use this index to match up the two parts of the spawn operation.

Next, the interrupt handler sends the interrupt control block to the dispatcher driver with a udi_intr_attach_req operation.

When the interrupt dispatcher driver receives this request, it spawns its end of the new interrupt event channel, calling udi_channel_spawn, passing in its end of the bus bridge channel and using interrupt_idx for the spawn index. The dispatcher then sends a udi_intr_attach_ack operation back on the original channel to the handler driver, which may now reuse the spawn index.

The handler driver can issue an udi_intr_attach_req for an interrupt_idx that is already attached (i.e., uses the same interrupt_idx as an existing attachment), in which case the udi_intr_attach_req simply changes the interrupt pre-processing for that interrupt source and ignores all other parameters. No channels are spawned and no other actions are taken when interrupt pre-processing is updated through this re-attachment operation.

If preprocessing_handle is not null (use UDI_HANDLE_IS_NULL to test it), events on this channel will be preprocessed. Otherwise, the handler driver must ensure that the handler's end of the new channel is anchored in an interrupt region (i.e. a region with the "interrupt" attribute set in the driver's static driver properties; see Section 1.4, "Extensions to Static Driver Properties").

Some of the advantages of interrupt preprocessing are that the interrupt handler does not need to be in an interrupt region and that the udi_intr_event_ind handler code is not restricted in the operations it may perform before responding with udi_intr_event_rdy, unlike in the non-preprocessed case. There are, however, some restrictions on interrupt preprocessing as discussed in detail in the udi_intr_event_ind operation description.

When the preprocessing trans list is executed, the dispatcher will invoke the trans list at one of four start_label entry points (i.e. the trans list should contain UDI_PIO_LABEL transactions for each of these values, with the exception of zero which implies the beginning of the transaction list):

0 The dispatcher will invoke the preprocessing trans list with this start_label value to enable or re-enable interrupts (at the device level), once the dispatcher has received at least min_event_pend interrupt control blocks. When started from this point, the trans list is responsible for enabling interrupts from the device then proceeding as for start_label 1 below (if applicable). Drivers that cannot determine whether their device asserted an interrupt must instead exit with a UDI_INTR_UNCLAIMED result code and not perform label 1 processing.

1 The dispatcher will invoke the preprocessing trans list at this label to handle the normal interrupt condition. The trans list should process the indicated interrupt(s), placing any interrupt information in the associated buffer, and return an appropriate exit code to the dispatcher as defined on page 5-27.

2 The dispatcher will invoke the preprocessing trans list at this label to handle the interrupt overrun condition. This condition occurs when an unmasked interrupt occurs and the dispatcher has only one udi_intr_event_cb_t available from the handler; any subsequent interrupts would not have an event control block or associated buffer to handle the interrupt. The trans list must check for an actual interrupt: if the device is not interrupting, the trans list must return UDI_INTR_UNCLAIMED; if the trans list handles the interrupt completely and no handler notification is needed, then UDI_INTR_NO_EVENT must be returned; in either of these cases the overrun situation is not encountered. Otherwise, the trans list must process the interrupt and then disable further interrupts from the device (if possible). Interrupts will be re-enabled by an entry into the trans list at start_label value 0 after min_event_pending number of additional udi_intr_event_cb_t control blocks have been supplied to the dispatcher by the handler.

3 The dispatcher will invoke the preprocessing trans list at this label to handle any interrupts received during the overrun condition. This entry point is used if interrupts are received after issuing a label 2 preprocessing operation to disable interrupts (i.e. the label position 2 entry point is unable to disable interrupts from the device and/or if the device is used in a shared interrupt situation) or if any interrupts are received before the dispatcher has enough interrupt event control blocks to use label 1. This trans list must determine if additional interrupts are being signalled by the device and, if so, dismiss the interrupt while discarding any associated data and return a status of UDI_INTR_NO_EVENT. If the device is not indicating an interrupt, UDI_INTR_UNCLAIMED must be returned by the trans list. When the transaction list is entered at this label, the exit code must be one of UDI_INTR_NO_EVENT or UDI_INTR_UNCLAIMED. All PIO preprocessing trans lists entered at label 3 should operate as if there is no associated control block or buffer, even if the handler has supplied more interrupt control blocks; interrupt processing will resume normally once the handler has supplied the min_event_pend number of control blocks and the PIO trans list has been entered at label 0.

Any interrupts for the selected interrupt source that are processed by the dispatcher after receiving a udi_intr_attach_req with a non-null preprocessing_handle will be preprocessed. This means that the dispatcher will use udi_pio_trans to execute the specified trans list (associated with preprocessing_handle). This trans list must include all operations necessary to de-assert its interrupt (if it was asserted) in all cases.

When the dispatcher calls udi_pio_trans it will set the buf argument to the buffer passed in the udi_intr_event_cb_t from the udi_intr_event_rdy. This buffer must have been pre-allocated by the handler to contain the data to be returned by the interrupt dispatcher; the buffer will not be extended as part of the interrupt handling operation. The trans list can use this buffer to pass data to the handler driver's upper-level handler.

If the bus type supports event info, the dispatcher driver must set the mem_ptr argument to point to a memory block containing the event info for this interrupt. Otherwise, mem_ptr must be set to NULL.

The preprocessing trans list must only use the first byte of the control block's scratch space to pass back the status of the interrupt preprocessing as specified in the udi_intr_event_cb_t description. No other references can be made to scratch space since the size and contents are unspecified beyond the first byte.

The result from the udi_pio_trans call (set with UDI_PIO_END) is used to determine the disposition of the interrupt, as described in udi_intr_event_cb_t and udi_intr_event_ind.

The bridge driver must free the preprocessing_handle after it has finished with it (as a result of either another udi_intr_attach_req with a new handle or a udi_intr_detach_req), by using udi_pio_unmap.

warnings The mem_ptr value must follow the rules for memory object usage described in Section 5.2.1.1, "Using Memory Pointers with Asynchronous Service Calls," on page 5-2 of the UDI Core Specification.

REFERENCES udi_intr_attach_cb_t, udi_channel_spawn, udi_intr_attach_ack, udi_intr_event_ind, udi_pio_trans, udi_pio_map, udi_pio_unmap

NAME udi_intr_attach_ack

Acknowledge an interrupt attachment

SYNOPSIS

#include <udi.h>

void udi_intr_attach_ack (

	udi_intr_attach_cb_t *intr_attach_cb,

	udi_status_t status );
 

ARGUMENTS intr_attach_cb is a pointer to an interrupt attach control block.

status indicates whether or not the attachment was successful.

TARGET CHANNEL The target channel for this operation is the bound bus bridge channel connecting a bus bridge driver with one of its child device drivers, established during the initial binding between the child device and its bus bridge.

PROXIES udi_intr_attach_ack_unused

Proxy for udi_intr_attach_ack
udi_intr_attach_ack_op_t udi_intr_attach_ack_unused;
 

udi_intr_attach_ack_unused may be used as a device driver's udi_intr_attach_ack entry point if the driver never calls udi_intr_attach_req (and therefore expects to receive no acknowledgements).

DESCRIPTION The udi_intr_attach_ack operation is used by an interrupt dispatcher driver to acknowledge attachment of an interrupt handler (or failure to do so, as indicated by status), as requested by a udi_intr_attach_req operation.

Before sending the acknowledgment, the interrupt dispatcher driver must spawn and anchor its end of the new interrupt event channel, setting the spawn index equal to the interrupt_idx for this attachment.

interrupt_idx in the returned control block must be the same as that passed to udi_intr_attach_req.

Upon failure indication, the handler driver must be sure to close the half-spawned channel, by calling udi_channel_close.

STATUS VALUES UDI_OK- The handler was successfully registered for the indicated interrupts and normal interrupt processing will occur. The preprocessing_handle argument returned in the control block must be UDI_NULL_PIO_HANDLE.

UDI_STAT_MISTAKEN_IDENTITY - This device has no interrupt source corresponding to the interrupt_idx value in the control block. The preprocessing_handle member of the control block is unchanged and the corresponding PIO handle ownership is returned to the interrupt handler.

warnings The control block must be the same control block as passed to the driver in the corresponding udi_intr_attach_req operation.

REFERENCES udi_intr_attach_cb_t, udi_intr_attach_req, udi_intr_detach_req, udi_channel_close

NAME udi_intr_detach_cb_t

Control block for interrupt detachment operations

SYNOPSIS

#include <udi.h>

typedef struct {

	udi_cb_t gcb;

	udi_index_t interrupt_idx;

} udi_intr_detach_cb_t;
 
/* Bridge Detach Control Block Group Number */
 
#define  UDI_BUS_INTR_DETACH_CB_NUM				3
 

MEMBERS gcb is a generic control block header, which includes a pointer to the scratch space associated with this control block. The driver may use the scratch space while it owns the control block, but the values are not guaranteed to persist across channel operations.

interrupt_idx is used to select one of possibly several interrupt sources from the interrupt handler's device that are managed by a particular interrupt dispatcher. Zero indicates the first interrupt source for the device, one indicates the second source, etc. The dispatcher driver will have previously associated the handler's device properties with its channel context during the initial binding sequence.

DESCRIPTION The interrupt detach control block is used between the interrupt handler and the interrupt dispatcher to detach interrupt handler channels (i.e., deregister an interrupt handler for a particular interrupt source).

This control block must be declared by specifying the control block index value UDI_BUS_INTR_DETACH_CB_NUM in a udi_cb_init_t in the driver's udi_init_info.

The bus device driver obtains the udi_intr_detach_cb_t structure to use with the udi_intr_detach_req by calling udi_cb_alloc with a cb_idx that has been associated with UDI_BUS_INTR_DETACH_CB_NUM.

REFERENCES udi_intr_detach_req, udi_intr_detach_ack, udi_init_info, udi_cb_init_t, udi_cb_alloc

NAME udi_intr_detach_req

Request an interrupt detachment

SYNOPSIS

#include <udi.h>

void udi_intr_detach_req (

	udi_intr_detach_cb_t *intr_detach_cb );
 

ARGUMENTS intr_detach_cb is a pointer to an interrupt detach control block.

TARGET CHANNEL The target channel for this operation is the bound bus bridge channel connecting a device driver with its parent bus bridge driver, established during the initial binding between the child device and its bus bridge.

DESCRIPTION When the interrupt handler driver wishes to detach its handler from the interrupt dispatcher, it invokes the udi_intr_detach_req channel operation. A prior attachment must have been completed, as indicated to the interrupt handler driver by receipt of the attach acknowledgment.

interrupt_idx in the control block must be the same as that passed to udi_intr_attach_req (and returned with udi_intr_attach_ack).

REFERENCES udi_intr_detach_cb_t, udi_intr_detach_ack

NAME udi_intr_detach_ack

Acknowledge an interrupt detachment

SYNOPSIS

#include <udi.h>

void udi_intr_detach_ack (

	udi_intr_detach_cb_t *intr_detach_cb );
 

ARGUMENTS intr_detach_cb is a pointer to an interrupt detach control block.

TARGET CHANNEL The target channel for this operation is the bound bus bridge channel connecting a bus bridge driver with one of its child device drivers, established during the initial binding between the child device and its bus bridge.

PROXIES udi_intr_detach_ack_unused

Proxy for udi_intr_detach_ack
udi_intr_detach_ack_op_t udi_intr_detach_ack_unused;
 

udi_intr_detach_ack_unused may be used as a device driver's udi_intr_detach_ack entry point if the driver never calls udi_intr_detach_req (and therefore expects to receive no acknowledgements).

DESCRIPTION After detaching the interrupt handler and closing the local end of the corresponding interrupt event channel, the interrupt dispatcher driver sends the control block back to the interrupt handler using the channel operation, udi_intr_detach_ack.

The dispatcher should discard any udi_intr_event_cb_t control blocks currently held via udi_cb_free before acknowledging the detach operation. Additionally, any interrupt event control blocks received while not attached should be discarded in a similar manner.

The interrupt_idx in the returned control block must be the same as that passed to udi_intr_detach_req.

Upon receipt of the udi_intr_detach_ack, the interrupt handler must close its end of the interrupt event channel (if it did not already do so as a result of a udi_channel_event_ind).

The interrupt handler may free the control block using udi_cb_free or reuse it for another detachment.

warnings The control block must be the same control block as passed to the driver in the corresponding udi_intr_detach_req operation.

REFERENCES udi_intr_detach_cb_t, udi_intr_detach_req, udi_cb_free

5.4 Interrupt Event Operations

These operations are used to deliver and respond to interrupt events between interrupt dispatchers and interrupt handlers.

Interrupt events may be handled in one of two ways: with interrupt preprocessing, or by using interrupt regions. See udi_intr_attach_req for details on interrupt preprocessing. Any region using udi_intr_event_ind or udi_intr_event_rdy without interrupt preprocessing enabled must be an interrupt region; i.e. it must have its type region attribute set to interrupt (see Table 1-1, "Physical I/O Region Attributes"). The primary region of a driver instance cannot be an interrupt region.

All environment services are available to interrupt handlers, but since interrupt regions can require critical resources to be held while executing, drivers should minimize the amount of time spent executing in interrupt regions.

There is, however, a restriction on the order in which service calls and channel operations can be invoked from an interrupt handler, when interrupt preprocessing is not used. For details, see udi_intr_event_ind and udi_intr_event_rdy.

NAME udi_intr_handler_ops_t

Interrupt handler ops vector

SYNOPSIS

#include <udi.h>

typedef const struct {

	udi_channel_event_ind_op_t *channel_event_ind_op;

	udi_intr_event_ind_op_t *intr_event_ind_op;

} udi_intr_handler_ops_t;
 
/* Interrupt Handler Ops Vector Number */
 
#define  UDI_BUS_INTR_HANDLER_OPS_NUM				3
 

DESCRIPTION A driver which wishes to register for handling interrupts (as opposed to "dispatching" interrupts declares the udi_intr_handler_ops_t structure to define its entry point for receiving interrupt events.

REFERENCES udi_init_info, udi_ops_init_t, udi_intr_dispatcher_ops_t

EXAMPLE The driver's initialization structure definitions might include the following:

#define MY_INTR_HANDLER_OPS 2 /* My interrupt handler ops */

#define MY_BUS_META 1 /* Meta index for the Bus Bridge Metalanguage */

static udi_intr_handler_ops_t

	ddd_intr_handler_ops = {

		ddd_intr_handler_channel_event_ind,

		ddd_intr_event_ind

	};

...

static udi_ops_init_t ddd_ops_init_list[] = {

	{	MY_INTR_HANDLER_OPS,

		MY_BUS_META,

		UDI_BUS_INTR_HANDLER_OPS_NUM,

		0, /* chan_context_size */

		(udi_ops_vector_t *)&ddd_intr_handler_ops },

	{ 0 }

};
 

NAME udi_intr_dispatcher_ops_t

Interrupt dispatcher ops vector

SYNOPSIS

#include <udi.h>

typedef const struct {

	udi_channel_event_ind_op_t *channel_event_ind_op;

	udi_intr_event_rdy_op_t *intr_event_rdy_op;

} udi_intr_dispatcher_ops_t;
 
/* Interrupt Dispatcher Ops Vector Number */
 
#define  UDI_BUS_INTR_DISPATCH_OPS_NUM				4
 

DESCRIPTION A bus driver which delivers interrupt indications uses the udi_intr_dispatcher_ops_t to declare the interface operations for receiving interrupt acknowledgements from the interrupt handler.

REFERENCES udi_init_info, udi_ops_init_t, udi_intr_handler_ops_t

EXAMPLE The driver's initialization structure definitions might include the following:

#define MY_INTR_DISP_OPS 2 /* My interrupt dispatcher ops */

#define MY_BUS_META 1 /* Meta index for the Bus Bridge Metalanguage */

static udi_intr_dispatcher_ops_t

	ddd_intr_dispatcher_ops = {

		ddd_intr_channel_event_ind,

		ddd_intr_event_rdy

	};

...

static udi_ops_init_t ddd_ops_init_list[] = {

	{	MY_INTR_DISP_OPS,

		MY_BUS_META,

		UDI_BUS_INTR_DISPATCH_OPS_NUM,

		0, /* chan_context_size */

		(udi_ops_vector_t *)&ddd_intr_dispatcher_ops

	},

	{ 0 }

};
 

NAME udi_intr_event_cb_t

Control block for interrupt event ops

SYNOPSIS

#include <udi.h>

typedef struct {

	udi_cb_t gcb;

	udi_buf_t *event_buf;

	udi_ubit16_t intr_result;

} udi_intr_event_cb_t;
 
/* Flag values for interrupt handling */
 
#define  UDI_INTR_UNCLAIMED				(1U<<0)
 
#define  UDI_INTR_NO_EVENT				(1U<<1)
 
/* Bus Interrupt Event Control Block Group Number */
 
#define UDI_BUS_INTR_EVENT_CB_NUM
4
 

MEMBERS gcb is a generic control block header, which includes a pointer to the scratch space associated with this control block. The driver may use the scratch space while it owns the control block, but the values are not guaranteed to persist across channel operations.

event_buf This buffer (if any) must be preallocated by the handler before being passed to the dispatcher and must contain enough valid bytes to handle the largest PIO trans list requirements; the dispatcher's PIO trans operations cannot extend the size of this buffer.

intr_result is, in the non-preprocessing case, set by the interrupt handler before invoking udi_intr_event_rdy, to indicate whether or not its device asserted the interrupt. In the preprocessing case, intr_result is set by the dispatcher to the result value from the udi_pio_trans call used to preprocess the interrupt, and passed to the handler via the udi_intr_event_ind channel operation.

UDI_INTR_UNCLAIMED is set by the non-preprocessing handler in the intr_result field for the udi_intr_event_rdy operation to indicate that the corresponding device did not generate the interrupt and that the dispatcher should proceed to process any other shared interrupts for this interrupt line. In the preprocessing case, this status is indicated by the preprocessing PIO trans list by setting this bit in the first byte of the control block's scratch space; the dispatcher will not pass the interrupt event indication to the handler and will check other devices as in the non-preprocessing case.

UDI_INTR_NO_EVENT is not used for interrupts occurring in the non-preprocessing case, but may be set in the first byte of the control block's scratch space by the PIO trans list in the preprocessing case to indicate that the PIO trans list handled the interrupt in its entirety and that no interrupt event should be delivered to the handler.

The UDI_INTR_NO_EVENT value may be set for newly allocated interrupt event control blocks allocated by the handler and passed to the dispatcher via the udi_intr_event_rdy operation.

The intr_result value returned in the udi_intr_event_rdy call for the preprocessing case is ignored by the dispatcher.

The dispatcher will zero the first byte of the control block scratch space before initiating the udi_pio_trans on the preprocessing PIO trans list in the preprocessing case; the PIO trans list does not need to modify the byte unless specific bits must be set. The remaining bytes of scratch space are unspecified and must not be used by the preprocessing trans list.

Drivers that cannot tell whether or not their device actually asserted an interrupt, or whose device's interrupts are for some other reason non-sharable, must include a "nonsharable_interrupt" declaration in their static driver properties file (see Section 1.4, "Extensions to Static Driver Properties"), and must not use UDI_INTR_UNCLAIMED.

DESCRIPTION The interrupt event control block is used between the interrupt handler and the interrupt dispatcher to deliver and acknowledge interrupt events.

If the interrupt event was pre-processed (as indicated by the initial value of intr_result passed to udi_intr_event_ind), the event_buf will contain any data filled in during the first-level handler by using the device driver's pre-registered PIO transaction list. (See preprocessing_handle in udi_intr_attach_cb_t.)

Otherwise, event_buf will contain bus-type specific event information, as defined in the bus binding specification for the type of bus to which the device is attached. If the size of the event information is greater than the valid buffer size, only the information that fits in the pre-validated buffer region will be returned. If the event information size is less than the valid buffer size, the remaining bytes will be part of the buffer's valid data range, but the contents are unspecified.

If a driver supports a device which might make use of interrupt event info, it must first determine what type of bus the device is plugged into, by looking at its driver instance attributes. It may then interpret the event info using the corresponding bus binding. See Chapter 6, "Introduction to Bus Bindings", for information on the format of interrupt event info.

REFERENCES udi_intr_attach_cb_t

NAME udi_intr_event_ind

Interrupt event indication

SYNOPSIS

#include <udi.h>

void udi_intr_event_ind (

	udi_intr_event_cb_t *intr_event_cb,

	udi_ubit8_t flags );
 
/* Values for flags */
 
#define  UDI_INTR_MASKING_NOT_REQUIRED				(1U<<0)
 
#define  UDI_INTR_OVERRUN_OCCURRED				(1U<<1)
 
#define  UDI_INTR_PREPROCESSED				(1U<<2)
 

ARGUMENTS intr_event_cb is a pointer to an interrupt event control block.

flags specifies optional flags, described below.

TARGET CHANNEL The target channel for this operation is the interrupt event channel for this attachment, jointly spawned by the interrupt handler and interrupt dispatcher during interrupt attachment (see udi_intr_attach_req, udi_intr_attach_ack). The interrupt handler driver can use the channel context pointer for this channel to distinguish this event from events for other attached interrupts.

DESCRIPTION Upon receipt of an interrupt condition that may have been generated by a particular interrupt source, an interrupt dispatcher will prepare to deliver the interrupt to the appropriate handler. If the handler has requested interrupt preprocessing, it will execute the pre-registered PIO trans list (see udi_intr_attach_req) before delivering the interrupt to the handler driver.

The dispatcher must not allocate interrupt event control blocks to deliver the interrupt to the handler; the handler must have already provided a control block to be used for this purpose. If no control blocks are currently available, the dispatcher should execute the preprocessing trans list (if specified) starting at label 3 (as described by udi_intr_attach_req) and then exit without attempting to notify the handler of the interrupt.

If the preprocessing transaction list handles the interrupt in its entirety such that there is no need for the dispatcher to signal the interrupt event to the handler, the UDI_INTR_NO_EVENT flag should be set in the first byte of the control block's scratch space (see page 4-22) and the dispatcher will simply exit without performing the udi_intr_event_ind operation to the handler.

Since some interrupt handlers change between non-preprocessing and preprocessing modes, the presence of the UDI_INTR_PREPROCESSED bit in flags indicates whether or not this particular interrupt was pre-processed. The dispatcher must set UDI_INTR_PREPROCESSED in flags if this interrupt was preprocessed; otherwise this bit will never be set.

The following applies only to the preprocessing case:

The result value from the udi_pio_trans call used to preprocess the interrupt is used by the dispatcher to set intr_result in the interrupt event control block. If either the UDI_INTR_UNCLAIMED or the UDI_INTR_NO_EVENT flags were set in the first byte of scratch space, no udi_intr_event_ind operation will be sent to the handler driver; otherwise, the dispatcher must set event_buf to the buffer used with the udi_pio_trans call, set intr_result to the result value, and deliver the event to the dispatcher using udi_intr_event_ind with the UDI_INTR_PREPROCESSED flag.

The following applies only to the non-preprocessing case:

The dispatcher driver must fill in the event_buf buffer with the bus type-specific event info for the interrupt, if any, and deliver the event to the appropriate interrupt handler using the channel operation, udi_intr_event_ind.

When the interrupt handler receives and interrupt event indication it must process that indication and either respond back to the dispatcher using udi_intr_event_res (after deasserting the device interrupt condition) or it must act as an intermediary dispatcher for child interrupt handlers. An intermediary dispatcher must execute any child interrupt handler's registered preprocessing PIO trans lists and/or issue udi_intr_event_ind operations to the child's interrupt event channel, passing the subsequent response back to the parent dispatcher.

If the interrupt was not preprocessed, the udi_intr_event_ind operation must execute in an interrupt region, and the driver must process the interrupt as described in the previous paragraph before performing any other channel operations or asynchronous service calls, with the exception of udi_pio_trans, and must not depend on any additional callbacks or channel ops entry points, except the udi_pio_trans callback(s), in order to complete the sequence needed to invoke the required interrupt event operation.

If the interrupt was preprocessed, there are no restrictions on the service calls and channel operations that udi_intr_event_ind may invoke before invoking udi_intr_event_ind or udi_intr_event_rdy, since the interrupt condition was already dismissed in the first-level handler.

The flags values are interpreted as follows:

UDI_INTR_MASKING_NOT_REQUIRED - this flag indicates that an interrupt handler that is also an interrupt dispatcher does not need to mask off the interrupt before passing the event on to the next level (because a higher level interrupt dispatcher interprets interrupts as one-shot events-rather than continuous assertion-and will not pass continuous assertion through).

UDI_INTR_OVERRUN_OCCURRED - this flag indicates that the preprocessing_handle PIO trans list was executed one or more times at start label 3 and did not return UDI_INTR_UNCLAIMED. This is an indication to the handler that one or more interrupts from the device were dismissed and their associated data was discarded prior to the current event being indicated.

UDI_INTR_PREPROCESSED - this flag indicates that the preprocessing PIO trans list was called for the associated interrupt. If clear, no trans list was executed and the handler must operate in the non-preprocessing mode. This will only occur if the device driver previously attached the interrupt without preprocessing and then invoked udi_intr_attach_req again with preprocessing enabled.

REFERENCES udi_intr_event_cb_t, udi_intr_attach_req, udi_intr_event_rdy

NAME udi_intr_event_rdy

Acknowledge an interrupt event

SYNOPSIS

#include <udi.h>

void udi_intr_event_rdy (

	udi_intr_event_cb_t *intr_event_cb );
 

ARGUMENTS intr_event_cb is a pointer to an interrupt event control block.

TARGET CHANNEL The target channel for this operation is the interrupt event channel for this attachment, jointly spawned by the interrupt handler and interrupt dispatcher during interrupt attachment (see udi_intr_attach_req, udi_intr_attach_ack). The interrupt dispatcher driver can use the channel context pointer for this channel to distinguish this response from responses for other attached interrupts.

DESCRIPTION An interrupt handler driver uses udi_intr_event_rdy to send an interrupt event control block to the dispatcher driver. These event control blocks allow the dispatcher to notify the handler of interrupt events, so the handler should endeavor to keep a number of these posted to the dispatcher to avoid missing interrupts. When the dispatcher indicates an interrupt, the handler should process the interrupt quickly and return the control block to the dispatcher to be used for future interrupt indications.

For a leaf interrupt source, this often means accessing some device-specific register which causes the device to stop asserting the interrupt. Leaf drivers must call udi_intr_event_rdy before returning from udi_intr_event_ind. Bridge drivers may complete the interrupt handling by passing the udi_intr_event_rdy on to their parent bridge, or may invoke another interrupt handler with udi_intr_event_ind.

For an interrupt handler which is also a dispatcher, udi_intr_event_rdy should be called immediately if the UDI_INTR_MASKING_NOT_REQUIRED flag is set, or after masking the interrupt if possible. If the interrupt could not be masked, then udi_intr_event_rdy should be called upon receipt of a udi_intr_event_rdy operation from the child handler driver.

In either case, if not using interrupt preprocessing, the handler driver must set intr_result in the control block to zero if its device asserted the interrupt (or the interrupt is non-sharable as indicated by the "nonsharable_interrupt" declaration) or to UDI_INTR_UNCLAIMED if the device was not the source of the interrupt. When using interrupt preprocessing, intr_result is ignored for udi_intr_event_ind.

The udi_intr_event_rdy operation must only be used when the handler is attached for that interrupt source (via udi_intr_attach_req).

The handler determines the number of interrupts indications that may be handled for this device by controlling the number of interrupt event control blocks that are used. The handler may allocate more interrupt control blocks at any time that it is attached to the interrupt dispatcher and provide those control blocks to the dispatcher for processing via the udi_intr_event_rdy operation; the intr_result field of these newly allocated control blocks should be set to UDI_INTR_NO_EVENT. If the handler wishes to reduce the number of interrupts being handled, it should reduce the number of interrupt control blocks available to the dispatcher by using udi_channel_op_abort and subsequently deallocating the aborted control blocks; the handler should not simply deallocate control blocks delivered via the udi_intr_event_ind operation since the interrupt must be acknowledged back to the dispatcher via the udi_intr_event_rdy operation.

warnings The control block must be the same control block as passed to the driver in the corresponding udi_intr_event_ind operation.

REFERENCES udi_intr_event_cb_t, udi_intr_attach_ack, udi_intr_event_ind, udi_channel_op_abort

5.5 Static Properties Bindings

The driver category to be used with the "category" declaration by a portable implementation of the Bus Bridge Metalanguage Library shall be "Bus Bridges".

5.6 Instance Attribute Bindings

One enumeration attribute is defined for all uses of the bus bridge metalanguage: bus_type. This attribute, of type UDI_ATTR_STRING, is set to the name of the I/O bus type to which the child adapter is connected, as defined by the relevant Bus Binding.

Additional enumeration attributes are specified in each Bus Binding to apply to each bus type.

5.7 Bus Bridge Trace Events

The Bus Bridge Metalanguage defines the use of UDI_TREVENT_META_SPECIFIC_1 for bus bridge drivers when they are about to call udi_pio_trans to execute a preprocessing transaction list.

The UDI_TREVENT_IO_SCHEDULED and UDI_TREVENT_IO_COMPLETED events are not defined for use with the Bus Bridge Metalanguage.

5.8 Bus Bridge Metalanguage States

The following events change the state of a device driver with respect to the Bus Bridge Metalanguage:

  1. Binding initiated
  2. Binding complete
  3. Interrupt attachment initiated
  4. Interrupt attachment complete
  5. Interrupt detachment initiated
  6. Interrupt detachment complete
  7. Unbinding initiated
  8. Unbinding complete

The following events change the state of a bus bridge driver with respect to the Bus Bridge Metalanguage:

  1. Binding to a new child
  2. New interrupt attached
  3. Interrupt detached
  4. Child unbound

5.9 Bus Bridge Status Codes

No metalanguage-specific status codes are defined for the Bus Bridge Metalanguage.


TOC PREV NEXT INDEX