root/usr/src/uts/common/io/bnxe/577xx/drivers/common/lm/device/lm_dmae.h
/*******************************************************************************
 *
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2014 QLogic Corporation
 * The contents of this file are subject to the terms of the
 * QLogic End User License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the License at
 * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
 * QLogic_End_User_Software_License.txt
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * Module Description:
 *
 *
 * History:
 *    02/05/07 Alon Elhanani    Inception.
 ******************************************************************************/

/**@file hw_dmae.h
 *
 * A module encapsulating the DMAE HW block. 
 * 
 * Use cases for this module include:
 * 
 * - 'Single-block' DMA operations
 *   Single-block DMA operations are composed of a single HW
 *   command that contains a GRC/PCI source, a GRC/PCI
 *   destination and length. Single-block DMA operations are
 *   locked from before writing the command to the HW registers,
 *   until after the DMAE writes the completion word to the
 *   appropriate location in host memory. Single-block DMA
 *   operations use a single DMAE channel.
 * 
 * - SGL DMA operations
 *   SGL DMA operations use two DMAE channels - one called a
 *   'loader' and one called an 'executer'. The operation is
 *   composed of a single HW command called a 'loader' that
 *   uses the loader channel, and multiple HW commands called
 *   'executers' that use the executer channel. The loader
 *   command is configured so that whenever it is executed,
 *   it loads and executes the next pending executer command.
 *   Executer commands are configured so that whenever they
 *   complete they execute the loader command, except the last
 *   executer command that simply writes the completion word
 *   to the appropriate location in host memory.
 *   SGL DMA operations lock both channels from the time the
 *   loader first executes, until the last executer completes.
 * 
 * - SGL DMA operations in asynchronous mode (a.k.a post/poll)
 *   SGL DMA operations in asynchronous mode only lock the
 *   context for the time required to load the loader command
 *   to the HW registers (called the 'post' stage). Afterwords
 *   they return immediately and unlock both channels. Then a
 *   DMAE user may query the context's state to check if the
 *   last executer command has already finished (the 'poll' stage).
 *   The context is locked only for the duration of a single
 *   query at a time. Note that a DMAE user may not use the
 *   context until the query returns with a code that indicates
 *   the context is available.
 */

#ifndef _LM_DMAE_H
#define _LM_DMAE_H

#include "mm.h"

// defines
#define DMAE_SGL_MAX_COMMANDS       5         // max number of commands in a DMAE SGL (just as a limit - can be defined other number)
#define DMAE_GO_VALUE               0x1         // DMAE spec
#define DMAE_SGL_COMPLETION_VAL     0xD0AE      // local completion word value (for SGL)
#define DMAE_COMPLETION_VAL         0xD1AE      // local completion word value with edianity mode 2 (for regular command)
#define DMAE_COMPLETION_VAL_SWAPPED 0xAED10000  // local completion word value with edianity mode 3

#define DMAE_CMD_SIZE               14          // size of DMAE command structure

#define DMAE_MAX_RW_SIZE_E1        0x0400 // maximun size (in DW) of read/write commands (HW limit) - for  (chip id<=5710)

// up to 0xffff actually limit is 64KB-1 so 0x2000 dwords is 32KB
#define DMAE_MAX_RW_SIZE_NEW       0x2000 // maximun size of read/write commands (HW limit) - for E1.5 and above (chip id>5710)
#define DMAE_MAX_READ_SIZE         0x80   // due to a HW issue in E1, E1.5 A0, pci to pci and grc to pci operations are limited to 128 DWORDS

// max value for static allocations
#define DMAE_MAX_RW_SIZE_STATIC    max(DMAE_MAX_RW_SIZE_E1,DMAE_MAX_RW_SIZE_NEW)

#define DMAE_MAX_RW_SIZE(pdev)    (CHIP_IS_E1(pdev) ?  DMAE_MAX_RW_SIZE_E1 : DMAE_MAX_RW_SIZE_NEW)


#define DMAE_STATS_GET_PORT_CMD_IDX(port_num,cmd_idx) DMAE_STATS_PORT_##port_num##_CMD_IDX_##cmd_idx

#define DMAE_STATS_PORT_0_CMD_IDX_0       DMAE_CMD_DRV_0
#define DMAE_STATS_PORT_0_CMD_IDX_1       DMAE_CMD_DRV_1
#define DMAE_STATS_PORT_1_CMD_IDX_0       DMAE_CMD_DRV_2
#define DMAE_STATS_PORT_1_CMD_IDX_1       DMAE_CMD_DRV_3
#define DMAE_WB_ACCESS_FUNCTION_CMD(_idx) DMAE_CMD_DRV_4+(_idx)
#define DMAE_COPY_PCI_PCI_PORT_0_CMD      DMAE_CMD_DRV_12
#define DMAE_COPY_PCI_PCI_PORT_1_CMD      DMAE_CMD_DRV_13

#define LM_DMAE_INTERMEDIATE_BUFFER_SIZE DMAE_MAX_RW_SIZE_NEW

#define LM_DMAE_NO_HWLOCK 0

typedef enum _lm_dmae_protected_resource_t
{
    LM_PROTECTED_RESOURCE_DMAE_STATS = 0,
    LM_PROTECTED_RESOURCE_DMAE_TOE,
    LM_PROTECTED_RESOURCE_DMAE_DEFAULT,
    LM_MAX_PROTECTED_RESOURCE
}lm_dmae_protected_resource_t;

typedef enum _lm_dmae_type_t
{
    LM_DMAE_STATS,
    LM_DMAE_TOE,
    LM_DMAE_DEFAULT,
    LM_DMAE_MAX_TYPE
}lm_dmae_type_t;

typedef enum _lm_dmae_address_type_t
{
    LM_DMAE_ADDRESS_HOST_VIRT,
    LM_DMAE_ADDRESS_HOST_PHYS,
    LM_DMAE_ADDRESS_GRC
}lm_dmae_address_type_t;

typedef enum _lm_dmae_mode_t
{
    LM_DMAE_MODE_SGL,
    LM_DMAE_MODE_SINGLE_BLOCK
}lm_dmae_mode_t;

typedef enum _lm_dmae_locking_policy_type_t
{
    LM_DMAE_LOCKING_POLICY_TYPE_NONE,
    LM_DMAE_LOCKING_POLICY_TYPE_PER_PF,
    LM_DMAE_LOCKING_POLICY_TYPE_INTER_PF
}lm_dmae_locking_policy_type_t;

/**
 * An encapsulation of the synchronization method for resource. 
 * The type of locking policy depends on the synchronization 
 * requirements for the protected resource (in this design's 
 * case - the DMAE context) 
 *  
 *  - No synchronization  
 *  Use this type of policy when there is no contention on the
 *  protected resource. No locking will take place.
 *  - per-PF synchronization
 *  synchronizes access to the protected resource among users in
 *  the same PF, but not between multiple PFs. Use this type of
 *  policy when the protected resource is per-PF.
 *  - inter-PF synchronization
 *  synchronizes access to the protected resource among multiple
 *  users that may be running in the contexts of multiple PFs.
 *  Use this type of policy when the protected resource is
 *  shared among multiple PFs.
 *  
 *  @ingroup LockingPolicy
 */
typedef struct _lm_dmae_locking_policy_t
{
    mm_spin_lock_t spinlock; /**< an opaque context for the spinlock that's used by this locking policy*/
    u32_t hwlock; /**< the HW lock used by this locking policy*/
}lm_dmae_locking_policy_t;

/**
 * A source/target address for a DMA operation. 
 *  
 * @ingroup DMAE_Address 
 */
typedef struct _lm_dmae_address_t
{
    /**The offset of this address (either a virtual address, a 
    physical address or a GRC offset) */
    union { 
        u32_t grc_offset;
        void* host_virt_address;
        lm_address_t host_phys_address;
    } u;

    /**The type of this address*/
    lm_dmae_address_type_t type;
}lm_dmae_address_t;


/**
 * @ingroup DMAE_Operation
 */
typedef struct _lm_dmae_block_t
{
    lm_dmae_address_t source;
    lm_dmae_address_t dest;
    u16_t length;
}lm_dmae_block_t;

/**
 * An aggregation of one or more DMAE channels that are used by 
 * the driver for the same function with the same configuration. 
 * A context may be a non-SGL context (in which case it is 
 * associated with a single DMAE channel) or an SGL context (in 
 * which case it is associated with two DMAE channels). Every 
 * context may have one current operation. 
 *  
 * @ingroup DMAE_Context 
 */
typedef struct _lm_dmae_context_t
{
    /**The type of the context (SGL or single-block)   */
    lm_dmae_mode_t mode;

    /** - single-block context: the index of the DMAE channel for
     *  this context
     *  - SGL context: the index of the loader DMAE channel for this
     *    context*/
    u8_t main_channel;

    /**SGL context: the index of the executer DMAE channel for this 
     * context. 
     * This field has no meaning for single-block contexts */ 
    u8_t executer_channel;

    u8_t change_endianity;

    u32_t next_command_id;

    lm_dmae_locking_policy_t* locking_policy;

    /**This physical address of the field completion_word   */
    lm_address_t completion_word_paddr;

    /**The memory location where the DMAE writes the completion 
     * value when an operation is finished on this context.*/ 
    volatile u32_t completion_word;

    /**The value that the DMAE writes to completion_word when an 
     * operation is finished on this context. Endianess note: The 
     * completion value that's written as part of the command is 
     * always the same, but the value that's later written to 
     * memory depends on the endianness mode of the command, so 
     * this value represents the value that's written by the DMAE 
     * and not the value that's used by the VBD. */ 
    u32_t completion_value;

    /**This physical address of the beginnning of 
     * intermediate_buffer*/ 
    lm_address_t intermediate_buffer_paddr;

    /**An intermediate buffer for DMAE operations that use virtual 
     * addresses - data is DMA'd to/from this buffer and then 
     * memcpy'd to/from the virtual address*/ 
    u32_t intermediate_buffer[LM_DMAE_INTERMEDIATE_BUFFER_SIZE];
}lm_dmae_context_t;


/**
 * A single logical DMAE transfer, which may be either a 
 * single-block transfer (in which case it has a single source 
 * and a single target) or an SGL transfer (in which case it is 
 * composed of multiple SGEs, each having a single source and a 
 * single target). An SGL operation may be synchronous or 
 * asynchronous - executing a synchronous DMAE operation results
 * in a wait until the operation completes, while an 
 * asynchronous operation may be posted to the hardware without 
 * waiting for its completion. 
 *  
 * @ingroup DMAE_Operation 
 */
typedef struct _lm_dmae_operation_t
{
    /**The type of this operation (SGL or single-block)*/ 
    lm_dmae_mode_t mode;

    /**The context of this operation.*/ 
    lm_dmae_context_t* context;

/**TRUE if the source is a block of length DMAE_MAX_RW_SIZE_E1 /
 * DMAE_MAX_RW_SIZE_NEW and the destination is larger. In this 
 * case the source block will be duplicated as many times as 
 * required to fill the destination block.*/ 
    u8_t b_replicate_source; 

    u8_t le32_swap;

    /**SGL: TRUE if this operation is synchronous. This field has 
     * no meaning for single-block operations. */ 
    u8_t b_sync;
    
    u32_t command_id;
        
    /**SGL: The loader command for this operation
     *SINGLE_BLOCK: The command for this operation*/
    struct dmae_cmd main_cmd;

    /**The next available entry in blocks[] and executer_cmdp[] */
    u8_t next_free_block;

    /**The block/blocks of this operation*/ 
    lm_dmae_block_t blocks[DMAE_SGL_MAX_COMMANDS];

    /**SGL: The physical address of the beginning of executer_cmd. 
     * This field has no meaning for single-block operations.   */
    lm_address_t executer_paddr;

    /**SGL: The executer HSI commands for this operation. This 
     * field has no meaning for single-block operations. */ 
    struct dmae_cmd executer_cmd[DMAE_SGL_MAX_COMMANDS]; //these must be consecutive, so they can't be a part of the blocks[] array. 
}lm_dmae_operation_t;

typedef struct _lm_dmae_context_info_t 
{
    lm_dmae_context_t* context;
    lm_dmae_locking_policy_t locking_policy;
}lm_dmae_context_info_t ;

typedef struct _lm_dmae_info_t
{
    lm_dmae_context_info_t ctx_arr[LM_DMAE_MAX_TYPE];
}lm_dmae_info_t;

//------------------ Locking Policy ------------------//

/**lm_dmae_locking_policy_create
 * Create a locking policy
 *  
 * @param resource The ID of the protected resource. This ID is 
 *                 used to determine which synchronization
 *                 objects will be used by the policy.
 * @param type the type of this locking policy 
 * @param policy the policy to initialize. 
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other 
 *         failure value on failure.
 */
lm_status_t lm_dmae_locking_policy_create(  struct _lm_device_t* pdev,
                                            IN const u32_t resource, 
                                            IN const lm_dmae_locking_policy_type_t type, 
                                            OUT lm_dmae_locking_policy_t* policy);

/**lm_dmae_locking_policy_lock
 * Use a locking policy to lock a resource, acquiring whatever 
 * spinlock or hardware lock required. 
 * 
 * @param locking_policy the policy to use
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other 
 *         failure code on failure.
 */
#ifdef _VBD_
__drv_maxIRQL(DISPATCH_LEVEL)
__drv_at(locking_policy->spinlock.irql, __drv_savesIRQL)
__drv_setsIRQL(DISPATCH_LEVEL)
#endif
lm_status_t lm_dmae_locking_policy_lock(struct _lm_device_t* pdev, lm_dmae_locking_policy_t* locking_policy);

/**lm_dmae_locking_policy_unlock
 * Use a locking policy to unlock a resource, releasing 
 * whatever spinlock or hardware lock required. 
 *  
 * @param locking_policy the policy to use
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other 
 *         failure code on failure
 */
#ifdef _VBD_
#if defined(NTDDI_WIN8)
_IRQL_requires_(DISPATCH_LEVEL)
__drv_at(locking_policy->spinlock.irql, __drv_restoresIRQL )
#endif
#endif
lm_status_t lm_dmae_locking_policy_unlock(struct _lm_device_t* pdev, lm_dmae_locking_policy_t* locking_policy);



//------------------ DMAE Context ------------------//

/**lm_dmae_context_create
 * Create a non-SGL DMA context, using the given policy for 
 * synchronization. 
 *  
 * @param channel_idx the DMAE channel index that is used by 
 *                    this context
 * @param locking_policy the synchronization policy used by this 
 *                       context
 * @param change_endianity 
 * 
 * @return lm_dmae_context_t* a single-block DMAE context 
 *                configured according to the supplied
 *                parameters.
 */
lm_dmae_context_t* lm_dmae_context_create(  struct _lm_device_t* pdev,
                                            IN const u8_t channel_idx, 
                                            lm_dmae_locking_policy_t* locking_policy, 
                                            IN const u8_t change_endianity);

/**lm_dmae_context_create_sgl
 * Create an SGL DMA context, using the given policy for 
 * synchronization. 
 *  
 * @param loader_channel_idx the 'loader' DMAE channel index 
 *                           that is used by this context
 * @param executer_channel_idx the 'executer' DMAE channel index 
 *                             that is used by this context
 * @param locking_policy the synchronization policy used by this 
 *                       context
 * @param change_endianity 
 * 
 * @return lm_status_t an SGL DMAE context configured according 
 *                to the supplied parameters.
 */
lm_dmae_context_t* lm_dmae_context_create_sgl( struct _lm_device_t* pdev,
                                               IN const u8_t loader_channel_idx,
                                               IN const u8_t executer_channel_idx,
                                               lm_dmae_locking_policy_t* locking_policy,
                                               IN const u8_t change_endianity);

/**lm_dmae_context_reset
 * Bring a DMAE context to a known-good state. This function 
 * must be used on an acquired context. It should be used if for 
 * some reason the context is left in an invalid state (e.g an 
 * error occured during a DMAE transaction using this context). 
 * 
 * @param context the context to reset.
 * 
 * @return lm_status LM_STATUS_SUCCESS on success, some other 
 *         failure code on failure.
 */
lm_status_t lm_dmae_context_reset(lm_dmae_context_t *context);

/**lm_dmae_context_acquire
 * Acquire the context, so that multiple DMAE operations may be 
 * executed on it without locking the context once for every 
 * operation. Only after calling this function can 
 * lm_dmae_context_execute_unsafe be used. 
 *  
 * @param context the context to acquire
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other 
 *         failure value on failure
 */
#ifdef _VBD_
__drv_maxIRQL(DISPATCH_LEVEL)
__drv_at(context->locking_policy->spinlock.irql, __drv_savesIRQL)
__drv_setsIRQL(DISPATCH_LEVEL)
#endif
lm_status_t lm_dmae_context_acquire(struct _lm_device_t* pdev, lm_dmae_context_t *context);

/**lm_dmae_context_release
 * Release a context that was acquired with 
 * lm_dmae_context_release. After calling this function, 
 * lm_dmae_context_execute_unsafe may not be used on the 
 * context. 
 *  
 * @param context the context to release
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other 
 *         failure value on failure
 */
#ifdef _VBD_
#if defined(NTDDI_WIN8)
_IRQL_requires_(DISPATCH_LEVEL)
__drv_at(context->locking_policy->spinlock.irql, __drv_restoresIRQL )
#endif
#endif
lm_status_t lm_dmae_context_release(struct _lm_device_t* pdev, lm_dmae_context_t *context);


/**lm_dmae_context_execute
 * Execute a command in a context, using the context's locking 
 * policy 
 * 
 * @param context the context to use
 * @param operation the operation to execute
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, 
 *         LM_STATUS_PENDING if executing an asynchronous
 *         operation, LM_STATUS_BUSY if another asyncronous
 *         operation is in progress or some other failure code
 *         on failure.
 */
lm_status_t lm_dmae_context_execute(struct _lm_device_t* pdev, lm_dmae_context_t *context, lm_dmae_operation_t *operation);

/**lm_dmae_context_execute_unsafe
 * Execute a command in a context, without locking. This 
 * function must be called between calls to 
 * lm_dmae_context_acquire and lm_dmae_context_release. 
 * 
 * @param context the context to use
 * @param operation the operation to execute
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, 
 *         LM_STATUS_PENDING if executing an asynchronous
 *         operation, LM_STATUS_BUSY if another asyncronous
 *         operation is in progress or some other failure code
 *         on failure.
 */
lm_status_t lm_dmae_context_execute_unsafe(struct _lm_device_t* pdev, lm_dmae_context_t *context, lm_dmae_operation_t *operation);




//------------------ DMAE Operation ------------------//

/**lm_dmae_operation_create
 * Create a single-block DMAE operation and the DMAE command 
 * that it uses. 
 *  
 * @param source the source for this DMAE operation
 * @param dest the destination for this DMAE operation
 * @param length the length of the block to transfer
 * @param replicate_source TRUE if the source is a block of 
 *                           length DMAE_MAX_RW_SIZE_E1/DMAE_MAX_RW_SIZE_NEW
 *                           and the destination is larger. In
 *                           this case the source block will be
 *                           duplicated as many times as
 *                           required to fill the destination
 *                           block.
 * @param le32_swap should byte-swapping occur before executing 
 *                  the operation.
 * @param context the DMAE context for this operation 
 * @param operation the operation to initialize. If this function 
 *                  returns LM_STATUS_SUCCESS, the operation
 *                  pointed to by this parameter is initialized
 *                  to a single-block DMAE operation configured
 *                  according to the supplied parameters.
 *  
 * @return lm_status_t LM_STATUS_SUCCESS on success, some other 
 *         failure value on failure.
 */
lm_status_t lm_dmae_operation_create(   struct _lm_device_t* pdev,
                                        IN const lm_dmae_address_t source,
                                        IN const lm_dmae_address_t dest,
                                        IN const u16_t length,
                                        IN const u8_t replicate_source,
                                        IN const u8_t le32_swap,
                                        IN lm_dmae_context_t* context,
                                        OUT lm_dmae_operation_t* operation);

/**lm_dmae_operation_create_sgl
 * Create an SGL DMAE operation and the DMAE commands that it 
 * uses. 
 * 
 * @param b_sync TRUE if this operation is synchronous, FALSE 
 *               otherwise.
 * @param context the DMAE context for this operation
 * 
 * @return lm_dmae_operation_t* An empty SGL DMAE operation 
 *         based on the supplied parameters. Use
 *         lm_dmae_operation_add_sge to add SGEs to this
 *         operation. On failure the function returns NULL.
 */
lm_dmae_operation_t* lm_dmae_operation_create_sgl(  struct _lm_device_t* pdev,
                                                    IN const u8_t b_sync,
                                                    IN lm_dmae_context_t* context);

/**lm_dmae_operation_add_sge
 * Add an SGE to an SGL operation.
 * 
 * @param operation the operation to add an SGE to. 
 * @param source the source for this SGE
 * @param dest the destination for this SGE
 * @param length the length of the block to transfer
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, 
 *         LM_STATUS_INVALID_PARAMETER if the supplied operation
 *         is not an SGL operation, some other failure code on
 *         failure.
 */
lm_status_t lm_dmae_operation_add_sge(  struct _lm_device_t* pdev,
                                        lm_dmae_operation_t* operation,
                                        IN const lm_dmae_address_t source,
                                        IN const lm_dmae_address_t dest,
                                        IN const u16_t length);

/**lm_dmae_operation_clear_all_sges
 * Remove all SGEs from an SGL DMAE command. 
 *  
 * @param operation the operation to clear
 * 
 */
void lm_dmae_operation_clear_all_sges(lm_dmae_operation_t* operation);

/**lm_dmae_operation_is_complete
 * check if an operation has finished
 *  
 * @param operation the operation to check
 * 
 * @return u8_t TRUE if the given operation is complete
 */
u8_t lm_dmae_operation_is_complete(IN lm_dmae_operation_t* operation);




//------------------ DMAE Address ------------------//

/**lm_dmae_address_native_offset
 * Get a u64_t representation of the address's value which can 
 * be used as a source/destination address by DMAE hardware (i.e 
 * byte offset for host memory address,  DWORD offset for GRC 
 * offsets) 
 *  
 * @param address the address to use
 * 
 * @return u64_t see description
 */
u64_t lm_dmae_address_native_offset(IN const lm_dmae_address_t* address);

/**lm_dmae_address
 * create a DMAE address 
 * 
 * @param offset the offset of the address (either 
 *               physical/virtual address or GRC offset)
 * @param type the type of the address
 * 
 * @return lm_dmae_address_t a DMAE address initialized 
 *         according to the supplied parameters
 */
lm_dmae_address_t lm_dmae_address(IN const u64_t offset, IN const lm_dmae_address_type_t type);

//------------------ DMAE users ------------------//

/**lm_dmae_get
 * Return the context info for a given DMAE user. 
 * 
 * @param pdev the device to use
 * @param type the dmae user
 * 
 * @return lm_dmae_context_info_t* the context info for the given user, or NULL on error.
 */
lm_dmae_context_info_t* lm_dmae_get(struct _lm_device_t* pdev, IN const lm_dmae_type_t type);

/**lm_dmae_reg_wr
 * Write a block of data from host memory (given as a virtual 
 * address) to GRC. 
 * 
 * @param pdev the device to use
 * @param context the DMAE context to use
 * @param source_vaddr the beginning of the source memory block
 * @param dest_offset the GRC offset of the destination block
 * @param length the length (in DWORDS) of the block
 * @param b_replicate_source TRUE if the source is a block of 
 *                           length
 *                           DMAE_MAX_RW_SIZE_E1/DMAE_MAX_RW_SIZE_NEW
 *                           and the destination is larger. In
 *                           this case the source block will be
 *                           duplicated as many times as
 *                           required to fill the destination
 *                           block.
 * @param le32_swap if TRUE, change all DWORDS in the source 
 *                  block to little-endian representation before
 *                  executing the operation.
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, 
 *         LM_STATUS_TIMEOUT if the operation did not finish in
 *         reasonable time, some other failure value on failure.
 */
lm_status_t lm_dmae_reg_wr(struct _lm_device_t* pdev, lm_dmae_context_t* context, void* source_vaddr, u32_t dest_offset, u16_t length, u8_t b_replicate_source, u8_t le32_swap);

/**lm_dmae_reg_wr_phys 
 * Write a block of data from host memory (given as a physical 
 * address) to GRC. 
 * 
 * @param pdev the device to use
 * @param context the DMAE context to use
 * @param source_paddr the beginning of the source memory block
 * @param dest_offset the GRC offset of the destination block
 * @param length the length (in DWORDS) of the block
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, 
 *         LM_STATUS_TIMEOUT if the operation did not finish in
 *         reasonable time, some other failure value on failure.
 */
lm_status_t lm_dmae_reg_wr_phys(struct _lm_device_t* pdev, lm_dmae_context_t* context, lm_address_t source_paddr, u32_t dest_offset, u16_t length);

/**lm_dmae_reg_rd
 * Read a block from GRC to host memory(given as a virtual 
 * address). 
 * 
 * 
 * @param pdev the device to use
 * @param context the DMAE context to use
 * @param source_offset the GRC offset of the source block
 * @param dest_vaddr the beginning of the destination memory 
 *                   block
 * @param length the length (in DWORDS) of the block
 * @param le32_swap if TRUE, change all DWORDS in data to 
 *                  little-endian after it's read from GRC.
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, 
 *         LM_STATUS_TIMEOUT if the operation did not finish in
 *         reasonable time, some other failure value on failure.
 */
lm_status_t lm_dmae_reg_rd(struct _lm_device_t* pdev, lm_dmae_context_t* context, u32_t source_offset, void* dest_vaddr, u16_t length, u8_t le32_swap);


/**lm_dmae_copy_phys_buffer_unsafe
 * Copy a block from host memory to host memory, both addresses 
 * given as physical addresses. 
 * 
 * 
 * @param pdev the device to use
 * @param context the DMAE context to use
 * @param source_paddr the beginning of the source memory block
 * @param dest_paddr the beginning of the destination memory 
 *                   block
 * @param length the length (in DWORDS) of the block
 * 
 * @return lm_status_t LM_STATUS_SUCCESS on success, 
 *         LM_STATUS_TIMEOUT if the operation did not finish in
 *         reasonable time, some other failure value on failure.
 */
lm_status_t lm_dmae_copy_phys_buffer_unsafe(struct _lm_device_t* pdev, lm_dmae_context_t* context, lm_address_t source_paddr, lm_address_t dest_paddr, u16_t length);

#endif// _LM_DMAE_H