220 lines
7.5 KiB
C
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_ */ |