Files

220 lines
7.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/**
* Copyright (c) 2024-2025 CALCULET Technologies Ltd. All rights reserved.
*/
#ifndef _CALCULET_DMA_H_
#define _CALCULET_DMA_H_
#include "ioctl.h"
#include <linux/dma-mapping.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/scatterlist.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ktime.h>
#include <linux/atomic.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#define DESC_MAGIC 0x0UL
#define DESC_MAX_COUNT (1024)
#define DMA_TRANSFER_MAX_DESC (2048)
#define DMA_CHANNEL_MAX_SIZE (8 * 1024 * 1024)
/* 获取64位地址的高32位和低32位 */
#define PCI_DMA_H(addr) ((addr >> 16) >> 16)
#define PCI_DMA_L(addr) (addr & 0xffffffffUL)
// DMA寄存器偏移定义
#define DMA_CHANNEL_BASE_OFF(i) ((i) * 2 * 0x100)
#define DMA_WRITE_ENGINE_EN_OFF 0xc
#define DMA_WRITE_DOORBELL_OFF 0x10
#define DMA_WRCH_CONTROL1_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x200)
#define DMA_WRCH_SIZE_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x208)
#define DMA_WRCH_SAR_LOW_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x20c)
#define DMA_WRCH_SAR_HIGH_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x210)
#define DMA_WRCH_DAR_LOW_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x214)
#define DMA_WRCH_DAR_HIGH_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x218)
#define DMA_READ_ENGINE_EN_OFF 0x2c
#define DMA_READ_DOORBELL_OFF 0x30
#define DMA_RDCH_CONTROL1_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x300)
#define DMA_RDCH_SIZE_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x308)
#define DMA_RDCH_SAR_LOW_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x30c)
#define DMA_RDCH_SAR_HIGH_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x310)
#define DMA_RDCH_DAR_LOW_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x314)
#define DMA_RDCH_DAR_HIGH_OFF(i) (DMA_CHANNEL_BASE_OFF(i) + 0x318)
// 前向声明
struct calculet_resource;
// DMA通道状态枚举
enum calculet_dma_channel_state {
DMA_CHANNEL_IDLE = 0,
DMA_CHANNEL_BUSY,
DMA_CHANNEL_COMPLETING,
DMA_CHANNEL_ERROR,
DMA_CHANNEL_DISABLED
};
// DMA IO回调结构体
struct calculet_dma_io_cb {
void __user *buf;
size_t len;
unsigned int pages_nr;
struct sg_table sgt;
struct page **pages;
};
// DMA传输上下文
struct calculet_dma_transfer_context {
struct completion completion;
int result;
ktime_t start_time;
ktime_t end_time;
pid_t requester_pid;
atomic_t ref_count;
};
// DMA通道结构体
struct calculet_dma_channel {
u8 channel_index;
u8 vector_index;
int msi_irq_line;
u32 irq_bitmask;
// 改进的状态管理
enum calculet_dma_channel_state state;
atomic_t transfer_finish;
spinlock_t state_lock;
resource_size_t dma_regs;
size_t dma_channel_size;
uint8_t *buffer;
uint64_t dst_address;
wait_queue_head_t channel_wq;
struct calculet_dma_io_cb *desc_io_cb;
// 改进的缓冲区管理
void *kernel_buf;
size_t dma_len;
dma_addr_t dma_handle;
struct mutex buffer_mutex;
atomic_t buffer_users;
// 传输统计和监控
atomic64_t transfer_count;
atomic64_t transfer_bytes;
ktime_t last_used;
// 当前传输上下文
struct calculet_dma_transfer_context *current_transfer;
struct mutex transfer_mutex;
};
// DMA轮询结构体
struct calculet_dma_poll {
dma_addr_t status_region_phys;
uint32_t *status_region;
uint32_t channel_status[CALCULET_TOTAL_CHANNELS];
uint32_t channel_data[CALCULET_TOTAL_CHANNELS];
spinlock_t poll_lock;
atomic_t poll_active;
};
// DMA内核线程结构体
struct calculet_dma_kthread {
struct calculet_dma_poll *dma_poll;
struct task_struct *poll_thread;
u32 poll_interval_ms;
char thread_name[24];
atomic_t should_stop;
struct completion thread_completion;
};
// DMA控制器结构体
struct calculet_dma_controller {
struct device *dev;
struct calculet_dma_channel dma_rdch_s[CALCULET_READ_CHANNELS];
struct calculet_dma_channel dma_wrch_s[CALCULET_WRITE_CHANNELS];
struct calculet_dma_channel msi_req[CALCULET_TOTAL_CHANNELS];
// struct calculet_dma_channel soft_reset;
struct calculet_dma_kthread *dma_kthread;
// 控制器级别的锁和状态
struct mutex controller_mutex;
atomic_t active_transfers;
bool controller_enabled;
// 通道分配管理
unsigned long read_channels_bitmap; // 读通道分配位图
unsigned long write_channels_bitmap; // 写通道分配位图
struct mutex allocation_mutex;
};
// 通道分配和释放
int calculet_dma_allocate_channel(struct calculet_dma_controller *controller,
enum calculet_transfer_direction direction,
int *channel_id);
void calculet_dma_release_channel(struct calculet_dma_controller *controller,
enum calculet_transfer_direction direction,
int channel_id);
// DMA通道状态管理
void calculet_dma_channel_set_state(struct calculet_dma_channel *channel,
enum calculet_dma_channel_state state);
enum calculet_dma_channel_state calculet_dma_channel_get_state(struct calculet_dma_channel *channel);
bool calculet_dma_channel_is_available(struct calculet_dma_channel *channel);
// 传输上下文管理
struct calculet_dma_transfer_context* calculet_dma_create_transfer_context(pid_t pid);
void calculet_dma_destroy_transfer_context(struct calculet_dma_transfer_context *ctx);
void calculet_dma_transfer_context_get(struct calculet_dma_transfer_context *ctx);
void calculet_dma_transfer_context_put(struct calculet_dma_transfer_context *ctx);
// 函数声明
int calculet_dma_controller_init(struct calculet_dma_controller *controller, struct device *dev, bool poll_en);
void calculet_dma_controller_deinit(struct calculet_dma_controller *controller, bool poll_en);
long calculet_dma_ioctl(struct calculet_resource *resource, struct calculet_dma_controller *controller, unsigned int cmd, unsigned long arg);
int calculet_dma_poll_ioctl(struct calculet_dma_controller *controller);
// DMA传输函数(改进版本)
long calculet_dma_h2c_transfer(struct device *dev, struct calculet_dma_channel *channel, struct calculet_resource *resource);
long calculet_dma_c2h_transfer(struct device *dev, struct calculet_dma_channel *channel, struct calculet_resource *resource);
// 新增:安全的DMA传输函数
long calculet_dma_safe_transfer(struct calculet_dma_controller *controller,
struct calculet_dma_transfer_channels_params *params,
struct calculet_resource *resource);
// 超时处理
void calculet_dma_timeout_handler(struct timer_list *timer);
int calculet_dma_set_timeout(struct calculet_dma_channel *channel, unsigned int timeout_ms);
// 中断处理函数
irqreturn_t calculet_irqhandler(int irq, void* dev_id);
int calculet_poll_handler(void *data);
// 错误恢复
void calculet_dma_error_recovery_work(struct work_struct *work);
int calculet_dma_channel_recovery(struct calculet_dma_channel *channel);
// 统计和监控
void calculet_dma_update_channel_stats(struct calculet_dma_channel *channel,
size_t bytes, bool success);
void calculet_dma_dump_channel_stats(struct calculet_dma_controller *controller);
// 调试和诊断
int calculet_dma_validate_transfer_params(struct calculet_dma_transfer_channels_params *params);
void calculet_dma_dump_controller_state(struct calculet_dma_controller *controller);
#endif /* _CALCULET_DMA_H_ */