/**
 * @file mvgal_p2p_dma.h
 * @brief Peer-to-Peer DMA Transfer API
 *
 * Multi-Vendor GPU Aggregation Layer for Linux
 *
 * This header provides P2P DMA transfer functionality for cross-GPU memory operations.
 */

#ifndef MVGAL_P2P_DMA_H
#define MVGAL_P2P_DMA_H

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "mvgal_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @addtogroup P2PTransfer
 * @{
 */

/**
 * @brief P2P transfer context
 */
typedef struct mvgal_p2p_context *mvgal_p2p_context_t;

/**
 * @brief P2P transfer capabilities
 */
typedef struct {
    bool supported;              /**< P2P transfer supported */
    bool same_root_complex;      /**< GPUs share same root complex */
    bool nvlink_connected;       /**< NVLink connection available */
    uint32_t max_bandwidth_mb_s; /**< Max bandwidth in MB/s */
    uint32_t latency_us;         /**< Estimated latency in microseconds */
} mvgal_p2p_caps_t;

/**
 * @brief P2P transfer direction
 */
typedef enum {
    MVGAL_P2P_DMA_TO_GPU = 0,    /**< Host to GPU */
    MVGAL_P2P_DMA_FROM_GPU = 1, /**< GPU to host */
    MVGAL_P2P_DMA_GPU_TO_GPU = 2, /**< GPU to GPU (P2P) */
} mvgal_p2p_direction_t;

/**
 * @brief Initialize P2P DMA subsystem
 * @param ctx Context handle (out)
 * @return MVGAL_SUCCESS on success
 */
mvgal_error_t mvgal_p2p_init(mvgal_p2p_context_t *ctx);

/**
 * @brief Cleanup P2P DMA subsystem
 * @param ctx Context handle
 */
void mvgal_p2p_fini(mvgal_p2p_context_t ctx);

/**
 * @brief Check P2P support between GPUs
 * @param gpu_src Source GPU index
 * @param gpu_dst Destination GPU index
 * @param caps Capabilities (out)
 * @return MVGAL_SUCCESS on success
 */
mvgal_error_t mvgal_p2p_query_caps(uint32_t gpu_src, uint32_t gpu_dst, mvgal_p2p_caps_t *caps);

/**
 * @brief Perform P2P DMA transfer
 * @param ctx Context handle
 * @param src_addr Source address
 * @param dst_addr Destination address
 * @param size Size in bytes
 * @param src_gpu Source GPU (0xFFFFFFFF for host)
 * @param dst_gpu Destination GPU
 * @param direction Transfer direction
 * @return MVGAL_SUCCESS on success
 */
mvgal_error_t mvgal_p2p_transfer(mvgal_p2p_context_t ctx,
                                  void *src_addr,
                                  void *dst_addr,
                                  size_t size,
                                  uint32_t src_gpu,
                                  uint32_t dst_gpu,
                                  mvgal_p2p_direction_t direction);

/**
 * @brief Perform async P2P transfer
 * @param ctx Context handle
 * @param src_addr Source address
 * @param dst_addr Destination address
 * @param size Size in bytes
 * @param src_gpu Source GPU
 * @param dst_gpu Destination GPU
 * @param fence Fence to signal on completion (out)
 * @return MVGAL_SUCCESS on success
 */
mvgal_error_t mvgal_p2p_transfer_async(mvgal_p2p_context_t ctx,
                                        void *src_addr,
                                        void *dst_addr,
                                        size_t size,
                                        uint32_t src_gpu,
                                        uint32_t dst_gpu,
                                        mvgal_fence_t *fence);

/**
 * @brief Get P2P bandwidth between GPUs
 * @param gpu_src Source GPU index
 * @param gpu_dst Destination GPU index
 * @return Bandwidth in MB/s
 */
uint32_t mvgal_p2p_get_bandwidth(uint32_t gpu_src, uint32_t gpu_dst);

/**
 * @brief Check if PCIe topology allows P2P
 * @param gpu_a GPU A index
 * @param gpu_b GPU B index
 * @return true if same root complex or upstream bridge allows P2P
 */
bool mvgal_p2p_check_pcie_topology(uint32_t gpu_a, uint32_t gpu_b);

/**
 * @brief Build P2P connectivity matrix
 * @param matrix Output matrix (gpu_count * gpu_count)
 * @param matrix_size Size of matrix buffer
 * @param gpu_count Number of GPUs (out)
 * @return MVGAL_SUCCESS on success
 */
mvgal_error_t mvgal_p2p_build_matrix(uint8_t *matrix, size_t matrix_size, uint32_t *gpu_count);

/**
 * @brief Check if cross-vendor DMA-BUF sharing is supported
 * @param src_gpu Source GPU index
 * @param dst_gpu Destination GPU index
 * @return true if both GPUs support DMA-BUF import/export
 */
bool mvgal_p2p_cross_vendor_supported(uint32_t src_gpu, uint32_t dst_gpu);

/**
 * @brief Get optimal transfer method for GPU pair
 * @param src_gpu Source GPU index
 * @param dst_gpu Destination GPU index
 * @return Recommended copy method (P2P, DMA_BUF, or CPU)
 */
mvgal_memory_copy_method_t mvgal_p2p_get_optimal_method(
    uint32_t src_gpu,
    uint32_t dst_gpu
);

/**
 * @brief P2P strategy for buffer placement
 */
typedef enum {
    MVGAL_P2P_STRATEGY_REPLICATE = 0,    /**< Replicate buffer on all GPUs */
    MVGAL_P2P_STRATEGY_MIGRATE = 1,      /**< Migrate buffer on-demand */
    MVGAL_P2P_STRATEGY_HOST_CACHED = 2,  /**< Keep on host, cache writes */
} mvgal_p2p_strategy_t;

/**
 * @brief Query optimal strategy considering bandwidth and buffer size
 * @param src_gpu Source GPU index
 * @param dst_gpu Destination GPU index
 * @param buffer_size Size of buffer in bytes
 * @return Recommended strategy
 */
mvgal_p2p_strategy_t mvgal_p2p_query_optimal_strategy(
    uint32_t src_gpu,
    uint32_t dst_gpu,
    size_t buffer_size
);

/** @} */ // end of P2PTransfer

#ifdef __cplusplus
}
#endif

#endif /* MVGAL_P2P_DMA_H */