fcode.h revision c7c6ab2a4af23be725dea6dacf112b0b9f3fe26f
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_FCODE_H
#define _SYS_FCODE_H
#include <sys/sysmacros.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* The FCode driver presents a private interface to the fcode
* user level interpreter. This interface is subject to change
* at any time and is only provided for use by the fcode interpreter.
*
* The user program opens the device, causing a new instance of
* the driver to be cloned. This instance is specific to a specific
* instance of a new device managed by the kernel and driver framework.
*
* The interpreter does an FC_GET_PARAMETERS ioctl to get the fcode
* length, which can be mmap-ed (at offset 0) to provide access to a copy
* of the device's fcode.
*
* The interpreter uses the FC_RUN_PRIV ioctl to request privileged
* operations to be run by the driver.
*
* The interpreter sends an FC_VALIDATE ioctl to notify the
* driver that it's done interpreting FCode to signify a normal
* ending sequence when the interpreter later closes the device.
* This way the driver can easily distinguish between the user
* level interpreter failing and finishing normally, thus validating
* the interpreters actions and the state it downloads to the driver.
* The 'arg' value in the FC_VALIDATE ioctl is ignored, there
* are no arguments to this ioctl.
*/
/*
* FC_GET_PARAMETERS: Expected as the first ioctl after a successful
* open and blocking read (the read returns 0 when there's something
* to interpret). The ioctl arg is a pointer to an fc_parameters
* data structure which is filled in by the driver with the fcode
* len (if any) and unit address of the new device.
* Offset 0 .. fcode len may be used as the offset to an mmap call to
* provide access to a copy of the device fcode. The unit address is
* returned as a NULL terminated string.
*/
struct fc_parameters {
char unit_address[OBP_MAXPATHLEN];
int config_address;
};
/*
* FC_RUN_PRIV: The ioctl 'arg' is a pointer to an array of fc_cell_t's
* in the following format:
*
* fc_cell_t[0]: Pointer to a NULL terminated string: service name
* fc_cell_t[1]: Number of input arguments (Call this value 'A')
* fc_cell_t[2]: Number of output result cells allocated (Call this val 'R')
* fc_cell_t[3]: Error Cell (See below)
* fc_cell_t[4]: Priv Violation Cell (non-zero if priv. violation)
* fc_cell_t[5]: Argument cell[0] (Possibly none)
* fc_cell_t[5 + 'A']: Result cell[0] (Possibly none)
*
* The array is variable sized, and must contain a minimum of 5 fc_cell_t's.
* The size (in fc_cell_t's) is 5 + 'A' + 'R'.
*
* The argument cells are filled in by the caller. The result cells
* (if any) and error cell are returned to the caller by the driver.
* The error cell and priv violation cell are filled in and returned
* to the caller by the driver.
*
* Error Cell Values:
*
* -1: The call itself failed (the service name was unknown).
*
* 0: No error (though the result cells may indicate results
* that signify an error consistent with the service request.)
*
* Priv Violation Cell Values:
*
* 0: No priv violation
*
* -1: Executing the request caused a priv. violation.
* For example, an rl@ from an address not mapped in
* by the interpreter.
*/
#define FC_ERR_NONE fc_int2cell(0)
#define FC_PRIV_OK fc_intcell(0)
/*
* Client interface template:
* The actual number of arguments is nargs.
* The actual number of results is nresults.
* The variable array 'v' contains 'nargs + nresults' elements
*/
struct fc_client_interface {
};
typedef struct fc_client_interface fc_ci_t;
#define FCC_FIXED_CELLS 5
/*
* FC_GET_FCODE_DATA: This ioctl allows userland portion of the fcode
* interpreter to get the fcode into a local buffer without having
* to use mmap() interface.
* This allows DR kernel cage memory to be relocated while this
* fcode buffer is allocated.
*
* The ioctl arg is a pointer to an fc_fcode_info structure which
* has the fcode_size field set with the expected fcode length.
* The driver uses this field to validate correct size before using
* copyout() to fill in the fcode_ptr buffer with fcode data.
*/
typedef struct fc_fcode_info {
char *fcode_ptr;
/*
* The service name len (max) is limited by the size of a method name
*/
#define FC_SVC_NAME_LEN OBP_MAXPROPNAME
/*
* "Internally" generated service names ...
*/
#define FC_SVC_VALIDATE "sunos,validate"
#define FC_SVC_INVALIDATE "sunos,invalidate"
#define FC_SVC_EXIT "sunos,exit"
#define FC_OPEN_METHOD "open"
#define FC_CLOSE_METHOD "close"
#define FC_FIND_FCODE "$find"
/*
* Property related group:
*
* sunos,get*proplen ( propname-cstr phandle -- proplen )
* sunos,get*prop ( propname-cstr buf phandle -- proplen )
*
* sunos,property ( propname-cstr buf len phandle -- )
*/
#define FC_GET_MY_PROPLEN "sunos,get-my-proplen"
#define FC_GET_MY_PROP "sunos,get-my-prop"
#define FC_GET_IN_PROPLEN "sunos,get-inherited-proplen"
#define FC_GET_IN_PROP "sunos,get-inherited-prop"
#define FC_GET_PKG_PROPLEN "sunos,get-package-proplen"
#define FC_GET_PKG_PROP "sunos,get-package-prop"
#define FC_CREATE_PROPERTY "sunos,property"
/*
* Register access and dma ... same as 1275
*
* dma-map-in maps in a suitable aligned user address.
*/
#define FC_RL_FETCH "rl@"
#define FC_RW_FETCH "rw@"
#define FC_RB_FETCH "rb@"
#define FC_RL_STORE "rl!"
#define FC_RW_STORE "rw!"
#define FC_RB_STORE "rb!"
#define FC_MAP_IN "map-in"
#define FC_MAP_OUT "map-out"
#define FC_DMA_MAP_IN "dma-map-in"
#define FC_DMA_MAP_OUT "dma-map-out"
/*
* PCI configuration space access methods ... same as pci binding
*/
#define FC_PCI_CFG_L_FETCH "config-l@"
#define FC_PCI_CFG_W_FETCH "config-w@"
#define FC_PCI_CFG_B_FETCH "config-b@"
#define FC_PCI_CFG_L_STORE "config-l!"
#define FC_PCI_CFG_W_STORE "config-w!"
#define FC_PCI_CFG_B_STORE "config-b!"
/*
* Device node creation ...
*
* Create a new device with the given name, unit-address, parent.phandle
* with a phandle that must have been previously allocated using
* sunos,alloc-phandle. finish-device marks the device creation and
* the creation of its properties as complete. (It's a signal to the
* the OS that the node is now reasonably complete.)
*
* sunos,new-device ( name-cstr unit-addr-cstr parent.phandle phandle -- )
* finish-device ( phandle -- )
*/
#define FC_NEW_DEVICE "sunos,new-device"
#define FC_FINISH_DEVICE "sunos,finish-device"
/*
* Navigation and configuration:
*
* sunos,probe-address ( -- phys.lo ... )
* sunos,probe-space ( -- phys.hi )
*
* sunos,ap-phandle ( -- ap.phandle )
* Return attachment point phandle
*
* sunos,parent ( child.phandle -- parent.phandle )
*
* child ( parent.phandle -- child.phandle )
* peer ( phandle -- phandle.sibling )
*
* sunos,alloc-phandle ( -- phandle )
* Allocates a unique phandle, not associated with the device tree
*
* sunos,config-child ( -- child.phandle )
* Return the phandle of the child being configured.
*/
#define FC_PROBE_ADDRESS "sunos,probe-address"
#define FC_PROBE_SPACE "sunos,probe-space"
#define FC_AP_PHANDLE "sunos,ap-phandle"
#define FC_PARENT "sunos,parent"
#define FC_CHILD_FCODE "child"
#define FC_PEER_FCODE "peer"
#define FC_ALLOC_PHANDLE "sunos,alloc-phandle"
#define FC_CONFIG_CHILD "sunos,config-child"
/*
* Fcode Drop In Routines:
* sunos,get_fcode_size ( cstr -- len )
* Returns the size in bytes of the Fcode for a given drop in.
* sunos,get_fcode (cstr buf len -- status? )
* Returns the Fcode image for a given drop in.
*/
#define FC_GET_FCODE_SIZE "sunos,get-fcode-size"
#define FC_GET_FCODE "sunos,get-fcode"
/*
* Values for fc_request 'error'. This has been moved from the _KERNEL
* area to allow the FC_SET_FCODE_ERROR ioctl to use these values to
* signal the kernel as to the disposition of the userland interpreter.
* NOTE: Positive values are used to indicate a kernel error,
* negative values are used to identify userland interpreter errors.
*/
#define FC_SUCCESS 0 /* FCode interpreted successfully */
/*
* kernel internal data structures and interfaces
* for the fcode interpreter.
*/
#if defined(_KERNEL)
/*
* PCI bus-specific arguments.
*
* We can't get the physical config address of the child from the
* unit address, so we supply it here, along with the child's dip
* as the bus specific argument to pci_ops_alloc_handle.
*/
struct pci_ops_bus_args {
};
/*
* Define data structures for resource lists and handle management
*
* 'untyped' resources are managed by the provider.
*/
struct fc_dma_resource {
void *virt;
};
struct fc_map_resource {
void *virt;
void *regspec;
};
struct fc_nodeid_resource {
int nodeid; /* An allocated nodeid */
};
struct fc_contigious_resource {
void *virt;
};
struct fc_untyped_resource {
int utype; /* providers private type field */
void (*free)(void *); /* function to free the resource */
void *resource; /* Pointer to the resource */
};
typedef enum {
RT_DMA = 0,
struct fc_resource {
struct fc_resource *next;
union {
struct fc_dma_resource d;
struct fc_map_resource m;
struct fc_nodeid_resource n;
struct fc_contigious_resource c;
struct fc_untyped_resource r;
} un;
};
#define fc_dma_handle un.d.h
#define fc_map_handle un.m.h
struct fc_phandle_entry {
struct fc_phandle_entry *next;
fc_phandle_t h;
};
extern void fc_phandle_table_alloc(struct fc_phandle_entry **);
extern void fc_phandle_table_free(struct fc_phandle_entry **);
/*
* Structures and functions for managing our own subtree rooted
* at the attachment point. The parent linkage is established
* at node creation time. The 'downwards' linkage isn't established
* until the node is bound.
*/
struct fc_device_tree {
struct fc_device_tree *child;
struct fc_device_tree *peer;
};
struct fc_device_tree *head);
/*
* Our handles represent a list of resources associated with an
* attachment point. The handles chain, just as the ops functions
* do, with the ops caller responsible for remembering the handle
* of the ops function below it. NB: Externally, this data structure
* is opaque. (Not all members may be present in each chained cookie.)
* For example, the dtree head is valid in only a single instance
* of a set of chained cookies, so use the access function to find it.)
*/
struct fc_resource_list {
struct fc_resource *head;
void *next_handle; /* next handle in chain */
int cdip_state; /* node creation state - see below */
void *fcode; /* fcode kernel address */
char *unit_address; /* childs unit address */
char *my_args; /* initial setting for my-args */
void *bus_args; /* bus dependent arguments */
};
typedef struct fc_resource_list *fco_handle_t;
/*
* Values for cdip_state:
*/
/*
* Functions to allocate handles for the fcode_interpreter.
*
* This function allocates a handle, used to store resources
* associated with this fcode request including the address of
* the mapped in and copied in fcode and it's size or NULL, 0
* if there is no fcode (the interpreter may look for a drop-in
* driver if there is no fcode), the unit address of child and
* bus specific arguments. For PCI, the bus specific arguments
* include the child's prototype dip and the config address of
* the child, which can't be derived from the unit address.
*
* The 'handle' returned also contains resource information
* about any allocations of kernel resources that the fcode
* may have created. Thus, the handle's life is the life
* of the plug-in card and can't be released until the card
* is removed. Upon release, the resources are released.
*/
extern fco_handle_t
extern fco_handle_t
struct pci_ops_bus_args *bus_args);
extern fco_handle_t
char *my_args);
/*
* fc_ops_t is the main glue back to the framework and attachment point driver
* to the fc_ops function to handle the request given in the args. The dip
* requests, if necessary. The argument array is an array of fc_cell_t's
* and is defined in fcode.h
*
* The ops function should return -1 to indicate that the service name is
* unknown and return the value 0 to indicate that the service name was known
* and processed (even if it failed). ops functions may chain, using the
* return code to communicate if the current function handled the service
* request. Using this technique, the driver can provide certain ops functions
* and allow a framework ops function to handle standardized ops functions,
* or work hand in hand with a framework function so both can handle an op.
* If an ops function is not handled, thus returning -1 to the driver, the
* driver will log an error noting the name of the service and return the
* error to the caller.
*/
extern fc_ops_t pci_fc_ops;
extern fc_ops_t gp2_fc_ops;
/*
* Internal structure used to enque an fcode request
* The 'next' and 'busy' fields are protected by a mutex.
* Thread synchronization is accomplished via use of the 'busy' field.
*/
struct fc_request {
int busy; /* Waiters flag (private; see below) */
int error; /* Interpreter return code (private) */
};
/*
* Values for 'busy'. The requester initializes the field to FC_R_INIT (0),
* then waits for it be set to FC_R_DONE. The framework sets it to
* FC_R_BUSY while working on the request so it can distinguish between
* an inactive and an active request.
*/
#define FC_R_INIT 0 /* initialized, on queue */
/*
* Function to call to invoke the fcode interpreter.
*
* This function will wait and return when the interpreter either
* the return code. Interim calls to the driver's ops function will
* be made for both priv. ops and to create device nodes and properties.
*
* Calling this function will log a message to userland to request the
* eventd to start the userland fcode interpreter process. The interpreter
* waits in a 'read' until there's an active request.
* XXX: For the prototype, we can start it manually or use an init.d script.
*
* 'ap' is the attachment point dip: that is, the driving parent's dev_info_t
* ie: for pci devices, this will be the dip of the pci nexus.
*
* The 'handle' is provided for the caller, and can be used to
* identify the request along with the attachment point dip, both
* of which will be passed back to the driver's ops function.
* The handle is allocated first by calling a bus-specific
* <bus>_ops_handle_alloc function.
*
* ops functions may chain; an ops function should return -1 if
* the call was not recognized, or 0 if the call was recognized.
*/
/*
* The fcode implementation uses this function to wait for and 'de-queue'
* an fcode request. It's triggered by a 'read' request from the
* userland interpreter. It uses a 'sig' form of waiting (cv_wait_sig),
* so the interpreter can interrupt the read.
*/
extern struct fc_request *fc_get_request(void);
/*
* When the fcode implementation is finished servicing a request, it calls this
* function to mark the request as done and to signal the originating thread
* (now waiting in fcode_interpreter) that the request is done.
*/
extern void fc_finish_request(struct fc_request *);
/*
* The fcode implementation uses these functions to manage
* resource items and resource lists ...
*/
extern void fc_lock_resource_list(fco_handle_t);
extern void fc_unlock_resource_list(fco_handle_t);
/*
* ops common and helper functions
*/
extern int fc_syntax_error(fc_ci_t *, char *);
extern int fc_priv_error(fc_ci_t *, char *);
/*
* Recharacterized ddi functions we need to define ...
*
* The only difference is we call through the attachment point driver,
* as a proxy for the child that isn't yet attached. The ddi functions
* optimize these functions by not necessarily calling through the
* attachment point driver.
*/
/*
* The ndi prop functions aren't appropriate for the interpreter.
* We create byte-array, untyped properties.
*/
/*
* The setup and teardown parts of physio()
*/
/*
* debugging macros
*/
extern int fcode_debug;
#ifdef DEBUG
fc_debug(s, 0, 0, 0, 0, 0)
if (fcode_debug >= level) \
#else
#endif
#endif /* defined(_KERNEL) */
#ifdef __cplusplus
}
#endif
#endif /* _SYS_FCODE_H */